Merge remote-tracking branch 'origin/trunk' into low-level-ops

This commit is contained in:
Richard Feldman 2020-07-07 21:02:03 -04:00
commit 1cd49689c2
29 changed files with 1630 additions and 440 deletions

View file

@ -118,8 +118,8 @@ pub fn constrain_expr(
let record_type = Type::Record(
field_types,
// TODO can we avoid doing Box::new on every single one of these?
// For example, could we have a single lazy_static global Box they
// could all share?
// We can put `static EMPTY_REC: Type = Type::EmptyRec`, but that requires a
// lifetime parameter on `Type`
Box::new(Type::EmptyRec),
);
let record_con = Eq(record_type, expected.clone(), Category::Record, region);
@ -600,11 +600,7 @@ pub fn constrain_expr(
}
}
// TODO check for exhaustiveness. If this `case` is non-exaustive, then:
//
// 1. Record a Problem.
// 2. Add an extra _ branch at the end which throws a runtime error.
// exhautiveness checking happens when converting to mono::Expr
exists(vec![cond_var, *expr_var], And(constraints))
}
Access {
@ -843,7 +839,6 @@ fn constrain_when_branch(
constraints: Vec::with_capacity(1),
};
// TODO ensure this is correct
// TODO investigate for error messages, is it better to unify all branches with a variable,
// then unify that variable with the expectation?
for loc_pattern in &when_branch.patterns {
@ -917,38 +912,35 @@ pub fn constrain_decls(
) -> Constraint {
let mut constraint = Constraint::SaveTheEnvironment;
let mut env = Env {
home,
rigids: ImMap::default(),
};
for decl in decls.iter().rev() {
// NOTE: rigids are empty because they are not shared between top-level definitions
// Clear the rigids from the previous iteration.
// rigids are not shared between top-level definitions
env.rigids.clear();
match decl {
Declaration::Declare(def) | Declaration::Builtin(def) => {
constraint = exists_with_aliases(
aliases.clone(),
Vec::new(),
constrain_def(
&Env {
home,
rigids: ImMap::default(),
},
def,
constraint,
),
constrain_def(&env, def, constraint),
);
}
Declaration::DeclareRec(defs) => {
constraint = exists_with_aliases(
aliases.clone(),
Vec::new(),
constrain_recursive_defs(
&Env {
home,
rigids: ImMap::default(),
},
defs,
constraint,
),
constrain_recursive_defs(&env, defs, constraint),
);
}
Declaration::InvalidCycle(_, _) => panic!("TODO handle invalid cycle"),
Declaration::InvalidCycle(_, _) => {
// invalid cycles give a canonicalization error. we skip them here.
continue;
}
}
}
@ -1015,8 +1007,7 @@ fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
expr_type,
annotation_expected.clone(),
Category::Storage,
// TODO proper region
Region::zero(),
annotation.region,
));
constrain_expr(

View file

@ -207,16 +207,7 @@ fn to_type(solved_type: &SolvedType, free_vars: &mut FreeVars, var_store: &mut V
Type::Variable(var)
}
}
Flex(var_id) => {
if let Some(var) = free_vars.unnamed_vars.get(&var_id) {
Type::Variable(*var)
} else {
let var = var_store.fresh();
free_vars.unnamed_vars.insert(*var_id, var);
Type::Variable(var)
}
}
Flex(var_id) => Type::Variable(var_id_to_flex_var(*var_id, free_vars, var_store)),
Wildcard => {
let var = var_store.fresh();
free_vars.wildcards.push(var);
@ -274,11 +265,11 @@ fn to_type(solved_type: &SolvedType, free_vars: &mut FreeVars, var_store: &mut V
}
Boolean(SolvedBool::SolvedShared) => Type::Boolean(Bool::Shared),
Boolean(SolvedBool::SolvedContainer(solved_cvar, solved_mvars)) => {
let cvar = var_id_to_var(*solved_cvar, free_vars, var_store);
let cvar = var_id_to_flex_var(*solved_cvar, free_vars, var_store);
let mvars = solved_mvars
.iter()
.map(|var_id| var_id_to_var(*var_id, free_vars, var_store));
.map(|var_id| var_id_to_flex_var(*var_id, free_vars, var_store));
Type::Boolean(Bool::container(cvar, mvars))
}
@ -298,7 +289,11 @@ fn to_type(solved_type: &SolvedType, free_vars: &mut FreeVars, var_store: &mut V
}
}
fn var_id_to_var(var_id: VarId, free_vars: &mut FreeVars, var_store: &mut VarStore) -> Variable {
fn var_id_to_flex_var(
var_id: VarId,
free_vars: &mut FreeVars,
var_store: &mut VarStore,
) -> Variable {
if let Some(var) = free_vars.unnamed_vars.get(&var_id) {
*var
} else {

View file

@ -52,6 +52,7 @@ fn headers_from_annotation_help(
}
Underscore
| Shadowed(_, _)
| MalformedPattern(_, _)
| UnsupportedPattern(_)
| NumLiteral(_, _)
| IntLiteral(_)
@ -117,7 +118,7 @@ pub fn constrain_pattern(
state: &mut PatternState,
) {
match pattern {
Underscore | UnsupportedPattern(_) | Shadowed(_, _) => {
Underscore | UnsupportedPattern(_) | MalformedPattern(_, _) | Shadowed(_, _) => {
// Neither the _ pattern nor erroneous ones add any constraints.
}

View file

@ -78,24 +78,33 @@ pub fn constrain_decls(
sharing::annotate_usage(&def.loc_expr.value, &mut var_usage);
}
}
Declaration::InvalidCycle(_, _) => panic!("TODO handle invalid cycle"),
Declaration::InvalidCycle(_, _) => {
// any usage of a value defined in an invalid cycle will blow up
// so for the analysis usage by such values doesn't count
continue;
}
}
}
aliases_to_attr_type(var_store, &mut aliases);
let mut env = Env {
home,
rigids: ImMap::default(),
};
for decl in decls.iter().rev() {
// NOTE: rigids are empty because they are not shared between top-level definitions
// clear the set of rigids from the previous iteration.
// rigids are not shared between top-level definitions.
env.rigids.clear();
match decl {
Declaration::Declare(def) | Declaration::Builtin(def) => {
constraint = exists_with_aliases(
aliases.clone(),
Vec::new(),
constrain_def(
&Env {
home,
rigids: ImMap::default(),
},
&env,
var_store,
&var_usage,
&mut ImSet::default(),
@ -109,10 +118,7 @@ pub fn constrain_decls(
aliases.clone(),
Vec::new(),
constrain_recursive_defs(
&Env {
home,
rigids: ImMap::default(),
},
&env,
var_store,
&var_usage,
&mut ImSet::default(),
@ -121,7 +127,10 @@ pub fn constrain_decls(
),
);
}
Declaration::InvalidCycle(_, _) => panic!("TODO handle invalid cycle"),
Declaration::InvalidCycle(_, _) => {
// invalid cycles give a canonicalization error. we skip them here.
continue;
}
}
}
@ -333,7 +342,7 @@ fn constrain_pattern(
state.constraints.push(tag_con);
}
Underscore | Shadowed(_, _) | UnsupportedPattern(_) => {
Underscore | Shadowed(_, _) | MalformedPattern(_, _) | UnsupportedPattern(_) => {
// no constraints
}
}
@ -1385,10 +1394,7 @@ pub fn constrain_expr(
And(vec![Eq(fn_type, expected, category, region), record_con]),
)
}
RuntimeError(_) => {
// Runtime Errors have no constraints because they're going to crash.
True
}
RuntimeError(_) => True,
}
}
@ -1980,6 +1986,9 @@ fn aliases_to_attr_type(var_store: &mut VarStore, aliases: &mut SendMap<Symbol,
_ => unreachable!("`annotation_to_attr_type` always gives back an Attr"),
}
// Check that if the alias is a recursive tag union, all structures containing the
// recursion variable get the same uniqueness as the recursion variable (and thus as the
// recursive tag union itself)
if let Some(b) = &alias.uniqueness {
fix_mutual_recursive_alias(&mut alias.typ, b);
}
@ -2407,10 +2416,12 @@ fn fix_mutual_recursive_alias_help_help(rec_var: Variable, attribute: &Type, int
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
fix_mutual_recursive_alias_help(rec_var, attribute, ext);
tags.iter_mut()
.map(|v| v.1.iter_mut())
.flatten()
.for_each(|arg| fix_mutual_recursive_alias_help(rec_var, attribute, arg));
for (_tag, args) in tags.iter_mut() {
for arg in args.iter_mut() {
fix_mutual_recursive_alias_help(rec_var, attribute, arg);
}
}
}
Record(fields, ext) => {
@ -2420,7 +2431,8 @@ fn fix_mutual_recursive_alias_help_help(rec_var: Variable, attribute: &Type, int
.for_each(|arg| fix_mutual_recursive_alias_help(rec_var, attribute, arg));
}
Alias(_, _, actual_type) => {
fix_mutual_recursive_alias_help(rec_var, attribute, actual_type);
// call help_help, because actual_type is not wrapped in ATTR
fix_mutual_recursive_alias_help_help(rec_var, attribute, actual_type);
}
Apply(_, args) => {
args.iter_mut()