Simplify pattern constraint generation

At the time we introduced presence constraints for tag unions, I added a
"destruct_position" variable so that we didn't change the typechecking
semantics for everything all at once, and because I wasn't totally sure
what I was doing was correct. But now we're more confident in this
approach, and every pattern is by definition a destructuring, so there
is no need for this flag.

Also should fix some potential bugs we didn't notice before with presence
constraints in closure variables, though I can't find a good test to
reproduce this, since closure variables are hidden from the user.
This commit is contained in:
ayazhafiz 2022-02-24 01:08:18 -05:00
parent 7e70f2e9ad
commit f8c7349193
2 changed files with 39 additions and 90 deletions

View file

@ -80,7 +80,6 @@ fn constrain_untyped_args(
loc_pattern.region, loc_pattern.region,
pattern_expected, pattern_expected,
&mut pattern_state, &mut pattern_state,
true,
); );
vars.push(*pattern_var); vars.push(*pattern_var);
@ -1039,7 +1038,6 @@ fn constrain_when_branch(
loc_pattern.region, loc_pattern.region,
pattern_expected.clone(), pattern_expected.clone(),
&mut state, &mut state,
true,
); );
} }
@ -1143,7 +1141,6 @@ fn constrain_def_pattern(env: &Env, loc_pattern: &Loc<Pattern>, expr_type: Type)
loc_pattern.region, loc_pattern.region,
pattern_expected, pattern_expected,
&mut state, &mut state,
true,
); );
state state
@ -1264,7 +1261,6 @@ fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
loc_pattern.region, loc_pattern.region,
pattern_expected, pattern_expected,
&mut state, &mut state,
false,
); );
} }
@ -1632,7 +1628,6 @@ pub fn rec_defs_help(
loc_pattern.region, loc_pattern.region,
pattern_expected, pattern_expected,
&mut state, &mut state,
false,
); );
} }

View file

@ -121,23 +121,6 @@ fn headers_from_annotation_help(
} }
} }
fn make_pattern_constraint(
region: Region,
category: PatternCategory,
actual: Type,
expected: PExpected<Type>,
presence_con: bool,
) -> Constraint {
if presence_con {
Constraint::Present(
actual,
PresenceConstraint::Pattern(region, category, expected),
)
} else {
Constraint::Pattern(region, category, actual, expected)
}
}
/// This accepts PatternState (rather than returning it) so that the caller can /// This accepts PatternState (rather than returning it) so that the caller can
/// initialize the Vecs in PatternState using with_capacity /// initialize the Vecs in PatternState using with_capacity
/// based on its knowledge of their lengths. /// based on its knowledge of their lengths.
@ -147,10 +130,9 @@ pub fn constrain_pattern(
region: Region, region: Region,
expected: PExpected<Type>, expected: PExpected<Type>,
state: &mut PatternState, state: &mut PatternState,
destruct_position: bool,
) { ) {
match pattern { match pattern {
Underscore if destruct_position => { Underscore => {
// This is an underscore in a position where we destruct a variable, // This is an underscore in a position where we destruct a variable,
// like a when expression: // like a when expression:
// when x is // when x is
@ -162,17 +144,15 @@ pub fn constrain_pattern(
PresenceConstraint::IsOpen, PresenceConstraint::IsOpen,
)); ));
} }
Underscore | UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => { UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => {
// Neither the _ pattern nor erroneous ones add any constraints. // Erroneous patterns don't add any constraints.
} }
Identifier(symbol) | Shadowed(_, _, symbol) => { Identifier(symbol) | Shadowed(_, _, symbol) => {
if destruct_position {
state.constraints.push(Constraint::Present( state.constraints.push(Constraint::Present(
expected.get_type_ref().clone(), expected.get_type_ref().clone(),
PresenceConstraint::IsOpen, PresenceConstraint::IsOpen,
)); ));
}
state.headers.insert( state.headers.insert(
*symbol, *symbol,
Loc { Loc {
@ -305,41 +285,36 @@ pub fn constrain_pattern(
let field_type = match typ { let field_type = match typ {
DestructType::Guard(guard_var, loc_guard) => { DestructType::Guard(guard_var, loc_guard) => {
state.constraints.push(make_pattern_constraint( state.constraints.push(Constraint::Present(
Type::Variable(*guard_var),
PresenceConstraint::Pattern(
region, region,
PatternCategory::PatternGuard, PatternCategory::PatternGuard,
Type::Variable(*guard_var),
PExpected::ForReason( PExpected::ForReason(
PReason::PatternGuard, PReason::PatternGuard,
pat_type.clone(), pat_type.clone(),
loc_guard.region, loc_guard.region,
), ),
destruct_position, ),
)); ));
state.vars.push(*guard_var); state.vars.push(*guard_var);
constrain_pattern( constrain_pattern(env, &loc_guard.value, loc_guard.region, expected, state);
env,
&loc_guard.value,
loc_guard.region,
expected,
state,
destruct_position,
);
RecordField::Demanded(pat_type) RecordField::Demanded(pat_type)
} }
DestructType::Optional(expr_var, loc_expr) => { DestructType::Optional(expr_var, loc_expr) => {
state.constraints.push(make_pattern_constraint( state.constraints.push(Constraint::Present(
Type::Variable(*expr_var),
PresenceConstraint::Pattern(
region, region,
PatternCategory::PatternDefault, PatternCategory::PatternDefault,
Type::Variable(*expr_var),
PExpected::ForReason( PExpected::ForReason(
PReason::OptionalField, PReason::OptionalField,
pat_type.clone(), pat_type.clone(),
loc_expr.region, loc_expr.region,
), ),
destruct_position, ),
)); ));
state.vars.push(*expr_var); state.vars.push(*expr_var);
@ -376,12 +351,9 @@ pub fn constrain_pattern(
region, region,
); );
let record_con = make_pattern_constraint( let record_con = Constraint::Present(
region,
PatternCategory::Record,
Type::Variable(*whole_var), Type::Variable(*whole_var),
expected, PresenceConstraint::Pattern(region, PatternCategory::Record, expected),
destruct_position,
); );
state.constraints.push(whole_con); state.constraints.push(whole_con);
@ -408,39 +380,21 @@ pub fn constrain_pattern(
pattern_type, pattern_type,
region, region,
); );
constrain_pattern( constrain_pattern(env, &loc_pattern.value, loc_pattern.region, expected, state);
env,
&loc_pattern.value,
loc_pattern.region,
expected,
state,
destruct_position,
);
} }
let whole_con = if destruct_position { let whole_con = Constraint::Present(
Constraint::Present(
expected.clone().get_type(), expected.clone().get_type(),
PresenceConstraint::IncludesTag(tag_name.clone(), argument_types.clone()), PresenceConstraint::IncludesTag(tag_name.clone(), argument_types.clone()),
) );
} else {
Constraint::Eq(
Type::Variable(*whole_var),
Expected::NoExpectation(Type::TagUnion(
vec![(tag_name.clone(), argument_types)],
Box::new(Type::Variable(*ext_var)),
)),
Category::Storage(std::file!(), std::line!()),
region,
)
};
let tag_con = make_pattern_constraint( let tag_con = Constraint::Present(
Type::Variable(*whole_var),
PresenceConstraint::Pattern(
region, region,
PatternCategory::Ctor(tag_name.clone()), PatternCategory::Ctor(tag_name.clone()),
Type::Variable(*whole_var),
expected, expected,
destruct_position, ),
); );
state.vars.push(*whole_var); state.vars.push(*whole_var);