mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Merge branch 'explicit-closed-tag-record' into delay-instantiating-aliases
This commit is contained in:
commit
a3b00fbf55
29 changed files with 691 additions and 223 deletions
|
@ -7,7 +7,9 @@ use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
|||
use roc_parse::ast::{AssignedField, Pattern, Tag, TypeAnnotation, TypeHeader};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::{Alias, AliasCommon, AliasKind, LambdaSet, Problem, RecordField, Type};
|
||||
use roc_types::types::{
|
||||
Alias, AliasCommon, AliasKind, LambdaSet, Problem, RecordField, Type, TypeExtension,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Annotation {
|
||||
|
@ -29,25 +31,27 @@ pub struct IntroducedVariables {
|
|||
// But then between annotations, the same name can occur multiple times,
|
||||
// but a variable can only have one name. Therefore
|
||||
// `ftv : SendMap<Variable, Lowercase>`.
|
||||
pub wildcards: Vec<Variable>,
|
||||
pub wildcards: Vec<Loc<Variable>>,
|
||||
pub lambda_sets: Vec<Variable>,
|
||||
pub inferred: Vec<Variable>,
|
||||
pub var_by_name: SendMap<Lowercase, Variable>,
|
||||
pub inferred: Vec<Loc<Variable>>,
|
||||
// NB: A mapping of a -> Loc<v1> in this map has the region of the first-seen var, but there
|
||||
// may be multiple occurrences of it!
|
||||
pub var_by_name: SendMap<Lowercase, Loc<Variable>>,
|
||||
pub name_by_var: SendMap<Variable, Lowercase>,
|
||||
pub host_exposed_aliases: MutMap<Symbol, Variable>,
|
||||
}
|
||||
|
||||
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.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);
|
||||
}
|
||||
|
||||
pub fn insert_inferred(&mut self, var: Variable) {
|
||||
pub fn insert_inferred(&mut self, var: Loc<Variable>) {
|
||||
self.inferred.push(var);
|
||||
}
|
||||
|
||||
|
@ -70,7 +74,7 @@ impl IntroducedVariables {
|
|||
}
|
||||
|
||||
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> {
|
||||
|
@ -286,7 +290,7 @@ fn can_annotation_help(
|
|||
let ret = can_annotation_help(
|
||||
env,
|
||||
&return_type.value,
|
||||
region,
|
||||
return_type.region,
|
||||
scope,
|
||||
var_store,
|
||||
introduced_variables,
|
||||
|
@ -314,7 +318,7 @@ fn can_annotation_help(
|
|||
let arg_ann = can_annotation_help(
|
||||
env,
|
||||
&arg.value,
|
||||
region,
|
||||
arg.region,
|
||||
scope,
|
||||
var_store,
|
||||
introduced_variables,
|
||||
|
@ -389,7 +393,7 @@ fn can_annotation_help(
|
|||
None => {
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named(name, var);
|
||||
introduced_variables.insert_named(name, Loc::at(region, var));
|
||||
|
||||
Type::Variable(var)
|
||||
}
|
||||
|
@ -453,7 +457,8 @@ fn can_annotation_help(
|
|||
} else {
|
||||
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)));
|
||||
|
||||
lowercase_vars.push(Loc::at(loc_var.region, (var_name, var)));
|
||||
|
@ -560,7 +565,7 @@ fn can_annotation_help(
|
|||
// just `a` does not mean the same as `{}a`, so even
|
||||
// if there are no fields, still make this a `Record`,
|
||||
// not an EmptyRec
|
||||
Type::Record(Default::default(), Box::new(ext_type))
|
||||
Type::Record(Default::default(), TypeExtension::from_type(ext_type))
|
||||
}
|
||||
|
||||
None => Type::EmptyRec,
|
||||
|
@ -577,7 +582,7 @@ fn can_annotation_help(
|
|||
references,
|
||||
);
|
||||
|
||||
Type::Record(field_types, Box::new(ext_type))
|
||||
Type::Record(field_types, TypeExtension::from_type(ext_type))
|
||||
}
|
||||
}
|
||||
TagUnion { tags, ext, .. } => {
|
||||
|
@ -598,7 +603,7 @@ fn can_annotation_help(
|
|||
// just `a` does not mean the same as `{}a`, so even
|
||||
// if there are no fields, still make this a `Record`,
|
||||
// not an EmptyRec
|
||||
Type::TagUnion(Default::default(), Box::new(ext_type))
|
||||
Type::TagUnion(Default::default(), TypeExtension::from_type(ext_type))
|
||||
}
|
||||
|
||||
None => Type::EmptyTagUnion,
|
||||
|
@ -620,7 +625,7 @@ fn can_annotation_help(
|
|||
// in theory we save a lot of time by sorting once here
|
||||
insertion_sort_by(&mut tag_types, |a, b| a.0.cmp(&b.0));
|
||||
|
||||
Type::TagUnion(tag_types, Box::new(ext_type))
|
||||
Type::TagUnion(tag_types, TypeExtension::from_type(ext_type))
|
||||
}
|
||||
}
|
||||
SpaceBefore(nested, _) | SpaceAfter(nested, _) => can_annotation_help(
|
||||
|
@ -636,7 +641,7 @@ fn can_annotation_help(
|
|||
Wildcard => {
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_wildcard(var);
|
||||
introduced_variables.insert_wildcard(Loc::at(region, var));
|
||||
|
||||
Type::Variable(var)
|
||||
}
|
||||
|
@ -645,7 +650,7 @@ fn can_annotation_help(
|
|||
// make a fresh unconstrained variable, and let the type solver fill it in for us 🤠
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_inferred(var);
|
||||
introduced_variables.insert_inferred(Loc::at(region, var));
|
||||
|
||||
Type::Variable(var)
|
||||
}
|
||||
|
@ -655,7 +660,7 @@ fn can_annotation_help(
|
|||
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_wildcard(var);
|
||||
introduced_variables.insert_wildcard(Loc::at(region, var));
|
||||
|
||||
Type::Variable(var)
|
||||
}
|
||||
|
@ -721,7 +726,7 @@ fn can_extension_type<'a>(
|
|||
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_inferred(var);
|
||||
introduced_variables.insert_inferred(Loc::at_zero(var));
|
||||
|
||||
Type::Variable(var)
|
||||
}
|
||||
|
@ -913,7 +918,10 @@ fn can_assigned_fields<'a>(
|
|||
Type::Variable(*var)
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -294,14 +294,12 @@ pub fn canonicalize_defs<'a>(
|
|||
let mut can_vars: Vec<Loc<(Lowercase, Variable)>> = Vec::with_capacity(vars.len());
|
||||
let mut is_phantom = false;
|
||||
|
||||
let mut var_by_name = can_ann.introduced_variables.var_by_name.clone();
|
||||
for loc_lowercase in vars.iter() {
|
||||
if let Some(var) = can_ann
|
||||
.introduced_variables
|
||||
.var_by_name(&loc_lowercase.value)
|
||||
{
|
||||
if let Some(var) = var_by_name.remove(&loc_lowercase.value) {
|
||||
// This is a valid lowercase rigid var for the type def.
|
||||
can_vars.push(Loc {
|
||||
value: (loc_lowercase.value.clone(), *var),
|
||||
value: (loc_lowercase.value.clone(), var.value),
|
||||
region: loc_lowercase.region,
|
||||
});
|
||||
} else {
|
||||
|
@ -320,6 +318,33 @@ pub fn canonicalize_defs<'a>(
|
|||
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_occurrence = 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_occurrence,
|
||||
kind,
|
||||
});
|
||||
|
||||
// Bail out
|
||||
continue;
|
||||
}
|
||||
|
||||
let alias = create_alias(
|
||||
symbol,
|
||||
name.region,
|
||||
|
|
|
@ -10,7 +10,7 @@ use roc_module::ident::TagName;
|
|||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::{AliasKind, Type};
|
||||
use roc_types::types::{AliasKind, Type, TypeExtension};
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub(crate) struct HostedGeneratedFunctions {
|
||||
|
@ -210,7 +210,7 @@ fn build_effect_always(
|
|||
let signature = {
|
||||
// Effect.always : a -> Effect a
|
||||
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(
|
||||
effect_symbol,
|
||||
|
@ -223,7 +223,7 @@ fn build_effect_always(
|
|||
);
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
Type::Function(
|
||||
vec![Type::Variable(var_a)],
|
||||
|
@ -402,8 +402,8 @@ fn build_effect_map(
|
|||
let var_a = var_store.fresh();
|
||||
let var_b = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named("a".into(), var_a);
|
||||
introduced_variables.insert_named("b".into(), var_b);
|
||||
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||
|
||||
let effect_a = build_effect_alias(
|
||||
effect_symbol,
|
||||
|
@ -426,7 +426,7 @@ fn build_effect_map(
|
|||
);
|
||||
|
||||
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 = {
|
||||
Type::Function(
|
||||
vec![Type::Variable(var_a)],
|
||||
|
@ -436,7 +436,7 @@ fn build_effect_map(
|
|||
};
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
Type::Function(
|
||||
vec![effect_a, a_to_b],
|
||||
Box::new(Type::Variable(closure_var)),
|
||||
|
@ -571,8 +571,8 @@ fn build_effect_after(
|
|||
let var_a = var_store.fresh();
|
||||
let var_b = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named("a".into(), var_a);
|
||||
introduced_variables.insert_named("b".into(), var_b);
|
||||
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||
|
||||
let effect_a = build_effect_alias(
|
||||
effect_symbol,
|
||||
|
@ -595,7 +595,7 @@ fn build_effect_after(
|
|||
);
|
||||
|
||||
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(
|
||||
vec![Type::Variable(var_a)],
|
||||
Box::new(Type::Variable(closure_var)),
|
||||
|
@ -603,7 +603,7 @@ fn build_effect_after(
|
|||
);
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
Type::Function(
|
||||
vec![effect_a, a_to_effect_b],
|
||||
Box::new(Type::Variable(closure_var)),
|
||||
|
@ -831,8 +831,8 @@ fn build_effect_forever(
|
|||
let var_a = var_store.fresh();
|
||||
let var_b = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named("a".into(), var_a);
|
||||
introduced_variables.insert_named("b".into(), var_b);
|
||||
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||
|
||||
let effect_a = build_effect_alias(
|
||||
effect_symbol,
|
||||
|
@ -855,7 +855,7 @@ fn build_effect_forever(
|
|||
);
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
Type::Function(
|
||||
vec![effect_a],
|
||||
|
@ -1089,8 +1089,8 @@ fn build_effect_loop(
|
|||
let var_a = var_store.fresh();
|
||||
let var_b = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named("a".into(), var_a);
|
||||
introduced_variables.insert_named("b".into(), var_b);
|
||||
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||
|
||||
let effect_b = build_effect_alias(
|
||||
effect_symbol,
|
||||
|
@ -1111,13 +1111,13 @@ fn build_effect_loop(
|
|||
(step_tag_name, vec![Type::Variable(var_a)]),
|
||||
(done_tag_name, vec![Type::Variable(var_b)]),
|
||||
],
|
||||
Box::new(Type::EmptyTagUnion),
|
||||
TypeExtension::Closed,
|
||||
)
|
||||
};
|
||||
|
||||
let effect_state_type = {
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
let actual = {
|
||||
Type::TagUnion(
|
||||
|
@ -1129,7 +1129,7 @@ fn build_effect_loop(
|
|||
Box::new(state_type.clone()),
|
||||
)],
|
||||
)],
|
||||
Box::new(Type::EmptyTagUnion),
|
||||
TypeExtension::Closed,
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -1145,7 +1145,7 @@ fn build_effect_loop(
|
|||
};
|
||||
|
||||
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(
|
||||
vec![Type::Variable(var_a)],
|
||||
|
@ -1154,7 +1154,7 @@ fn build_effect_loop(
|
|||
);
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
Type::Function(
|
||||
vec![Type::Variable(var_a), step_type],
|
||||
|
@ -1559,7 +1559,7 @@ fn build_effect_alias(
|
|||
introduced_variables: &mut IntroducedVariables,
|
||||
) -> Type {
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
let actual = {
|
||||
Type::TagUnion(
|
||||
|
@ -1571,7 +1571,7 @@ fn build_effect_alias(
|
|||
Box::new(a_type),
|
||||
)],
|
||||
)],
|
||||
Box::new(Type::EmptyTagUnion),
|
||||
TypeExtension::Closed,
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -1600,7 +1600,7 @@ pub fn build_effect_actual(
|
|||
Box::new(a_type),
|
||||
)],
|
||||
)],
|
||||
Box::new(Type::EmptyTagUnion),
|
||||
TypeExtension::Closed,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
}
|
||||
|
||||
for var in output.introduced_variables.wildcards {
|
||||
rigid_variables.wildcards.insert(var);
|
||||
rigid_variables.wildcards.insert(var.value);
|
||||
}
|
||||
|
||||
let mut referenced_values = MutSet::default();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue