This commit is contained in:
Ayaz Hafiz 2022-04-28 14:06:02 -04:00 committed by ayazhafiz
parent bd4f004cea
commit 9dac9e4bc2
15 changed files with 502 additions and 207 deletions

View file

@ -5,11 +5,11 @@ use crate::pattern::{constrain_pattern, PatternState};
use roc_can::annotation::IntroducedVariables;
use roc_can::constraint::{Constraint, Constraints};
use roc_can::def::{Declaration, Def};
use roc_can::exhaustive::{sketch_rows, ExhaustiveContext};
use roc_can::exhaustive::{sketch_pattern_to_rows, sketch_when_branches, ExhaustiveContext};
use roc_can::expected::Expected::{self, *};
use roc_can::expected::PExpected;
use roc_can::expr::Expr::{self, *};
use roc_can::expr::{AccessorData, ClosureData, Field, WhenBranch};
use roc_can::expr::{AccessorData, AnnotatedMark, ClosureData, Field, WhenBranch};
use roc_can::pattern::Pattern;
use roc_collections::all::{HumanIndex, MutMap, SendMap};
use roc_module::ident::{Lowercase, TagName};
@ -50,7 +50,7 @@ pub struct Env {
fn constrain_untyped_args(
constraints: &mut Constraints,
env: &Env,
arguments: &[(Variable, Loc<Pattern>)],
arguments: &[(Variable, AnnotatedMark, Loc<Pattern>)],
closure_type: Type,
return_type: Type,
) -> (Vec<Variable>, PatternState, Type) {
@ -59,7 +59,10 @@ fn constrain_untyped_args(
let mut pattern_state = PatternState::default();
for (pattern_var, loc_pattern) in arguments {
for (pattern_var, annotated_mark, loc_pattern) in arguments {
// Untyped args don't need exhaustiveness checking because they are the source of truth!
let _ = annotated_mark;
let pattern_type = Type::Variable(*pattern_var);
let pattern_expected = PExpected::NoExpectation(pattern_type.clone());
@ -720,12 +723,14 @@ pub fn constrain_expr(
pattern_cons.push(cond_constraint);
// Now check the condition against the type expected by the branches.
let sketched_rows = sketch_rows(real_cond_var, branches_region, branches);
let sketched_rows = sketch_when_branches(real_cond_var, branches_region, branches);
let cond_matches_branches_constraint = constraints.exhaustive(
real_cond_var,
loc_cond.region,
loc_cond.value.category(),
Expected::ForReason(Reason::WhenBranches, branches_cond_type, branches_region),
Ok((
loc_cond.value.category(),
Expected::ForReason(Reason::WhenBranches, branches_cond_type, branches_region),
)),
sketched_rows,
ExhaustiveContext::BadCase,
*exhaustive,
@ -1547,7 +1552,7 @@ fn constrain_typed_function_arguments(
def: &Def,
def_pattern_state: &mut PatternState,
argument_pattern_state: &mut PatternState,
arguments: &[(Variable, Loc<Pattern>)],
arguments: &[(Variable, AnnotatedMark, Loc<Pattern>)],
arg_types: &[Type],
) {
// ensure type matches the one in the annotation
@ -1558,38 +1563,113 @@ fn constrain_typed_function_arguments(
};
let it = arguments.iter().zip(arg_types.iter()).enumerate();
for (index, ((pattern_var, loc_pattern), loc_ann)) in it {
let pattern_expected = PExpected::ForReason(
PReason::TypedArg {
index: HumanIndex::zero_based(index),
opt_name: opt_label,
},
loc_ann.clone(),
loc_pattern.region,
);
constrain_pattern(
constraints,
env,
&loc_pattern.value,
loc_pattern.region,
pattern_expected,
argument_pattern_state,
);
{
// NOTE: because we perform an equality with part of the signature
// this constraint must be to the def_pattern_state's constraints
def_pattern_state.vars.push(*pattern_var);
let pattern_con = constraints.equal_types_var(
*pattern_var,
Expected::NoExpectation(loc_ann.clone()),
Category::Storage(std::file!(), std::line!()),
for (index, ((pattern_var, annotated_mark, loc_pattern), ann)) in it {
if loc_pattern.value.surely_exhaustive() {
// OPT: we don't need to perform any type-level exhaustiveness checking.
// Check instead only that the pattern unifies with the annotation type.
let pattern_expected = PExpected::ForReason(
PReason::TypedArg {
index: HumanIndex::zero_based(index),
opt_name: opt_label,
},
ann.clone(),
loc_pattern.region,
);
def_pattern_state.constraints.push(pattern_con);
constrain_pattern(
constraints,
env,
&loc_pattern.value,
loc_pattern.region,
pattern_expected,
argument_pattern_state,
);
{
// NOTE: because we perform an equality with part of the signature
// this constraint must be to the def_pattern_state's constraints
def_pattern_state.vars.push(*pattern_var);
let pattern_con = constraints.equal_types_var(
*pattern_var,
Expected::NoExpectation(ann.clone()),
Category::Storage(std::file!(), std::line!()),
loc_pattern.region,
);
def_pattern_state.constraints.push(pattern_con);
}
} else {
// We need to check the types, and run exhaustiveness checking.
let &AnnotatedMark {
annotation_var,
exhaustive,
} = annotated_mark;
def_pattern_state.vars.push(*pattern_var);
def_pattern_state.vars.push(annotation_var);
{
// First, solve the type that the pattern is expecting to match in this
// position.
let pattern_expected = PExpected::NoExpectation(Type::Variable(*pattern_var));
constrain_pattern(
constraints,
env,
&loc_pattern.value,
loc_pattern.region,
pattern_expected,
argument_pattern_state,
);
}
{
// Store the actual type in a variable.
argument_pattern_state
.constraints
.push(constraints.equal_types_var(
annotation_var,
Expected::NoExpectation(ann.clone()),
Category::Storage(file!(), line!()),
Region::zero(),
));
}
{
// let pattern_expected = PExpected::ForReason(
// PReason::TypedArg {
// index: HumanIndex::zero_based(index),
// opt_name: opt_label,
// },
// ann.clone(),
// loc_pattern.region,
// );
// Exhaustiveness-check the type in the pattern against what the
// annotation wants.
let sketched_rows =
sketch_pattern_to_rows(annotation_var, loc_pattern.region, &loc_pattern.value);
let category = loc_pattern.value.category();
let expected = PExpected::ForReason(
PReason::TypedArg {
index: HumanIndex::zero_based(index),
opt_name: opt_label,
},
Type::Variable(*pattern_var),
loc_pattern.region,
);
let exhaustive_constraint = constraints.exhaustive(
annotation_var,
loc_pattern.region,
Err((category, expected)),
sketched_rows,
ExhaustiveContext::BadArg,
exhaustive,
);
argument_pattern_state
.constraints
.push(exhaustive_constraint)
}
}
}
}
@ -1894,7 +1974,6 @@ pub fn rec_defs_help(
delayed_is_open_constraints: vec![],
};
let mut vars = Vec::with_capacity(state.vars.capacity() + 1);
let mut pattern_types = Vec::with_capacity(state.vars.capacity());
let ret_var = *ret_var;
let closure_var = *closure_var;
let closure_ext_var = *closure_ext_var;
@ -1904,53 +1983,16 @@ pub fn rec_defs_help(
vars.push(closure_var);
vars.push(closure_ext_var);
let it = arguments.iter().zip(arg_types.iter()).enumerate();
for (index, ((pattern_var, loc_pattern), loc_ann)) in it {
{
// ensure type matches the one in the annotation
let opt_label =
if let Pattern::Identifier(label) = def.loc_pattern.value {
Some(label)
} else {
None
};
let pattern_type: &Type = loc_ann;
let pattern_expected = PExpected::ForReason(
PReason::TypedArg {
index: HumanIndex::zero_based(index),
opt_name: opt_label,
},
pattern_type.clone(),
loc_pattern.region,
);
constrain_pattern(
constraints,
env,
&loc_pattern.value,
loc_pattern.region,
pattern_expected,
&mut state,
);
}
{
// NOTE: because we perform an equality with part of the signature
// this constraint must be to the def_pattern_state's constraints
def_pattern_state.vars.push(*pattern_var);
pattern_types.push(Type::Variable(*pattern_var));
let pattern_con = constraints.equal_types_var(
*pattern_var,
Expected::NoExpectation(loc_ann.clone()),
Category::Storage(std::file!(), std::line!()),
loc_pattern.region,
);
def_pattern_state.constraints.push(pattern_con);
}
}
constrain_typed_function_arguments(
constraints,
env,
def,
&mut def_pattern_state,
&mut state,
&arguments,
&arg_types,
);
let pattern_types = arguments.iter().map(|a| Type::Variable(a.0)).collect();
let closure_constraint = constrain_closure_size(
constraints,