mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
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:
parent
7e70f2e9ad
commit
f8c7349193
2 changed files with 39 additions and 90 deletions
|
@ -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,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
region,
|
|
||||||
PatternCategory::PatternGuard,
|
|
||||||
Type::Variable(*guard_var),
|
Type::Variable(*guard_var),
|
||||||
PExpected::ForReason(
|
PresenceConstraint::Pattern(
|
||||||
PReason::PatternGuard,
|
region,
|
||||||
pat_type.clone(),
|
PatternCategory::PatternGuard,
|
||||||
loc_guard.region,
|
PExpected::ForReason(
|
||||||
|
PReason::PatternGuard,
|
||||||
|
pat_type.clone(),
|
||||||
|
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(
|
||||||
region,
|
|
||||||
PatternCategory::PatternDefault,
|
|
||||||
Type::Variable(*expr_var),
|
Type::Variable(*expr_var),
|
||||||
PExpected::ForReason(
|
PresenceConstraint::Pattern(
|
||||||
PReason::OptionalField,
|
region,
|
||||||
pat_type.clone(),
|
PatternCategory::PatternDefault,
|
||||||
loc_expr.region,
|
PExpected::ForReason(
|
||||||
|
PReason::OptionalField,
|
||||||
|
pat_type.clone(),
|
||||||
|
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(
|
||||||
region,
|
|
||||||
PatternCategory::Ctor(tag_name.clone()),
|
|
||||||
Type::Variable(*whole_var),
|
Type::Variable(*whole_var),
|
||||||
expected,
|
PresenceConstraint::Pattern(
|
||||||
destruct_position,
|
region,
|
||||||
|
PatternCategory::Ctor(tag_name.clone()),
|
||||||
|
expected,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
state.vars.push(*whole_var);
|
state.vars.push(*whole_var);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue