mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
parent
17029cff7e
commit
3da34fc843
8 changed files with 246 additions and 50 deletions
|
@ -29,25 +29,27 @@ pub struct IntroducedVariables {
|
||||||
// But then between annotations, the same name can occur multiple times,
|
// But then between annotations, the same name can occur multiple times,
|
||||||
// but a variable can only have one name. Therefore
|
// but a variable can only have one name. Therefore
|
||||||
// `ftv : SendMap<Variable, Lowercase>`.
|
// `ftv : SendMap<Variable, Lowercase>`.
|
||||||
pub wildcards: Vec<Variable>,
|
pub wildcards: Vec<Loc<Variable>>,
|
||||||
pub lambda_sets: Vec<Variable>,
|
pub lambda_sets: Vec<Variable>,
|
||||||
pub inferred: Vec<Variable>,
|
pub inferred: Vec<Loc<Variable>>,
|
||||||
pub var_by_name: SendMap<Lowercase, Variable>,
|
// NB: A mapping of a -> Loc<v1> in this map has the region of the first-seen var, but there
|
||||||
|
// may be multiple occurences of it!
|
||||||
|
pub var_by_name: SendMap<Lowercase, Loc<Variable>>,
|
||||||
pub name_by_var: SendMap<Variable, Lowercase>,
|
pub name_by_var: SendMap<Variable, Lowercase>,
|
||||||
pub host_exposed_aliases: MutMap<Symbol, Variable>,
|
pub host_exposed_aliases: MutMap<Symbol, Variable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntroducedVariables {
|
impl IntroducedVariables {
|
||||||
pub fn insert_named(&mut self, name: Lowercase, var: Variable) {
|
pub fn insert_named(&mut self, name: Lowercase, var: Loc<Variable>) {
|
||||||
self.var_by_name.insert(name.clone(), var);
|
self.var_by_name.insert(name.clone(), var);
|
||||||
self.name_by_var.insert(var, name);
|
self.name_by_var.insert(var.value, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_wildcard(&mut self, var: Variable) {
|
pub fn insert_wildcard(&mut self, var: Loc<Variable>) {
|
||||||
self.wildcards.push(var);
|
self.wildcards.push(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_inferred(&mut self, var: Variable) {
|
pub fn insert_inferred(&mut self, var: Loc<Variable>) {
|
||||||
self.inferred.push(var);
|
self.inferred.push(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +72,7 @@ impl IntroducedVariables {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn var_by_name(&self, name: &Lowercase) -> Option<&Variable> {
|
pub fn var_by_name(&self, name: &Lowercase) -> Option<&Variable> {
|
||||||
self.var_by_name.get(name)
|
self.var_by_name.get(name).map(|v| &v.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name_by_var(&self, var: Variable) -> Option<&Lowercase> {
|
pub fn name_by_var(&self, var: Variable) -> Option<&Lowercase> {
|
||||||
|
@ -286,7 +288,7 @@ fn can_annotation_help(
|
||||||
let ret = can_annotation_help(
|
let ret = can_annotation_help(
|
||||||
env,
|
env,
|
||||||
&return_type.value,
|
&return_type.value,
|
||||||
region,
|
return_type.region,
|
||||||
scope,
|
scope,
|
||||||
var_store,
|
var_store,
|
||||||
introduced_variables,
|
introduced_variables,
|
||||||
|
@ -314,7 +316,7 @@ fn can_annotation_help(
|
||||||
let arg_ann = can_annotation_help(
|
let arg_ann = can_annotation_help(
|
||||||
env,
|
env,
|
||||||
&arg.value,
|
&arg.value,
|
||||||
region,
|
arg.region,
|
||||||
scope,
|
scope,
|
||||||
var_store,
|
var_store,
|
||||||
introduced_variables,
|
introduced_variables,
|
||||||
|
@ -368,7 +370,7 @@ fn can_annotation_help(
|
||||||
None => {
|
None => {
|
||||||
let var = var_store.fresh();
|
let var = var_store.fresh();
|
||||||
|
|
||||||
introduced_variables.insert_named(name, var);
|
introduced_variables.insert_named(name, Loc::at(region, var));
|
||||||
|
|
||||||
Type::Variable(var)
|
Type::Variable(var)
|
||||||
}
|
}
|
||||||
|
@ -377,7 +379,8 @@ fn can_annotation_help(
|
||||||
As(
|
As(
|
||||||
loc_inner,
|
loc_inner,
|
||||||
_spaces,
|
_spaces,
|
||||||
alias_header @ TypeHeader {
|
alias_header
|
||||||
|
@ TypeHeader {
|
||||||
name,
|
name,
|
||||||
vars: loc_vars,
|
vars: loc_vars,
|
||||||
},
|
},
|
||||||
|
@ -432,7 +435,8 @@ fn can_annotation_help(
|
||||||
} else {
|
} else {
|
||||||
let var = var_store.fresh();
|
let var = var_store.fresh();
|
||||||
|
|
||||||
introduced_variables.insert_named(var_name.clone(), var);
|
introduced_variables
|
||||||
|
.insert_named(var_name.clone(), Loc::at(loc_var.region, var));
|
||||||
vars.push((var_name.clone(), Type::Variable(var)));
|
vars.push((var_name.clone(), Type::Variable(var)));
|
||||||
|
|
||||||
lowercase_vars.push(Loc::at(loc_var.region, (var_name, var)));
|
lowercase_vars.push(Loc::at(loc_var.region, (var_name, var)));
|
||||||
|
@ -615,7 +619,7 @@ fn can_annotation_help(
|
||||||
Wildcard => {
|
Wildcard => {
|
||||||
let var = var_store.fresh();
|
let var = var_store.fresh();
|
||||||
|
|
||||||
introduced_variables.insert_wildcard(var);
|
introduced_variables.insert_wildcard(Loc::at(region, var));
|
||||||
|
|
||||||
Type::Variable(var)
|
Type::Variable(var)
|
||||||
}
|
}
|
||||||
|
@ -624,7 +628,7 @@ fn can_annotation_help(
|
||||||
// make a fresh unconstrained variable, and let the type solver fill it in for us 🤠
|
// make a fresh unconstrained variable, and let the type solver fill it in for us 🤠
|
||||||
let var = var_store.fresh();
|
let var = var_store.fresh();
|
||||||
|
|
||||||
introduced_variables.insert_inferred(var);
|
introduced_variables.insert_inferred(Loc::at(region, var));
|
||||||
|
|
||||||
Type::Variable(var)
|
Type::Variable(var)
|
||||||
}
|
}
|
||||||
|
@ -634,7 +638,7 @@ fn can_annotation_help(
|
||||||
|
|
||||||
let var = var_store.fresh();
|
let var = var_store.fresh();
|
||||||
|
|
||||||
introduced_variables.insert_wildcard(var);
|
introduced_variables.insert_wildcard(Loc::at(region, var));
|
||||||
|
|
||||||
Type::Variable(var)
|
Type::Variable(var)
|
||||||
}
|
}
|
||||||
|
@ -700,7 +704,7 @@ fn can_extension_type<'a>(
|
||||||
|
|
||||||
let var = var_store.fresh();
|
let var = var_store.fresh();
|
||||||
|
|
||||||
introduced_variables.insert_inferred(var);
|
introduced_variables.insert_inferred(Loc::at_zero(var));
|
||||||
|
|
||||||
Type::Variable(var)
|
Type::Variable(var)
|
||||||
}
|
}
|
||||||
|
@ -869,7 +873,10 @@ fn can_assigned_fields<'a>(
|
||||||
Type::Variable(*var)
|
Type::Variable(*var)
|
||||||
} else {
|
} else {
|
||||||
let field_var = var_store.fresh();
|
let field_var = var_store.fresh();
|
||||||
introduced_variables.insert_named(field_name.clone(), field_var);
|
introduced_variables.insert_named(
|
||||||
|
field_name.clone(),
|
||||||
|
Loc::at(loc_field_name.region, field_var),
|
||||||
|
);
|
||||||
Type::Variable(field_var)
|
Type::Variable(field_var)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -294,14 +294,12 @@ pub fn canonicalize_defs<'a>(
|
||||||
let mut can_vars: Vec<Loc<(Lowercase, Variable)>> = Vec::with_capacity(vars.len());
|
let mut can_vars: Vec<Loc<(Lowercase, Variable)>> = Vec::with_capacity(vars.len());
|
||||||
let mut is_phantom = false;
|
let mut is_phantom = false;
|
||||||
|
|
||||||
|
let mut var_by_name = can_ann.introduced_variables.var_by_name.clone();
|
||||||
for loc_lowercase in vars.iter() {
|
for loc_lowercase in vars.iter() {
|
||||||
if let Some(var) = can_ann
|
if let Some(var) = var_by_name.remove(&loc_lowercase.value) {
|
||||||
.introduced_variables
|
|
||||||
.var_by_name(&loc_lowercase.value)
|
|
||||||
{
|
|
||||||
// This is a valid lowercase rigid var for the type def.
|
// This is a valid lowercase rigid var for the type def.
|
||||||
can_vars.push(Loc {
|
can_vars.push(Loc {
|
||||||
value: (loc_lowercase.value.clone(), *var),
|
value: (loc_lowercase.value.clone(), var.value),
|
||||||
region: loc_lowercase.region,
|
region: loc_lowercase.region,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -320,6 +318,32 @@ pub fn canonicalize_defs<'a>(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let IntroducedVariables {
|
||||||
|
wildcards,
|
||||||
|
inferred,
|
||||||
|
..
|
||||||
|
} = can_ann.introduced_variables;
|
||||||
|
let num_unbound = var_by_name.len() + wildcards.len() + inferred.len();
|
||||||
|
if num_unbound > 0 {
|
||||||
|
let one_occurence = var_by_name
|
||||||
|
.iter()
|
||||||
|
.map(|(_, v)| v)
|
||||||
|
.chain(wildcards.iter())
|
||||||
|
.chain(inferred.iter())
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.region;
|
||||||
|
|
||||||
|
env.problems.push(Problem::UnboundTypeVariable {
|
||||||
|
typ: symbol,
|
||||||
|
num_unbound,
|
||||||
|
one_occurence,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bail out
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let alias = create_alias(
|
let alias = create_alias(
|
||||||
symbol,
|
symbol,
|
||||||
name.region,
|
name.region,
|
||||||
|
|
|
@ -210,7 +210,7 @@ fn build_effect_always(
|
||||||
let signature = {
|
let signature = {
|
||||||
// Effect.always : a -> Effect a
|
// Effect.always : a -> Effect a
|
||||||
let var_a = var_store.fresh();
|
let var_a = var_store.fresh();
|
||||||
introduced_variables.insert_named("a".into(), var_a);
|
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||||
|
|
||||||
let effect_a = build_effect_alias(
|
let effect_a = build_effect_alias(
|
||||||
effect_symbol,
|
effect_symbol,
|
||||||
|
@ -223,7 +223,7 @@ fn build_effect_always(
|
||||||
);
|
);
|
||||||
|
|
||||||
let closure_var = var_store.fresh();
|
let closure_var = var_store.fresh();
|
||||||
introduced_variables.insert_wildcard(closure_var);
|
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||||
|
|
||||||
Type::Function(
|
Type::Function(
|
||||||
vec![Type::Variable(var_a)],
|
vec![Type::Variable(var_a)],
|
||||||
|
@ -402,8 +402,8 @@ fn build_effect_map(
|
||||||
let var_a = var_store.fresh();
|
let var_a = var_store.fresh();
|
||||||
let var_b = var_store.fresh();
|
let var_b = var_store.fresh();
|
||||||
|
|
||||||
introduced_variables.insert_named("a".into(), var_a);
|
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||||
introduced_variables.insert_named("b".into(), var_b);
|
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||||
|
|
||||||
let effect_a = build_effect_alias(
|
let effect_a = build_effect_alias(
|
||||||
effect_symbol,
|
effect_symbol,
|
||||||
|
@ -426,7 +426,7 @@ fn build_effect_map(
|
||||||
);
|
);
|
||||||
|
|
||||||
let closure_var = var_store.fresh();
|
let closure_var = var_store.fresh();
|
||||||
introduced_variables.insert_wildcard(closure_var);
|
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||||
let a_to_b = {
|
let a_to_b = {
|
||||||
Type::Function(
|
Type::Function(
|
||||||
vec![Type::Variable(var_a)],
|
vec![Type::Variable(var_a)],
|
||||||
|
@ -436,7 +436,7 @@ fn build_effect_map(
|
||||||
};
|
};
|
||||||
|
|
||||||
let closure_var = var_store.fresh();
|
let closure_var = var_store.fresh();
|
||||||
introduced_variables.insert_wildcard(closure_var);
|
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||||
Type::Function(
|
Type::Function(
|
||||||
vec![effect_a, a_to_b],
|
vec![effect_a, a_to_b],
|
||||||
Box::new(Type::Variable(closure_var)),
|
Box::new(Type::Variable(closure_var)),
|
||||||
|
@ -571,8 +571,8 @@ fn build_effect_after(
|
||||||
let var_a = var_store.fresh();
|
let var_a = var_store.fresh();
|
||||||
let var_b = var_store.fresh();
|
let var_b = var_store.fresh();
|
||||||
|
|
||||||
introduced_variables.insert_named("a".into(), var_a);
|
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||||
introduced_variables.insert_named("b".into(), var_b);
|
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||||
|
|
||||||
let effect_a = build_effect_alias(
|
let effect_a = build_effect_alias(
|
||||||
effect_symbol,
|
effect_symbol,
|
||||||
|
@ -595,7 +595,7 @@ fn build_effect_after(
|
||||||
);
|
);
|
||||||
|
|
||||||
let closure_var = var_store.fresh();
|
let closure_var = var_store.fresh();
|
||||||
introduced_variables.insert_wildcard(closure_var);
|
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||||
let a_to_effect_b = Type::Function(
|
let a_to_effect_b = Type::Function(
|
||||||
vec![Type::Variable(var_a)],
|
vec![Type::Variable(var_a)],
|
||||||
Box::new(Type::Variable(closure_var)),
|
Box::new(Type::Variable(closure_var)),
|
||||||
|
@ -603,7 +603,7 @@ fn build_effect_after(
|
||||||
);
|
);
|
||||||
|
|
||||||
let closure_var = var_store.fresh();
|
let closure_var = var_store.fresh();
|
||||||
introduced_variables.insert_wildcard(closure_var);
|
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||||
Type::Function(
|
Type::Function(
|
||||||
vec![effect_a, a_to_effect_b],
|
vec![effect_a, a_to_effect_b],
|
||||||
Box::new(Type::Variable(closure_var)),
|
Box::new(Type::Variable(closure_var)),
|
||||||
|
@ -831,8 +831,8 @@ fn build_effect_forever(
|
||||||
let var_a = var_store.fresh();
|
let var_a = var_store.fresh();
|
||||||
let var_b = var_store.fresh();
|
let var_b = var_store.fresh();
|
||||||
|
|
||||||
introduced_variables.insert_named("a".into(), var_a);
|
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||||
introduced_variables.insert_named("b".into(), var_b);
|
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||||
|
|
||||||
let effect_a = build_effect_alias(
|
let effect_a = build_effect_alias(
|
||||||
effect_symbol,
|
effect_symbol,
|
||||||
|
@ -855,7 +855,7 @@ fn build_effect_forever(
|
||||||
);
|
);
|
||||||
|
|
||||||
let closure_var = var_store.fresh();
|
let closure_var = var_store.fresh();
|
||||||
introduced_variables.insert_wildcard(closure_var);
|
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||||
|
|
||||||
Type::Function(
|
Type::Function(
|
||||||
vec![effect_a],
|
vec![effect_a],
|
||||||
|
@ -1089,8 +1089,8 @@ fn build_effect_loop(
|
||||||
let var_a = var_store.fresh();
|
let var_a = var_store.fresh();
|
||||||
let var_b = var_store.fresh();
|
let var_b = var_store.fresh();
|
||||||
|
|
||||||
introduced_variables.insert_named("a".into(), var_a);
|
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||||
introduced_variables.insert_named("b".into(), var_b);
|
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||||
|
|
||||||
let effect_b = build_effect_alias(
|
let effect_b = build_effect_alias(
|
||||||
effect_symbol,
|
effect_symbol,
|
||||||
|
@ -1117,7 +1117,7 @@ fn build_effect_loop(
|
||||||
|
|
||||||
let effect_state_type = {
|
let effect_state_type = {
|
||||||
let closure_var = var_store.fresh();
|
let closure_var = var_store.fresh();
|
||||||
introduced_variables.insert_wildcard(closure_var);
|
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||||
|
|
||||||
let actual = {
|
let actual = {
|
||||||
Type::TagUnion(
|
Type::TagUnion(
|
||||||
|
@ -1145,7 +1145,7 @@ fn build_effect_loop(
|
||||||
};
|
};
|
||||||
|
|
||||||
let closure_var = var_store.fresh();
|
let closure_var = var_store.fresh();
|
||||||
introduced_variables.insert_wildcard(closure_var);
|
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||||
|
|
||||||
let step_type = Type::Function(
|
let step_type = Type::Function(
|
||||||
vec![Type::Variable(var_a)],
|
vec![Type::Variable(var_a)],
|
||||||
|
@ -1154,7 +1154,7 @@ fn build_effect_loop(
|
||||||
);
|
);
|
||||||
|
|
||||||
let closure_var = var_store.fresh();
|
let closure_var = var_store.fresh();
|
||||||
introduced_variables.insert_wildcard(closure_var);
|
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||||
|
|
||||||
Type::Function(
|
Type::Function(
|
||||||
vec![Type::Variable(var_a), step_type],
|
vec![Type::Variable(var_a), step_type],
|
||||||
|
@ -1559,7 +1559,7 @@ fn build_effect_alias(
|
||||||
introduced_variables: &mut IntroducedVariables,
|
introduced_variables: &mut IntroducedVariables,
|
||||||
) -> Type {
|
) -> Type {
|
||||||
let closure_var = var_store.fresh();
|
let closure_var = var_store.fresh();
|
||||||
introduced_variables.insert_wildcard(closure_var);
|
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||||
|
|
||||||
let actual = {
|
let actual = {
|
||||||
Type::TagUnion(
|
Type::TagUnion(
|
||||||
|
|
|
@ -259,7 +259,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
for var in output.introduced_variables.wildcards {
|
for var in output.introduced_variables.wildcards {
|
||||||
rigid_variables.wildcards.insert(var);
|
rigid_variables.wildcards.insert(var.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut referenced_values = MutSet::default();
|
let mut referenced_values = MutSet::default();
|
||||||
|
|
|
@ -1651,7 +1651,7 @@ fn instantiate_rigids(
|
||||||
headers: &mut SendMap<Symbol, Loc<Type>>,
|
headers: &mut SendMap<Symbol, Loc<Type>>,
|
||||||
) -> InstantiateRigids {
|
) -> InstantiateRigids {
|
||||||
let mut annotation = annotation.clone();
|
let mut annotation = annotation.clone();
|
||||||
let mut new_rigid_variables = Vec::new();
|
let mut new_rigid_variables: Vec<Variable> = Vec::new();
|
||||||
|
|
||||||
let mut rigid_substitution: ImMap<Variable, Type> = ImMap::default();
|
let mut rigid_substitution: ImMap<Variable, Type> = ImMap::default();
|
||||||
for (name, var) in introduced_vars.var_by_name.iter() {
|
for (name, var) in introduced_vars.var_by_name.iter() {
|
||||||
|
@ -1660,23 +1660,24 @@ fn instantiate_rigids(
|
||||||
match ftv.entry(name.clone()) {
|
match ftv.entry(name.clone()) {
|
||||||
Occupied(occupied) => {
|
Occupied(occupied) => {
|
||||||
let existing_rigid = occupied.get();
|
let existing_rigid = occupied.get();
|
||||||
rigid_substitution.insert(*var, Type::Variable(*existing_rigid));
|
rigid_substitution.insert(var.value, Type::Variable(*existing_rigid));
|
||||||
}
|
}
|
||||||
Vacant(vacant) => {
|
Vacant(vacant) => {
|
||||||
// It's possible to use this rigid in nested defs
|
// It's possible to use this rigid in nested defs
|
||||||
vacant.insert(*var);
|
vacant.insert(var.value);
|
||||||
new_rigid_variables.push(*var);
|
new_rigid_variables.push(var.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wildcards are always freshly introduced in this annotation
|
// wildcards are always freshly introduced in this annotation
|
||||||
new_rigid_variables.extend(introduced_vars.wildcards.iter().copied());
|
new_rigid_variables.extend(introduced_vars.wildcards.iter().map(|v| v.value));
|
||||||
|
|
||||||
// lambda set vars are always freshly introduced in this annotation
|
// lambda set vars are always freshly introduced in this annotation
|
||||||
new_rigid_variables.extend(introduced_vars.lambda_sets.iter().copied());
|
new_rigid_variables.extend(introduced_vars.lambda_sets.iter().copied());
|
||||||
|
|
||||||
let new_infer_variables = introduced_vars.inferred.clone();
|
let new_infer_variables: Vec<Variable> =
|
||||||
|
introduced_vars.inferred.iter().map(|v| v.value).collect();
|
||||||
|
|
||||||
// Instantiate rigid variables
|
// Instantiate rigid variables
|
||||||
if !rigid_substitution.is_empty() {
|
if !rigid_substitution.is_empty() {
|
||||||
|
|
|
@ -43,6 +43,11 @@ pub enum Problem {
|
||||||
variable_region: Region,
|
variable_region: Region,
|
||||||
variable_name: Lowercase,
|
variable_name: Lowercase,
|
||||||
},
|
},
|
||||||
|
UnboundTypeVariable {
|
||||||
|
typ: Symbol,
|
||||||
|
num_unbound: usize,
|
||||||
|
one_occurence: Region,
|
||||||
|
},
|
||||||
DuplicateRecordFieldValue {
|
DuplicateRecordFieldValue {
|
||||||
field_name: Lowercase,
|
field_name: Lowercase,
|
||||||
record_region: Region,
|
record_region: Region,
|
||||||
|
|
|
@ -17,6 +17,7 @@ const UNRECOGNIZED_NAME: &str = "UNRECOGNIZED NAME";
|
||||||
const UNUSED_DEF: &str = "UNUSED DEFINITION";
|
const UNUSED_DEF: &str = "UNUSED DEFINITION";
|
||||||
const UNUSED_IMPORT: &str = "UNUSED IMPORT";
|
const UNUSED_IMPORT: &str = "UNUSED IMPORT";
|
||||||
const UNUSED_ALIAS_PARAM: &str = "UNUSED TYPE ALIAS PARAMETER";
|
const UNUSED_ALIAS_PARAM: &str = "UNUSED TYPE ALIAS PARAMETER";
|
||||||
|
const UNBOUND_TYPE_VARIABLE: &str = "UNBOUND TYPE VARIABLE";
|
||||||
const UNUSED_ARG: &str = "UNUSED ARGUMENT";
|
const UNUSED_ARG: &str = "UNUSED ARGUMENT";
|
||||||
const MISSING_DEFINITION: &str = "MISSING DEFINITION";
|
const MISSING_DEFINITION: &str = "MISSING DEFINITION";
|
||||||
const UNKNOWN_GENERATES_WITH: &str = "UNKNOWN GENERATES FUNCTION";
|
const UNKNOWN_GENERATES_WITH: &str = "UNKNOWN GENERATES FUNCTION";
|
||||||
|
@ -252,6 +253,37 @@ pub fn can_problem<'b>(
|
||||||
title = UNUSED_ALIAS_PARAM.to_string();
|
title = UNUSED_ALIAS_PARAM.to_string();
|
||||||
severity = Severity::RuntimeError;
|
severity = Severity::RuntimeError;
|
||||||
}
|
}
|
||||||
|
Problem::UnboundTypeVariable {
|
||||||
|
typ: alias,
|
||||||
|
num_unbound,
|
||||||
|
one_occurence,
|
||||||
|
} => {
|
||||||
|
let mut stack = Vec::with_capacity(4);
|
||||||
|
if num_unbound == 1 {
|
||||||
|
stack.push(alloc.concat(vec![
|
||||||
|
alloc.reflow("The definition of "),
|
||||||
|
alloc.symbol_unqualified(alias),
|
||||||
|
alloc.reflow(" has an unbound type variable:"),
|
||||||
|
]));
|
||||||
|
} else {
|
||||||
|
stack.push(alloc.concat(vec![
|
||||||
|
alloc.reflow("The definition of "),
|
||||||
|
alloc.symbol_unqualified(alias),
|
||||||
|
alloc.reflow(" has "),
|
||||||
|
alloc.text(format!("{}", num_unbound)),
|
||||||
|
alloc.reflow(" unbound type variables."),
|
||||||
|
]));
|
||||||
|
stack.push(alloc.reflow("Here is one occurence:"));
|
||||||
|
}
|
||||||
|
stack.push(alloc.region(lines.convert_region(one_occurence)));
|
||||||
|
stack.push(alloc.tip().append(
|
||||||
|
alloc.reflow("Perhaps you intended to add a type parameter to this type?"),
|
||||||
|
));
|
||||||
|
doc = alloc.stack(stack);
|
||||||
|
|
||||||
|
title = UNBOUND_TYPE_VARIABLE.to_string();
|
||||||
|
severity = Severity::RuntimeError;
|
||||||
|
}
|
||||||
Problem::BadRecursion(entries) => {
|
Problem::BadRecursion(entries) => {
|
||||||
doc = to_circular_def_doc(alloc, lines, &entries);
|
doc = to_circular_def_doc(alloc, lines, &entries);
|
||||||
title = CIRCULAR_DEF.to_string();
|
title = CIRCULAR_DEF.to_string();
|
||||||
|
|
|
@ -76,7 +76,7 @@ mod test_reporting {
|
||||||
}
|
}
|
||||||
|
|
||||||
for var in output.introduced_variables.wildcards {
|
for var in output.introduced_variables.wildcards {
|
||||||
subs.rigid_var(var, "*".into());
|
subs.rigid_var(var.value, "*".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut unify_problems = Vec::new();
|
let mut unify_problems = Vec::new();
|
||||||
|
@ -8727,4 +8727,131 @@ I need all branches in an `if` to have the same type!
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wildcard_in_alias() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
I : Int *
|
||||||
|
a : I
|
||||||
|
a
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNBOUND TYPE VARIABLE ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
The definition of `I` has an unbound type variable:
|
||||||
|
|
||||||
|
1│ I : Int *
|
||||||
|
^
|
||||||
|
|
||||||
|
Tip: Perhaps you intended to add a type parameter to this type?
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wildcard_in_opaque() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
I := Int *
|
||||||
|
a : I
|
||||||
|
a
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNBOUND TYPE VARIABLE ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
The definition of `I` has an unbound type variable:
|
||||||
|
|
||||||
|
1│ I := Int *
|
||||||
|
^
|
||||||
|
|
||||||
|
Tip: Perhaps you intended to add a type parameter to this type?
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiple_wildcards_in_alias() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
I : [ A (Int *), B (Int *) ]
|
||||||
|
a : I
|
||||||
|
a
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNBOUND TYPE VARIABLE ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
The definition of `I` has 2 unbound type variables.
|
||||||
|
|
||||||
|
Here is one occurence:
|
||||||
|
|
||||||
|
1│ I : [ A (Int *), B (Int *) ]
|
||||||
|
^
|
||||||
|
|
||||||
|
Tip: Perhaps you intended to add a type parameter to this type?
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inference_var_in_alias() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
I : Int _
|
||||||
|
a : I
|
||||||
|
a
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNBOUND TYPE VARIABLE ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
The definition of `I` has an unbound type variable:
|
||||||
|
|
||||||
|
1│ I : Int _
|
||||||
|
^
|
||||||
|
|
||||||
|
Tip: Perhaps you intended to add a type parameter to this type?
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_var_in_alias() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
I : Int a
|
||||||
|
a : I
|
||||||
|
a
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNBOUND TYPE VARIABLE ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
The definition of `I` has an unbound type variable:
|
||||||
|
|
||||||
|
1│ I : Int a
|
||||||
|
^
|
||||||
|
|
||||||
|
Tip: Perhaps you intended to add a type parameter to this type?
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue