diff --git a/compiler/can/src/annotation.rs b/compiler/can/src/annotation.rs index a3c8ed95d2..51a36c1b53 100644 --- a/compiler/can/src/annotation.rs +++ b/compiler/can/src/annotation.rs @@ -234,7 +234,12 @@ fn can_annotation_help( // instantiate variables actual.substitute(&substitutions); - Type::Alias(symbol, vars, Box::new(actual)) + Type::Alias { + symbol, + type_arguments: vars, + lambda_set_variables: alias.lambda_set_variables.clone(), + actual: Box::new(actual), + } } None => { let mut args = Vec::new(); @@ -378,7 +383,12 @@ fn can_annotation_help( actual_var, } } else { - Type::Alias(symbol, vars, Box::new(alias.typ.clone())) + Type::Alias { + symbol, + type_arguments: vars, + lambda_set_variables: alias.lambda_set_variables.clone(), + actual: Box::new(alias.typ.clone()), + } } } _ => { diff --git a/compiler/can/src/constraint.rs b/compiler/can/src/constraint.rs index dfac99f49e..931c43f9b5 100644 --- a/compiler/can/src/constraint.rs +++ b/compiler/can/src/constraint.rs @@ -76,7 +76,7 @@ fn subtract(declared: &Declared, detail: &VariableDetail, accum: &mut VariableDe } if !declared.flex_vars.contains(&var.into_inner()) { - accum.lambda_set_variables.insert(*var); + accum.lambda_set_variables.push(*var); } } diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index b4a4652924..336d9cc7f2 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -1634,7 +1634,7 @@ fn make_tag_union_recursive<'a>( typ.substitute_alias(symbol, &Type::Variable(rec_var)); } Type::RecursiveTagUnion(_, _, _) => {} - Type::Alias(_, _, actual) => make_tag_union_recursive( + Type::Alias { actual, .. } => make_tag_union_recursive( env, symbol, region, diff --git a/compiler/can/src/scope.rs b/compiler/can/src/scope.rs index 9037d6e193..ecfb3fa03b 100644 --- a/compiler/can/src/scope.rs +++ b/compiler/can/src/scope.rs @@ -47,7 +47,7 @@ impl Scope { let alias = Alias { region, typ, - lambda_set_variables: MutSet::default(), + lambda_set_variables: Vec::new(), recursion_variables: MutSet::default(), type_variables: variables, }; diff --git a/compiler/constrain/src/builtins.rs b/compiler/constrain/src/builtins.rs index 4704c67539..c47a1e5796 100644 --- a/compiler/constrain/src/builtins.rs +++ b/compiler/constrain/src/builtins.rs @@ -2,7 +2,7 @@ use roc_can::constraint::Constraint::{self, *}; use roc_can::constraint::LetConstraint; use roc_can::expected::Expected::{self, *}; use roc_collections::all::SendMap; -use roc_module::ident::TagName; +use roc_module::ident::{Lowercase, TagName}; use roc_module::symbol::Symbol; use roc_region::all::Region; use roc_types::subs::Variable; @@ -89,9 +89,23 @@ pub fn str_type() -> Type { builtin_type(Symbol::STR_STR, Vec::new()) } +#[inline(always)] +fn builtin_alias( + symbol: Symbol, + type_arguments: Vec<(Lowercase, Type)>, + actual: Box, +) -> Type { + Type::Alias { + symbol, + type_arguments, + actual, + lambda_set_variables: vec![], + } +} + #[inline(always)] pub fn num_float(range: Type) -> Type { - Type::Alias( + builtin_alias( Symbol::NUM_FLOAT, vec![("range".into(), range.clone())], Box::new(num_num(num_floatingpoint(range))), @@ -108,7 +122,7 @@ pub fn num_floatingpoint(range: Type) -> Type { Box::new(Type::EmptyTagUnion), ); - Type::Alias( + builtin_alias( Symbol::NUM_FLOATINGPOINT, vec![("range".into(), range)], Box::new(alias_content), @@ -122,12 +136,12 @@ pub fn num_binary64() -> Type { Box::new(Type::EmptyTagUnion), ); - Type::Alias(Symbol::NUM_BINARY64, vec![], Box::new(alias_content)) + builtin_alias(Symbol::NUM_BINARY64, vec![], Box::new(alias_content)) } #[inline(always)] pub fn num_int(range: Type) -> Type { - Type::Alias( + builtin_alias( Symbol::NUM_INT, vec![("range".into(), range.clone())], Box::new(num_num(num_integer(range))), @@ -141,7 +155,7 @@ pub fn num_signed64() -> Type { Box::new(Type::EmptyTagUnion), ); - Type::Alias(Symbol::NUM_SIGNED64, vec![], Box::new(alias_content)) + builtin_alias(Symbol::NUM_SIGNED64, vec![], Box::new(alias_content)) } #[inline(always)] @@ -154,7 +168,7 @@ pub fn num_integer(range: Type) -> Type { Box::new(Type::EmptyTagUnion), ); - Type::Alias( + builtin_alias( Symbol::NUM_INTEGER, vec![("range".into(), range)], Box::new(alias_content), @@ -168,7 +182,7 @@ pub fn num_num(typ: Type) -> Type { Box::new(Type::EmptyTagUnion), ); - Type::Alias( + builtin_alias( Symbol::NUM_NUM, vec![("range".into(), typ)], Box::new(alias_content), diff --git a/compiler/load/src/effect_module.rs b/compiler/load/src/effect_module.rs index 5dab90a4f8..798c7b45c3 100644 --- a/compiler/load/src/effect_module.rs +++ b/compiler/load/src/effect_module.rs @@ -1,3 +1,4 @@ +use roc_can::annotation::IntroducedVariables; use roc_can::def::{Declaration, Def}; use roc_can::env::Env; use roc_can::expr::{Expr, Recursive}; @@ -160,25 +161,22 @@ fn build_effect_always( (function_var, closure) }; - use roc_can::annotation::IntroducedVariables; - let mut introduced_variables = IntroducedVariables::default(); let signature = { // Effect.always : a -> Effect a let var_a = var_store.fresh(); - introduced_variables.insert_named("a".into(), var_a); - let effect_a = { - let actual = build_effect_actual(effect_tag_name, Type::Variable(var_a), var_store); - - Type::Alias( - effect_symbol, - vec![("a".into(), Type::Variable(var_a))], - Box::new(actual), - ) - }; + let effect_a = build_effect_alias( + effect_symbol, + effect_tag_name, + "a", + var_a, + Type::Variable(var_a), + var_store, + &mut introduced_variables, + ); let closure_var = var_store.fresh(); introduced_variables.insert_wildcard(closure_var); @@ -353,8 +351,6 @@ fn build_effect_map( loc_body: Box::new(Located::at_zero(body)), }; - use roc_can::annotation::IntroducedVariables; - let mut introduced_variables = IntroducedVariables::default(); let signature = { @@ -365,26 +361,25 @@ fn build_effect_map( introduced_variables.insert_named("a".into(), var_a); introduced_variables.insert_named("b".into(), var_b); - let effect_a = { - let actual = - build_effect_actual(effect_tag_name.clone(), Type::Variable(var_a), var_store); + let effect_a = build_effect_alias( + effect_symbol, + effect_tag_name.clone(), + "a", + var_a, + Type::Variable(var_a), + var_store, + &mut introduced_variables, + ); - Type::Alias( - effect_symbol, - vec![("a".into(), Type::Variable(var_a))], - Box::new(actual), - ) - }; - - let effect_b = { - let actual = build_effect_actual(effect_tag_name, Type::Variable(var_b), var_store); - - Type::Alias( - effect_symbol, - vec![("b".into(), Type::Variable(var_b))], - Box::new(actual), - ) - }; + let effect_b = build_effect_alias( + effect_symbol, + effect_tag_name, + "b", + var_b, + Type::Variable(var_b), + var_store, + &mut introduced_variables, + ); let closure_var = var_store.fresh(); introduced_variables.insert_wildcard(closure_var); @@ -526,8 +521,6 @@ fn build_effect_after( loc_body: Box::new(Located::at_zero(to_effect_call)), }; - use roc_can::annotation::IntroducedVariables; - let mut introduced_variables = IntroducedVariables::default(); let signature = { @@ -537,26 +530,25 @@ fn build_effect_after( introduced_variables.insert_named("a".into(), var_a); introduced_variables.insert_named("b".into(), var_b); - let effect_a = { - let actual = - build_effect_actual(effect_tag_name.clone(), Type::Variable(var_a), var_store); + let effect_a = build_effect_alias( + effect_symbol, + effect_tag_name.clone(), + "a", + var_a, + Type::Variable(var_a), + var_store, + &mut introduced_variables, + ); - Type::Alias( - effect_symbol, - vec![("a".into(), Type::Variable(var_a))], - Box::new(actual), - ) - }; - - let effect_b = { - let actual = build_effect_actual(effect_tag_name, Type::Variable(var_b), var_store); - - Type::Alias( - effect_symbol, - vec![("b".into(), Type::Variable(var_b))], - Box::new(actual), - ) - }; + let effect_b = build_effect_alias( + effect_symbol, + effect_tag_name, + "b", + var_b, + Type::Variable(var_b), + var_store, + &mut introduced_variables, + ); let closure_var = var_store.fresh(); introduced_variables.insert_wildcard(closure_var); @@ -763,6 +755,40 @@ pub fn build_host_exposed_def( } } +fn build_effect_alias( + effect_symbol: Symbol, + effect_tag_name: TagName, + a_name: &str, + a_var: Variable, + a_type: Type, + var_store: &mut VarStore, + introduced_variables: &mut IntroducedVariables, +) -> Type { + let closure_var = var_store.fresh(); + introduced_variables.insert_wildcard(closure_var); + + let actual = { + Type::TagUnion( + vec![( + effect_tag_name, + vec![Type::Function( + vec![Type::EmptyRec], + Box::new(Type::Variable(closure_var)), + Box::new(a_type), + )], + )], + Box::new(Type::EmptyTagUnion), + ) + }; + + Type::Alias { + symbol: effect_symbol, + type_arguments: vec![(a_name.into(), Type::Variable(a_var))], + lambda_set_variables: vec![roc_types::subs::LambdaSet(closure_var)], + actual: Box::new(actual), + } +} + pub fn build_effect_actual( effect_tag_name: TagName, a_type: Type, diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index 914c7149b7..16f969d045 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -790,8 +790,14 @@ fn type_to_variable( tag_union_var } - Alias(Symbol::BOOL_BOOL, _, _) => Variable::BOOL, - Alias(symbol, args, alias_type) => { + + Type::Alias { + symbol, + type_arguments: args, + actual: alias_type, + lambda_set_variables, + } => { + dbg!(lambda_set_variables); let mut arg_vars = Vec::with_capacity(args.len()); for (arg, arg_type) in args { diff --git a/compiler/types/src/solved_types.rs b/compiler/types/src/solved_types.rs index 4bf65f0966..d091ea8413 100644 --- a/compiler/types/src/solved_types.rs +++ b/compiler/types/src/solved_types.rs @@ -183,6 +183,7 @@ pub enum SolvedType { Erroneous(Problem), /// A type alias + /// TODO transmit lambda sets! Alias(Symbol, Vec<(Lowercase, SolvedType)>, Box), HostExposedAlias { @@ -293,11 +294,16 @@ impl SolvedType { ) } Erroneous(problem) => SolvedType::Erroneous(problem.clone()), - Alias(symbol, args, box_type) => { + Alias { + symbol, + type_arguments, + actual: box_type, + .. + } => { let solved_type = Self::from_type(solved_subs, box_type); - let mut solved_args = Vec::with_capacity(args.len()); + let mut solved_args = Vec::with_capacity(type_arguments.len()); - for (name, var) in args { + for (name, var) in type_arguments { solved_args.push((name.clone(), Self::from_type(solved_subs, var))); } @@ -617,7 +623,12 @@ pub fn to_type( let actual = to_type(solved_actual, free_vars, var_store); - Type::Alias(*symbol, type_variables, Box::new(actual)) + Type::Alias { + symbol: *symbol, + type_arguments: type_variables, + lambda_set_variables: vec![], // TODO transfer lambda sets + actual: Box::new(actual), + } } HostExposedAlias { name, diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index fa240dad0c..5875fc8924 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -206,7 +206,7 @@ impl UnifyKey for Variable { } #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct LambdaSet(Variable); +pub struct LambdaSet(pub Variable); impl fmt::Debug for LambdaSet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/compiler/types/src/types.rs b/compiler/types/src/types.rs index 7e0e54d3f4..56f7443f6d 100644 --- a/compiler/types/src/types.rs +++ b/compiler/types/src/types.rs @@ -12,6 +12,11 @@ pub const TYPE_NUM: &str = "Num"; pub const TYPE_INTEGER: &str = "Integer"; pub const TYPE_FLOATINGPOINT: &str = "FloatingPoint"; +const GREEK_LETTERS: &[char] = &[ + 'α', 'ν', 'β', 'ξ', 'γ', 'ο', 'δ', 'π', 'ε', 'ρ', 'ζ', 'σ', 'η', 'τ', 'θ', 'υ', 'ι', 'φ', 'κ', + 'χ', 'λ', 'ψ', 'μ', 'ω', 'ς', +]; + /// /// Intuitively /// @@ -142,7 +147,12 @@ pub enum Type { Record(SendMap>, Box), TagUnion(Vec<(TagName, Vec)>, Box), FunctionOrTagUnion(TagName, Symbol, Box), - Alias(Symbol, Vec<(Lowercase, Type)>, Box), + Alias { + symbol: Symbol, + type_arguments: Vec<(Lowercase, Type)>, + lambda_set_variables: Vec, + actual: Box, + }, HostExposedAlias { name: Symbol, arguments: Vec<(Lowercase, Type)>, @@ -198,13 +208,22 @@ impl fmt::Debug for Type { write!(f, ")") } - Type::Alias(symbol, args, _actual) => { + Type::Alias { + symbol, + type_arguments, + lambda_set_variables, + .. + } => { write!(f, "Alias {:?}", symbol)?; - for (_, arg) in args { + for (_, arg) in type_arguments { write!(f, " {:?}", arg)?; } + for (_, greek_letter) in lambda_set_variables.iter().zip(GREEK_LETTERS.iter()) { + write!(f, " {:?}", greek_letter)?; + } + // Sometimes it's useful to see the expansion of the alias // write!(f, "[ but actually {:?} ]", _actual)?; @@ -442,11 +461,16 @@ impl Type { } ext.substitute(substitutions); } - Alias(_, zipped, actual_type) => { - for (_, value) in zipped.iter_mut() { + Alias { + type_arguments, + actual, + .. + } => { + for (_, value) in type_arguments.iter_mut() { value.substitute(substitutions); } - actual_type.substitute(substitutions); + + actual.substitute(substitutions); } HostExposedAlias { arguments, @@ -497,8 +521,11 @@ impl Type { } ext.substitute_alias(rep_symbol, actual); } - Alias(_, _, actual_type) => { - actual_type.substitute_alias(rep_symbol, actual); + Alias { + actual: alias_actual, + .. + } => { + alias_actual.substitute_alias(rep_symbol, actual); } HostExposedAlias { actual: actual_type, @@ -547,9 +574,11 @@ impl Type { ext.contains_symbol(rep_symbol) || fields.values().any(|arg| arg.contains_symbol(rep_symbol)) } - Alias(alias_symbol, _, actual_type) => { - alias_symbol == &rep_symbol || actual_type.contains_symbol(rep_symbol) - } + Alias { + symbol: alias_symbol, + actual: actual_type, + .. + } => alias_symbol == &rep_symbol || actual_type.contains_symbol(rep_symbol), HostExposedAlias { name, actual, .. } => { name == &rep_symbol || actual.contains_symbol(rep_symbol) } @@ -585,7 +614,10 @@ impl Type { .values() .any(|arg| arg.contains_variable(rep_variable)) } - Alias(_, _, actual_type) => actual_type.contains_variable(rep_variable), + Alias { + actual: actual_type, + .. + } => actual_type.contains_variable(rep_variable), HostExposedAlias { actual, .. } => actual.contains_variable(rep_variable), Apply(_, args) => args.iter().any(|arg| arg.contains_variable(rep_variable)), EmptyRec | EmptyTagUnion | Erroneous(_) => false, @@ -602,7 +634,7 @@ impl Type { /// a shallow dealias, continue until the first constructor is not an alias. pub fn shallow_dealias(&self) -> &Self { match self { - Type::Alias(_, _, actual) => actual.shallow_dealias(), + Type::Alias { actual, .. } => actual.shallow_dealias(), _ => self, } } @@ -646,7 +678,11 @@ impl Type { actual: actual_type, .. } - | Alias(_, type_args, actual_type) => { + | Alias { + type_arguments: type_args, + actual: actual_type, + .. + } => { for arg in type_args { arg.1 .instantiate_aliases(region, aliases, var_store, introduced); @@ -737,13 +773,19 @@ impl Type { } ext.substitute(&substitution); - *self = Type::Alias( - *symbol, - named_args, - Box::new(Type::RecursiveTagUnion(new_rec_var, tags, ext)), - ); + *self = Type::Alias { + symbol: *symbol, + type_arguments: named_args, + lambda_set_variables: alias.lambda_set_variables.clone(), + actual: Box::new(Type::RecursiveTagUnion(new_rec_var, tags, ext)), + }; } else { - *self = Type::Alias(*symbol, named_args, Box::new(actual)); + *self = Type::Alias { + symbol: *symbol, + type_arguments: named_args, + lambda_set_variables: alias.lambda_set_variables.clone(), + actual: Box::new(actual), + }; } } else { // one of the special-cased Apply types. @@ -789,7 +831,11 @@ fn symbols_help(tipe: &Type, accum: &mut ImSet) { } }); } - Alias(alias_symbol, _, actual_type) => { + Alias { + symbol: alias_symbol, + actual: actual_type, + .. + } => { accum.insert(*alias_symbol); symbols_help(&actual_type, accum); } @@ -859,8 +905,12 @@ fn variables_help(tipe: &Type, accum: &mut ImSet) { // this rec var doesn't need to be in flex_vars or rigid_vars accum.remove(rec); } - Alias(_, args, actual) => { - for (_, arg) in args { + Alias { + type_arguments, + actual, + .. + } => { + for (_, arg) in type_arguments { variables_help(arg, accum); } variables_help(actual, accum); @@ -884,7 +934,7 @@ fn variables_help(tipe: &Type, accum: &mut ImSet) { #[derive(Default)] pub struct VariableDetail { pub type_variables: MutSet, - pub lambda_set_variables: MutSet, + pub lambda_set_variables: Vec, pub recursion_variables: MutSet, } @@ -911,7 +961,7 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) { variables_help_detailed(arg, accum); } if let Type::Variable(v) = **closure { - accum.lambda_set_variables.insert(LambdaSet::from(v)); + accum.lambda_set_variables.push(LambdaSet::from(v)); } else { variables_help_detailed(closure, accum); } @@ -957,8 +1007,12 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) { accum.recursion_variables.insert(*rec); } - Alias(_, args, actual) => { - for (_, arg) in args { + Alias { + type_arguments, + actual, + .. + } => { + for (_, arg) in type_arguments { variables_help_detailed(arg, accum); } variables_help_detailed(actual, accum); @@ -1106,7 +1160,7 @@ pub struct Alias { /// lambda set variables, e.g. the one annotating the arrow in /// a |c|-> b - pub lambda_set_variables: MutSet, + pub lambda_set_variables: Vec, pub recursion_variables: MutSet, diff --git a/editor/src/lang/solve.rs b/editor/src/lang/solve.rs index f248cc4999..7271701782 100644 --- a/editor/src/lang/solve.rs +++ b/editor/src/lang/solve.rs @@ -767,7 +767,6 @@ fn type_to_variable<'a>( register(subs, rank, pools, content) } - Alias(Symbol::BOOL_BOOL, _, _) => roc_types::subs::Variable::BOOL, Alias(symbol, args, alias_type_id) => { // TODO cache in uniqueness inference gives problems! all Int's get the same uniqueness var! // Cache aliases without type arguments. Commonly used aliases like `Int` would otherwise get O(n)