store lambda set in alias types

This commit is contained in:
Folkert 2021-07-28 15:26:25 +02:00
parent dad5d5de85
commit 4cefbec5c7
11 changed files with 223 additions and 103 deletions

View File

@ -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()),
}
}
}
_ => {

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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,
};

View File

@ -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 {
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),

View File

@ -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,

View File

@ -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 {

View File

@ -183,6 +183,7 @@ pub enum SolvedType {
Erroneous(Problem),
/// A type alias
/// TODO transmit lambda sets!
Alias(Symbol, Vec<(Lowercase, SolvedType)>, Box<SolvedType>),
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,

View File

@ -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 {

View File

@ -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<Lowercase, RecordField<Type>>, Box<Type>),
TagUnion(Vec<(TagName, Vec<Type>)>, Box<Type>),
FunctionOrTagUnion(TagName, Symbol, Box<Type>),
Alias(Symbol, Vec<(Lowercase, Type)>, Box<Type>),
Alias {
symbol: Symbol,
type_arguments: Vec<(Lowercase, Type)>,
lambda_set_variables: Vec<LambdaSet>,
actual: Box<Type>,
},
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<Symbol>) {
}
});
}
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<Variable>) {
// 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<Variable>) {
#[derive(Default)]
pub struct VariableDetail {
pub type_variables: MutSet<Variable>,
pub lambda_set_variables: MutSet<LambdaSet>,
pub lambda_set_variables: Vec<LambdaSet>,
pub recursion_variables: MutSet<Variable>,
}
@ -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<LambdaSet>,
pub lambda_set_variables: Vec<LambdaSet>,
pub recursion_variables: MutSet<Variable>,

View File

@ -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)