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

@ -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
/// initialize the Vecs in PatternState using with_capacity
/// based on its knowledge of their lengths.
@ -147,10 +130,9 @@ pub fn constrain_pattern(
region: Region,
expected: PExpected<Type>,
state: &mut PatternState,
destruct_position: bool,
) {
match pattern {
Underscore if destruct_position => {
Underscore => {
// This is an underscore in a position where we destruct a variable,
// like a when expression:
// when x is
@ -162,17 +144,15 @@ pub fn constrain_pattern(
PresenceConstraint::IsOpen,
));
}
Underscore | UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => {
// Neither the _ pattern nor erroneous ones add any constraints.
UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => {
// Erroneous patterns don't add any constraints.
}
Identifier(symbol) | Shadowed(_, _, symbol) => {
if destruct_position {
state.constraints.push(Constraint::Present(
expected.get_type_ref().clone(),
PresenceConstraint::IsOpen,
));
}
state.constraints.push(Constraint::Present(
expected.get_type_ref().clone(),
PresenceConstraint::IsOpen,
));
state.headers.insert(
*symbol,
Loc {
@ -305,41 +285,36 @@ pub fn constrain_pattern(
let field_type = match typ {
DestructType::Guard(guard_var, loc_guard) => {
state.constraints.push(make_pattern_constraint(
region,
PatternCategory::PatternGuard,
state.constraints.push(Constraint::Present(
Type::Variable(*guard_var),
PExpected::ForReason(
PReason::PatternGuard,
pat_type.clone(),
loc_guard.region,
PresenceConstraint::Pattern(
region,
PatternCategory::PatternGuard,
PExpected::ForReason(
PReason::PatternGuard,
pat_type.clone(),
loc_guard.region,
),
),
destruct_position,
));
state.vars.push(*guard_var);
constrain_pattern(
env,
&loc_guard.value,
loc_guard.region,
expected,
state,
destruct_position,
);
constrain_pattern(env, &loc_guard.value, loc_guard.region, expected, state);
RecordField::Demanded(pat_type)
}
DestructType::Optional(expr_var, loc_expr) => {
state.constraints.push(make_pattern_constraint(
region,
PatternCategory::PatternDefault,
state.constraints.push(Constraint::Present(
Type::Variable(*expr_var),
PExpected::ForReason(
PReason::OptionalField,
pat_type.clone(),
loc_expr.region,
PresenceConstraint::Pattern(
region,
PatternCategory::PatternDefault,
PExpected::ForReason(
PReason::OptionalField,
pat_type.clone(),
loc_expr.region,
),
),
destruct_position,
));
state.vars.push(*expr_var);
@ -376,12 +351,9 @@ pub fn constrain_pattern(
region,
);
let record_con = make_pattern_constraint(
region,
PatternCategory::Record,
let record_con = Constraint::Present(
Type::Variable(*whole_var),
expected,
destruct_position,
PresenceConstraint::Pattern(region, PatternCategory::Record, expected),
);
state.constraints.push(whole_con);
@ -408,39 +380,21 @@ pub fn constrain_pattern(
pattern_type,
region,
);
constrain_pattern(
env,
&loc_pattern.value,
loc_pattern.region,
expected,
state,
destruct_position,
);
constrain_pattern(env, &loc_pattern.value, loc_pattern.region, expected, state);
}
let whole_con = if destruct_position {
Constraint::Present(
expected.clone().get_type(),
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 whole_con = Constraint::Present(
expected.clone().get_type(),
PresenceConstraint::IncludesTag(tag_name.clone(), argument_types.clone()),
);
let tag_con = make_pattern_constraint(
region,
PatternCategory::Ctor(tag_name.clone()),
let tag_con = Constraint::Present(
Type::Variable(*whole_var),
expected,
destruct_position,
PresenceConstraint::Pattern(
region,
PatternCategory::Ctor(tag_name.clone()),
expected,
),
);
state.vars.push(*whole_var);