Canonicalize multiple abilities bound to a type variable

This commit is contained in:
Ayaz Hafiz 2022-10-11 17:45:33 -05:00
parent 97dbac1631
commit 6bb97c92b9
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
9 changed files with 84 additions and 77 deletions

View file

@ -105,10 +105,10 @@ impl OwnedNamedOrAble {
}
}
pub fn opt_ability(&self) -> Option<Symbol> {
pub fn opt_abilities(&self) -> Option<&[Symbol]> {
match self {
OwnedNamedOrAble::Named(_) => None,
OwnedNamedOrAble::Able(av) => Some(av.ability),
OwnedNamedOrAble::Able(av) => Some(&av.abilities),
}
}
}
@ -127,7 +127,7 @@ pub struct NamedVariable {
pub struct AbleVariable {
pub variable: Variable,
pub name: Lowercase,
pub ability: Symbol,
pub abilities: Vec<Symbol>,
// NB: there may be multiple occurrences of a variable
pub first_seen: Region,
}
@ -166,12 +166,12 @@ impl IntroducedVariables {
self.named.insert(named_variable);
}
pub fn insert_able(&mut self, name: Lowercase, var: Loc<Variable>, ability: Symbol) {
pub fn insert_able(&mut self, name: Lowercase, var: Loc<Variable>, abilities: Vec<Symbol>) {
self.debug_assert_not_already_present(var.value);
let able_variable = AbleVariable {
name,
ability,
abilities,
variable: var.value,
first_seen: var.region,
};
@ -450,8 +450,9 @@ pub fn find_type_def_symbols(
stack.push(&annotation.value);
for has_clause in clauses.iter() {
// TODO(abilities)
stack.push(&has_clause.value.abilities[0].value);
for ab in has_clause.value.abilities {
stack.push(&ab.value);
}
}
}
Inferred | Wildcard | Malformed(_) => {}
@ -538,7 +539,7 @@ fn can_annotation_help(
// Generate an variable bound to the ability so we can keep compiling.
let var = var_store.fresh();
introduced_variables.insert_able(fresh_ty_var, Loc::at(region, var), symbol);
introduced_variables.insert_able(fresh_ty_var, Loc::at(region, var), vec![symbol]);
return Type::Variable(var);
}
@ -579,7 +580,7 @@ fn can_annotation_help(
arg_ann.region,
OptAbleType {
typ: arg_ann.value,
opt_ability: alias_arg.value.opt_bound_ability,
opt_abilities: alias_arg.value.opt_bound_abilities.clone(),
},
));
}
@ -674,7 +675,7 @@ fn can_annotation_help(
AliasVar {
name: var_name,
var,
opt_bound_ability: None,
opt_bound_abilities: None,
},
));
} else {
@ -689,7 +690,7 @@ fn can_annotation_help(
AliasVar {
name: var_name,
var,
opt_bound_ability: None,
opt_bound_abilities: None,
},
));
}
@ -769,10 +770,7 @@ fn can_annotation_help(
symbol,
type_arguments: vars
.into_iter()
.map(|typ| OptAbleType {
typ,
opt_ability: None,
})
.map(|typ| OptAbleType::unbound(typ))
.collect(),
lambda_set_variables: alias.lambda_set_variables.clone(),
actual: Box::new(alias.typ.clone()),
@ -932,31 +930,33 @@ fn canonicalize_has_clause(
);
let var_name = Lowercase::from(var_name);
// TODO(abilities)
let ability = abilities[0];
let ability = match ability.value {
TypeAnnotation::Apply(module_name, ident, _type_arguments) => {
let symbol = make_apply_symbol(env, ability.region, scope, module_name, ident)?;
let mut can_abilities = Vec::with_capacity(abilities.len());
for ability in *abilities {
let ability = match ability.value {
TypeAnnotation::Apply(module_name, ident, _type_arguments) => {
let symbol = make_apply_symbol(env, ability.region, scope, module_name, ident)?;
// Ability defined locally, whose members we are constructing right now...
if !pending_abilities_in_scope.contains_key(&symbol)
// Ability defined locally, whose members we are constructing right now...
if !pending_abilities_in_scope.contains_key(&symbol)
// or an ability that was imported from elsewhere
&& !scope.abilities_store.is_ability(symbol)
{
{
let region = ability.region;
env.problem(roc_problem::can::Problem::HasClauseIsNotAbility { region });
return Err(Type::Erroneous(Problem::HasClauseIsNotAbility(region)));
}
symbol
}
_ => {
let region = ability.region;
env.problem(roc_problem::can::Problem::HasClauseIsNotAbility { region });
return Err(Type::Erroneous(Problem::HasClauseIsNotAbility(region)));
}
symbol
}
_ => {
let region = ability.region;
env.problem(roc_problem::can::Problem::HasClauseIsNotAbility { region });
return Err(Type::Erroneous(Problem::HasClauseIsNotAbility(region)));
}
};
};
references.insert(ability);
references.insert(ability);
can_abilities.push(ability);
}
if let Some(shadowing) = introduced_variables.named_var_by_name(&var_name) {
let var_name_ident = var_name.to_string().into();
@ -974,7 +974,7 @@ fn canonicalize_has_clause(
let var = var_store.fresh();
introduced_variables.insert_able(var_name, Loc::at(region, var), ability);
introduced_variables.insert_able(var_name, Loc::at(region, var), can_abilities);
Ok(())
}
@ -1126,7 +1126,7 @@ pub fn freshen_opaque_def(
.iter()
.map(|alias_var| OptAbleVar {
var: var_store.fresh(),
opt_ability: alias_var.value.opt_bound_ability,
opt_abilities: alias_var.value.opt_bound_abilities.clone(),
})
.collect();