From b71ab55e3e8583708b338d9e07fa5ba4e7f79655 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 11 Feb 2020 20:41:31 +0100 Subject: [PATCH 1/3] thread the aliases into the solver --- src/can/annotation.rs | 37 +++++--- src/can/def.rs | 12 +-- src/can/scope.rs | 9 +- src/constrain/builtins.rs | 1 + src/constrain/expr.rs | 19 +++- src/constrain/module.rs | 1 + src/infer.rs | 6 +- src/load/mod.rs | 12 +-- src/solve.rs | 176 ++++++++++++++++++++++---------------- src/types/mod.rs | 8 ++ src/uniqueness/mod.rs | 19 +++- 11 files changed, 190 insertions(+), 110 deletions(-) diff --git a/src/can/annotation.rs b/src/can/annotation.rs index bb315994bd..25212c5c7e 100644 --- a/src/can/annotation.rs +++ b/src/can/annotation.rs @@ -6,9 +6,10 @@ use crate::can::scope::Scope; use crate::collections::{default_hasher, ImMap, MutMap, MutSet, SendMap}; use crate::module::symbol::Symbol; use crate::parse::ast::{AssignedField, Tag, TypeAnnotation}; +use crate::region::Located; use crate::region::Region; use crate::subs::{VarStore, Variable}; -use crate::types::{Problem, Type}; +use crate::types::{Alias, Problem, Type}; use std::collections::HashSet; #[derive(Clone, Debug, PartialEq)] @@ -17,6 +18,7 @@ pub struct Annotation { pub ftv: MutMap, pub rigids: ImMap, pub references: MutSet, + pub aliases: SendMap, } pub fn canonicalize_annotation( @@ -38,7 +40,7 @@ pub fn canonicalize_annotation( // `ftv : SendMap`. let mut rigids = ImMap::default(); let mut local_aliases = Vec::new(); - let (mut typ, references) = can_annotation_help( + let (typ, references) = can_annotation_help( env, annotation, region, @@ -48,8 +50,11 @@ pub fn canonicalize_annotation( &mut local_aliases, ); - for (symbol, tipe) in local_aliases { - typ.substitute_alias(symbol, &tipe); + let mut aliases = SendMap::default(); + for (symbol, (vars, typ)) in local_aliases { + let alias = Alias { region, vars, typ }; + + aliases.insert(symbol, alias); } let mut ftv = MutMap::default(); @@ -63,6 +68,7 @@ pub fn canonicalize_annotation( ftv, references, rigids, + aliases, } } @@ -73,8 +79,8 @@ fn can_annotation_help( scope: &mut Scope, var_store: &VarStore, rigids: &mut ImMap, - local_aliases: &mut Vec<(Symbol, crate::types::Type)>, -) -> (crate::types::Type, MutSet) { + local_aliases: &mut Vec<(Symbol, (Vec>, Type))>, +) -> (Type, MutSet) { use crate::parse::ast::TypeAnnotation::*; match annotation { @@ -245,6 +251,7 @@ fn can_annotation_help( local_aliases, ); let mut vars = Vec::with_capacity(loc_vars.len()); + let mut lowercase_vars = Vec::with_capacity(loc_vars.len()); references.insert(symbol); @@ -259,7 +266,9 @@ fn can_annotation_help( let var = var_store.fresh(); rigids.insert(var_name.clone(), var); - vars.push((var_name, Type::Variable(var))); + vars.push((var_name.clone(), Type::Variable(var))); + + lowercase_vars.push(Located::at(loc_var.region, (var_name, var))); } } _ => { @@ -273,7 +282,7 @@ fn can_annotation_help( } } - let alias = if let Type::TagUnion(tags, ext) = inner_type { + let alias_actual = if let Type::TagUnion(tags, ext) = inner_type { let rec_var = var_store.fresh(); let mut new_tags = Vec::with_capacity(tags.len()); @@ -287,13 +296,13 @@ fn can_annotation_help( new_tags.push((tag_name.clone(), new_args)); } let rec_tag_union = Type::RecursiveTagUnion(rec_var, new_tags, ext); - - Type::Alias(symbol, vars, Box::new(rec_tag_union)) + rec_tag_union } else { - Type::Alias(symbol, vars, Box::new(inner_type)) + inner_type }; - local_aliases.push((symbol, alias.clone())); + let alias = Type::Alias(symbol, vars, Box::new(alias_actual.clone())); + local_aliases.push((symbol, (lowercase_vars, alias_actual))); (alias, references) } @@ -398,7 +407,7 @@ fn can_assigned_field<'a>( scope: &mut Scope, var_store: &VarStore, rigids: &mut ImMap, - local_aliases: &mut Vec<(Symbol, Type)>, + local_aliases: &mut Vec<(Symbol, (Vec>, Type))>, field_types: &mut SendMap, ) -> MutSet { use crate::parse::ast::AssignedField::*; @@ -460,7 +469,7 @@ fn can_tag<'a>( scope: &mut Scope, var_store: &VarStore, rigids: &mut ImMap, - local_aliases: &mut Vec<(Symbol, Type)>, + local_aliases: &mut Vec<(Symbol, (Vec>, Type))>, tag_types: &mut Vec<(TagName, Vec)>, ) -> MutSet { match tag { diff --git a/src/can/def.rs b/src/can/def.rs index 4905a25c08..ee3515d7a4 100644 --- a/src/can/def.rs +++ b/src/can/def.rs @@ -18,7 +18,7 @@ use crate::module::symbol::Symbol; use crate::parse::ast; use crate::region::{Located, Region}; use crate::subs::{VarStore, Variable}; -use crate::types::Type; +use crate::types::{Alias, Type}; use std::cmp::Ordering; use std::collections::HashMap; use std::fmt::Debug; @@ -29,7 +29,7 @@ pub struct Def { pub loc_expr: Located, pub expr_var: Variable, pub pattern_vars: SendMap, - pub annotation: Option<(Type, SendMap)>, + pub annotation: Option<(Type, SendMap, SendMap)>, } #[derive(Debug)] @@ -741,7 +741,7 @@ fn canonicalize_pending_def<'a>( value: loc_can_expr.value.clone(), }, pattern_vars: im::HashMap::clone(&vars_by_symbol), - annotation: Some((typ.clone(), found_rigids.clone())), + annotation: Some((typ.clone(), found_rigids.clone(), ann.aliases.clone())), }, ); } @@ -760,11 +760,11 @@ fn canonicalize_pending_def<'a>( } } - TypedBody(loc_pattern, loc_can_pattern, loc_annotation, loc_expr) => { + TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr) => { // TODO we have ann.references here, which includes information about // which symbols were referenced in type annotations, but we never // use them. We discard them! - let ann = loc_annotation.value; + let ann = loc_ann.value; let typ = ann.typ; // union seen rigids with already found ones @@ -887,7 +887,7 @@ fn canonicalize_pending_def<'a>( value: loc_can_expr.value.clone(), }, pattern_vars: im::HashMap::clone(&vars_by_symbol), - annotation: Some((typ.clone(), found_rigids.clone())), + annotation: Some((typ.clone(), found_rigids.clone(), ann.aliases.clone())), }, ); } diff --git a/src/can/scope.rs b/src/can/scope.rs index 750e103097..063f0c290f 100644 --- a/src/can/scope.rs +++ b/src/can/scope.rs @@ -4,14 +4,7 @@ use crate::collections::ImMap; use crate::module::symbol::{IdentIds, ModuleId, Symbol}; use crate::region::{Located, Region}; use crate::subs::Variable; -use crate::types::Type; - -#[derive(Clone, Debug, PartialEq)] -pub struct Alias { - pub region: Region, - pub vars: Vec>, - pub typ: Type, -} +use crate::types::{Alias, Type}; #[derive(Clone, Debug, PartialEq)] pub struct Scope { diff --git a/src/constrain/builtins.rs b/src/constrain/builtins.rs index c088537967..cee65c0e59 100644 --- a/src/constrain/builtins.rs +++ b/src/constrain/builtins.rs @@ -29,6 +29,7 @@ pub fn exists(flex_vars: Vec, constraint: Constraint) -> Constraint { rigid_vars: Vec::new(), flex_vars, def_types: SendMap::default(), + def_aliases: SendMap::default(), defs_constraint: constraint, ret_constraint: Constraint::True, })) diff --git a/src/constrain/expr.rs b/src/constrain/expr.rs index 2c9fef40bf..6087504ac7 100644 --- a/src/constrain/expr.rs +++ b/src/constrain/expr.rs @@ -11,6 +11,7 @@ use crate::constrain::pattern::{constrain_pattern, PatternState}; use crate::module::symbol::{ModuleId, Symbol}; use crate::region::{Located, Region}; use crate::subs::Variable; +use crate::types::Alias; use crate::types::AnnotationSource::{self, *}; use crate::types::Constraint::{self, *}; use crate::types::Expected::{self, *}; @@ -42,6 +43,7 @@ pub fn exists(flex_vars: Vec, constraint: Constraint) -> Constraint { rigid_vars: Vec::new(), flex_vars, def_types: SendMap::default(), + def_aliases: SendMap::default(), defs_constraint: constraint, ret_constraint: Constraint::True, })) @@ -283,6 +285,7 @@ pub fn constrain_expr( rigid_vars: Vec::new(), flex_vars: state.vars, def_types: state.headers, + def_aliases: SendMap::default(), defs_constraint, ret_constraint, })), @@ -638,6 +641,7 @@ fn constrain_when_branch( rigid_vars: Vec::new(), flex_vars: state.vars, def_types: state.headers, + def_aliases: SendMap::default(), defs_constraint: Constraint::And(state.constraints), ret_constraint, })) @@ -711,15 +715,18 @@ fn constrain_def_pattern(loc_pattern: &Located, expr_type: Type) -> Pat pub fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint { let expr_var = def.expr_var; let expr_type = Type::Variable(expr_var); + let mut def_aliases: SendMap = SendMap::default(); let mut pattern_state = constrain_def_pattern(&def.loc_pattern, expr_type.clone()); pattern_state.vars.push(expr_var); + let mut def_aliases = SendMap::default(); let mut new_rigids = Vec::new(); let expr_con = match &def.annotation { - Some((annotation, free_vars)) => { + Some((annotation, free_vars, ann_def_aliases)) => { + def_aliases = ann_def_aliases.clone(); let mut annotation = annotation.clone(); let rigids = &env.rigids; let mut ftv: ImMap = rigids.clone(); @@ -787,10 +794,12 @@ pub fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint { rigid_vars: new_rigids, flex_vars: pattern_state.vars, def_types: pattern_state.headers, + def_aliases, defs_constraint: Let(Box::new(LetConstraint { rigid_vars: Vec::new(), // always empty flex_vars: Vec::new(), // empty, because our functions have no arguments def_types: SendMap::default(), // empty, because our functions have no arguments! + def_aliases: SendMap::default(), defs_constraint: And(pattern_state.constraints), ret_constraint: expr_con, })), @@ -851,6 +860,7 @@ pub fn rec_defs_help( rigid_vars: Vec::new(), flex_vars: Vec::new(), // empty because Roc function defs have no args def_types: SendMap::default(), // empty because Roc function defs have no args + def_aliases: SendMap::default(), defs_constraint: True, // I think this is correct, once again because there are no args ret_constraint: expr_con, })); @@ -860,7 +870,7 @@ pub fn rec_defs_help( flex_info.def_types.extend(pattern_state.headers); } - Some((annotation, seen_rigids)) => { + Some((annotation, seen_rigids, def_aliases)) => { // TODO also do this for more complex patterns if let Pattern::Identifier(symbol) = def.loc_pattern.value { pattern_state.headers.insert( @@ -910,6 +920,7 @@ pub fn rec_defs_help( rigid_vars: Vec::new(), flex_vars: Vec::new(), // empty because Roc function defs have no args def_types: SendMap::default(), // empty because Roc function defs have no args + def_aliases: SendMap::default(), defs_constraint: True, // I think this is correct, once again because there are no args ret_constraint: expr_con, })); @@ -921,6 +932,7 @@ pub fn rec_defs_help( rigid_vars: new_rigids, flex_vars: Vec::new(), // no flex vars introduced def_types: SendMap::default(), // no headers introduced (at this level) + def_aliases: SendMap::default(), defs_constraint: def_con, ret_constraint: True, }))); @@ -933,15 +945,18 @@ pub fn rec_defs_help( rigid_vars: rigid_info.vars, flex_vars: Vec::new(), def_types: rigid_info.def_types, + def_aliases: SendMap::default(), defs_constraint: True, ret_constraint: Let(Box::new(LetConstraint { rigid_vars: Vec::new(), flex_vars: flex_info.vars, def_types: flex_info.def_types.clone(), + def_aliases: SendMap::default(), defs_constraint: Let(Box::new(LetConstraint { rigid_vars: Vec::new(), flex_vars: Vec::new(), def_types: flex_info.def_types, + def_aliases: SendMap::default(), defs_constraint: True, ret_constraint: And(flex_info.constraints), })), diff --git a/src/constrain/module.rs b/src/constrain/module.rs index b69409ee1f..4bd512b9f2 100644 --- a/src/constrain/module.rs +++ b/src/constrain/module.rs @@ -139,6 +139,7 @@ fn constrain_imported_value( // Importing a value doesn't constrain this module at all. // All it does is introduce variables and provide def_types for lookups def_types, + def_aliases: SendMap::default(), defs_constraint: True, ret_constraint: body_con, })) diff --git a/src/infer.rs b/src/infer.rs index 5ef847680a..363f8d4530 100644 --- a/src/infer.rs +++ b/src/infer.rs @@ -9,7 +9,11 @@ pub fn infer_expr( constraint: &Constraint, expr_var: Variable, ) -> (Content, Solved) { - let (solved, _) = solve::run(&SendMap::default(), problems, subs, constraint); + let env = solve::Env { + aliases: SendMap::default(), + vars_by_symbol: SendMap::default(), + }; + let (solved, _) = solve::run(&env, problems, subs, constraint); let content = solved.inner().get_without_compacting(expr_var).content; diff --git a/src/load/mod.rs b/src/load/mod.rs index 9731dcacc6..242fcf76c6 100644 --- a/src/load/mod.rs +++ b/src/load/mod.rs @@ -78,7 +78,7 @@ enum Msg { solved_types: MutMap, subs: Arc>, problems: Vec, - new_vars_by_symbol: SendMap, + new_vars_by_symbol: solve::Env, }, } @@ -407,8 +407,6 @@ pub async fn load<'a>( }); } else { // This was a dependency. Write it down and keep processing messaages. - vars_by_symbol = vars_by_symbol.union(new_vars_by_symbol); - debug_assert!(!exposed_types.contains_key(&module_id)); exposed_types.insert(module_id, ExposedModuleTypes::Valid(solved_types)); @@ -788,9 +786,13 @@ fn solve_module( let subs = Subs::new(var_store.into()); let mut problems = Vec::new(); + let env = solve::Env { + vars_by_symbol, + aliases: SendMap::default(), + }; + // Run the solver to populate Subs. - let (solved_subs, new_vars_by_symbol) = - solve::run(&vars_by_symbol, &mut problems, subs, &constraint); + let (solved_subs, new_vars_by_symbol) = solve::run(&env, &mut problems, subs, &constraint); let mut solved_types = MutMap::default(); diff --git a/src/solve.rs b/src/solve.rs index 5f0406567a..cbd80439ea 100644 --- a/src/solve.rs +++ b/src/solve.rs @@ -3,6 +3,7 @@ use crate::collections::{ImMap, MutMap, SendMap}; use crate::module::symbol::{ModuleId, Symbol}; use crate::region::Located; use crate::subs::{Content, Descriptor, FlatType, Mark, OptVariable, Rank, Subs, Variable}; +use crate::types::Alias; use crate::types::Constraint::{self, *}; use crate::types::Problem; use crate::types::Type::{self, *}; @@ -162,7 +163,11 @@ impl SolvedType { } } -type Env = SendMap; +#[derive(Clone, Debug)] +pub struct Env { + pub vars_by_symbol: SendMap, + pub aliases: SendMap, +} const DEFAULT_POOLS: usize = 8; @@ -215,7 +220,7 @@ impl Pools { #[derive(Clone)] struct State { - vars_by_symbol: Env, + env: Env, mark: Mark, } @@ -235,32 +240,26 @@ impl Solved { } pub fn run( - vars_by_symbol: &Env, + env: &Env, problems: &mut Vec, mut subs: Subs, constraint: &Constraint, ) -> (Solved, Env) { let mut pools = Pools::default(); let state = State { - vars_by_symbol: vars_by_symbol.clone(), + env: env.clone(), mark: Mark::NONE.next(), }; let rank = Rank::toplevel(); let state = solve( - vars_by_symbol, - state, - rank, - &mut pools, - problems, - &mut subs, - constraint, + env, state, rank, &mut pools, problems, &mut subs, constraint, ); - (Solved(subs), state.vars_by_symbol) + (Solved(subs), state.env) } fn solve( - vars_by_symbol: &Env, + env: &Env, state: State, rank: Rank, pools: &mut Pools, @@ -273,13 +272,19 @@ fn solve( SaveTheEnvironment => { let mut copy = state; - copy.vars_by_symbol = vars_by_symbol.clone(); + copy.env = env.clone(); copy } Eq(typ, expected_type, _region) => { - let actual = type_to_var(subs, rank, pools, typ); - let expected = type_to_var(subs, rank, pools, expected_type.get_type_ref()); + let actual = type_to_var(subs, rank, pools, &env.aliases, typ); + let expected = type_to_var( + subs, + rank, + pools, + &env.aliases, + expected_type.get_type_ref(), + ); let Unified { vars, mismatches } = unify(subs, actual, expected); // TODO use region when reporting a problem @@ -290,12 +295,12 @@ fn solve( state } Lookup(symbol, expected_type, _region) => { - let var = *vars_by_symbol.get(&symbol).unwrap_or_else(|| { + let var = *env.vars_by_symbol.get(&symbol).unwrap_or_else(|| { // TODO Instead of panicking, solve this as True and record // a Problem ("module Foo does not expose `bar`") for later. panic!( "Could not find symbol {:?} in vars_by_symbol {:?}", - symbol, vars_by_symbol + symbol, env.vars_by_symbol ) }); @@ -321,7 +326,13 @@ fn solve( // is being looked up in this module, then we use our Subs as both // the source and destination. let actual = deep_copy_var(subs, rank, pools, var); - let expected = type_to_var(subs, rank, pools, expected_type.get_type_ref()); + let expected = type_to_var( + subs, + rank, + pools, + &env.aliases, + expected_type.get_type_ref(), + ); let Unified { vars, mismatches } = unify(subs, actual, expected); // TODO use region when reporting a problem @@ -335,22 +346,14 @@ fn solve( let mut state = state; for sub_constraint in sub_constraints.iter() { - state = solve( - vars_by_symbol, - state, - rank, - pools, - problems, - subs, - sub_constraint, - ); + state = solve(env, state, rank, pools, problems, subs, sub_constraint); } state } Pattern(_region, _category, typ, expected) => { - let actual = type_to_var(subs, rank, pools, typ); - let expected = type_to_var(subs, rank, pools, expected.get_type_ref()); + let actual = type_to_var(subs, rank, pools, &env.aliases, typ); + let expected = type_to_var(subs, rank, pools, &env.aliases, expected.get_type_ref()); let Unified { vars, mismatches } = unify(subs, actual, expected); // TODO use region when reporting a problem @@ -368,7 +371,7 @@ fn solve( // If the return expression is guaranteed to solve, // solve the assignments themselves and move on. solve( - vars_by_symbol, + env, state, rank, pools, @@ -379,7 +382,7 @@ fn solve( } ret_con if let_con.rigid_vars.is_empty() && let_con.flex_vars.is_empty() => { let state = solve( - vars_by_symbol, + env, state, rank, pools, @@ -388,11 +391,17 @@ fn solve( &let_con.defs_constraint, ); + let mut new_env = env.clone(); + + for (symbol, alias) in let_con.def_aliases.iter() { + new_env.aliases.insert(*symbol, alias.clone()); + } + // Add a variable for each def to new_vars_by_env. let mut local_def_vars = ImMap::default(); for (symbol, loc_type) in let_con.def_types.iter() { - let var = type_to_var(subs, rank, pools, &loc_type.value); + let var = type_to_var(subs, rank, pools, &new_env.aliases, &loc_type.value); local_def_vars.insert( symbol.clone(), @@ -403,23 +412,13 @@ fn solve( ); } - let mut new_vars_by_symbol = vars_by_symbol.clone(); - for (symbol, loc_var) in local_def_vars.iter() { - if !new_vars_by_symbol.contains_key(&symbol) { - new_vars_by_symbol.insert(symbol.clone(), loc_var.value); + if !new_env.vars_by_symbol.contains_key(&symbol) { + new_env.vars_by_symbol.insert(symbol.clone(), loc_var.value); } } - let new_state = solve( - &new_vars_by_symbol, - state, - rank, - pools, - problems, - subs, - ret_con, - ); + let new_state = solve(&new_env, state, rank, pools, problems, subs, ret_con); for (symbol, loc_var) in local_def_vars { check_for_infinite_type(subs, problems, symbol, loc_var); @@ -448,12 +447,26 @@ fn solve( pool.extend(rigid_vars.iter()); pool.extend(flex_vars.iter()); + let mut new_env = env.clone(); + + for (symbol, alias) in let_con.def_aliases.iter() { + new_env.aliases.insert(*symbol, alias.clone()); + } + // Add a variable for each def to local_def_vars. let mut local_def_vars = ImMap::default(); for (symbol, loc_type) in let_con.def_types.iter() { let def_type = loc_type.value.clone(); - let var = type_to_var(subs, next_rank, next_pools, &def_type); + + // TODO should this use new aliases? + let var = type_to_var( + subs, + next_rank, + next_pools, + &new_env.aliases, + &def_type, + ); local_def_vars.insert( symbol.clone(), @@ -468,7 +481,7 @@ fn solve( // Solve the assignments' constraints first. let new_state = solve( - vars_by_symbol, + &new_env, state, next_rank, next_pools, @@ -513,31 +526,24 @@ fn solve( failing.is_empty() }); - let mut new_vars_by_symbol = vars_by_symbol.clone(); for (symbol, loc_var) in local_def_vars.iter() { - if !new_vars_by_symbol.contains_key(&symbol) { - new_vars_by_symbol.insert(symbol.clone(), loc_var.value); + if !new_env.vars_by_symbol.contains_key(&symbol) { + new_env.vars_by_symbol.insert(symbol.clone(), loc_var.value); } } // Note that this vars_by_symbol is the one returned by the // previous call to solve() let temp_state = State { - vars_by_symbol: new_state.vars_by_symbol, + env: new_state.env, mark: final_mark, }; // Now solve the body, using the new vars_by_symbol which includes // the assignments' name-to-variable mappings. let new_state = solve( - &new_vars_by_symbol, - temp_state, - rank, - next_pools, - problems, - subs, - &ret_con, + &new_env, temp_state, rank, next_pools, problems, subs, &ret_con, ); for (symbol, loc_var) in local_def_vars { @@ -559,30 +565,56 @@ fn solve( } } -fn type_to_var(subs: &mut Subs, rank: Rank, pools: &mut Pools, typ: &Type) -> Variable { - type_to_variable(subs, rank, pools, &ImMap::default(), typ) +fn type_to_var( + subs: &mut Subs, + rank: Rank, + pools: &mut Pools, + aliases: &SendMap, + typ: &Type, +) -> Variable { + dbg!(&aliases); + type_to_variable(subs, rank, pools, aliases, typ) } fn type_to_variable( subs: &mut Subs, rank: Rank, pools: &mut Pools, - aliases: &ImMap, + aliases: &SendMap, typ: &Type, ) -> Variable { match typ { Variable(var) => *var, Apply(symbol, args) => { - let mut arg_vars = Vec::with_capacity(args.len()); + if let Some(alias) = aliases.get(symbol) { + /* + let mut arg_vars = Vec::with_capacity(args.len()); + let mut new_aliases = ImMap::default(); - for arg in args { - arg_vars.push(type_to_variable(subs, rank, pools, aliases, arg)) + for (arg, arg_type) in alias.args { + let arg_var = type_to_variable(subs, rank, pools, aliases, arg_type); + + arg_vars.push((arg.clone(), arg_var)); + new_aliases.insert(arg.clone(), arg_var); + } + */ + + let alias_var = type_to_variable(subs, rank, pools, aliases, &alias.typ); + let content = Content::Alias(*symbol, vec![], alias_var); + + register(subs, rank, pools, content) + } else { + let mut arg_vars = Vec::with_capacity(args.len()); + + for arg in args { + arg_vars.push(type_to_variable(subs, rank, pools, aliases, arg)) + } + + let flat_type = FlatType::Apply(*symbol, arg_vars); + let content = Content::Structure(flat_type); + + register(subs, rank, pools, content) } - - let flat_type = FlatType::Apply(*symbol, arg_vars); - let content = Content::Structure(flat_type); - - register(subs, rank, pools, content) } EmptyRec => { let content = Content::Structure(FlatType::EmptyRecord); @@ -671,13 +703,13 @@ fn type_to_variable( let mut new_aliases = ImMap::default(); for (arg, arg_type) in args { - let arg_var = type_to_variable(subs, rank, pools, &ImMap::default(), arg_type); + let arg_var = type_to_variable(subs, rank, pools, aliases, arg_type); arg_vars.push((arg.clone(), arg_var)); new_aliases.insert(arg.clone(), arg_var); } - let alias_var = type_to_variable(subs, rank, pools, &new_aliases, alias_type); + let alias_var = type_to_variable(subs, rank, pools, aliases, alias_type); let content = Content::Alias(*symbol, arg_vars, alias_var); register(subs, rank, pools, content) diff --git a/src/types/mod.rs b/src/types/mod.rs index c7929c5aa2..d998235d66 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -571,10 +571,18 @@ pub struct LetConstraint { pub rigid_vars: Vec, pub flex_vars: Vec, pub def_types: SendMap>, + pub def_aliases: SendMap, pub defs_constraint: Constraint, pub ret_constraint: Constraint, } +#[derive(Clone, Debug, PartialEq)] +pub struct Alias { + pub region: Region, + pub vars: Vec>, + pub typ: Type, +} + #[derive(PartialEq, Eq, Debug, Clone)] pub enum Problem { CanonicalizationProblem, diff --git a/src/uniqueness/mod.rs b/src/uniqueness/mod.rs index cce7f70f10..4a1e0375fe 100644 --- a/src/uniqueness/mod.rs +++ b/src/uniqueness/mod.rs @@ -524,6 +524,7 @@ pub fn constrain_expr( rigid_vars: Vec::new(), flex_vars: state.vars, def_types: state.headers, + def_aliases: SendMap::default(), defs_constraint, ret_constraint, })), @@ -1212,6 +1213,7 @@ fn constrain_when_branch( rigid_vars: Vec::new(), flex_vars: state.vars, def_types: state.headers, + def_aliases: SendMap::default(), defs_constraint: Constraint::And(state.constraints), ret_constraint, })) @@ -1420,10 +1422,12 @@ pub fn constrain_def( pattern_state.vars.push(expr_var); + let mut def_aliases = SendMap::default(); let mut new_rigids = Vec::new(); let expr_con = match &def.annotation { - Some((annotation, free_vars)) => { + Some((annotation, free_vars, ann_def_aliases)) => { + def_aliases = ann_def_aliases.clone(); let rigids = &env.rigids; let mut ftv: ImMap = rigids.clone(); let (uniq_vars, annotation) = annotation_to_attr_type(var_store, annotation); @@ -1482,10 +1486,12 @@ pub fn constrain_def( rigid_vars: new_rigids, flex_vars: pattern_state.vars, def_types: pattern_state.headers, + def_aliases, defs_constraint: Let(Box::new(LetConstraint { rigid_vars: Vec::new(), // always empty flex_vars: Vec::new(), // empty, because our functions have no arguments def_types: SendMap::default(), // empty, because our functions have no arguments! + def_aliases: SendMap::default(), defs_constraint: And(pattern_state.constraints), ret_constraint: expr_con, })), @@ -1545,6 +1551,8 @@ pub fn rec_defs_help( pattern_expected, ); + // TODO see where aliases should go + let mut def_aliases = SendMap::default(); let mut new_rigids = Vec::new(); match &def.annotation { None => { @@ -1563,6 +1571,7 @@ pub fn rec_defs_help( rigid_vars: Vec::new(), flex_vars: Vec::new(), // empty because Roc function defs have no args def_types: SendMap::default(), // empty because Roc function defs have no args + def_aliases: SendMap::default(), defs_constraint: True, // I think this is correct, once again because there are no args ret_constraint: expr_con, })); @@ -1572,7 +1581,8 @@ pub fn rec_defs_help( flex_info.def_types.extend(pattern_state.headers); } - Some((annotation, seen_rigids)) => { + Some((annotation, seen_rigids, ann_def_aliases)) => { + def_aliases = ann_def_aliases.clone(); let (uniq_vars, annotation) = annotation_to_attr_type(var_store, annotation); // TODO also do this for more complex patterns @@ -1657,6 +1667,7 @@ pub fn rec_defs_help( rigid_vars: Vec::new(), flex_vars: Vec::new(), // empty because Roc function defs have no args def_types: SendMap::default(), // empty because Roc function defs have no args + def_aliases: SendMap::default(), defs_constraint: True, // I think this is correct, once again because there are no args ret_constraint: expr_con, })); @@ -1668,6 +1679,7 @@ pub fn rec_defs_help( rigid_vars: new_rigids, flex_vars: Vec::new(), // no flex vars introduced def_types: SendMap::default(), // no headers introduced (at this level) + def_aliases: SendMap::default(), defs_constraint: def_con, ret_constraint: True, }))); @@ -1680,15 +1692,18 @@ pub fn rec_defs_help( rigid_vars: rigid_info.vars, flex_vars: Vec::new(), def_types: rigid_info.def_types, + def_aliases: SendMap::default(), defs_constraint: True, ret_constraint: Let(Box::new(LetConstraint { rigid_vars: Vec::new(), flex_vars: flex_info.vars, def_types: flex_info.def_types.clone(), + def_aliases: SendMap::default(), defs_constraint: Let(Box::new(LetConstraint { rigid_vars: Vec::new(), flex_vars: Vec::new(), def_types: flex_info.def_types, + def_aliases: SendMap::default(), defs_constraint: True, ret_constraint: And(flex_info.constraints), })), From f87c1eddd18ae83d2316cead115c0b1bb0d6f22f Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 12 Feb 2020 00:19:35 +0100 Subject: [PATCH 2/3] add aliases to Let All tests pass again --- src/can/annotation.rs | 67 +++++++++------------------------------ src/can/def.rs | 42 +++++++++++++++++++++--- src/can/expr.rs | 8 +++-- src/can/module.rs | 11 ++++++- src/constrain/expr.rs | 36 +++++++++++++++++---- src/load/mod.rs | 25 +++++++++++---- src/mono/expr.rs | 2 +- src/solve.rs | 61 +++++++++++++++++++++++++++-------- src/uniqueness/mod.rs | 22 ++++++++----- src/uniqueness/sharing.rs | 4 +-- 10 files changed, 179 insertions(+), 99 deletions(-) diff --git a/src/can/annotation.rs b/src/can/annotation.rs index 25212c5c7e..1603da6ebc 100644 --- a/src/can/annotation.rs +++ b/src/can/annotation.rs @@ -39,7 +39,7 @@ pub fn canonicalize_annotation( // but a variable can only have one name. Therefore // `ftv : SendMap`. let mut rigids = ImMap::default(); - let mut local_aliases = Vec::new(); + let mut aliases = SendMap::default(); let (typ, references) = can_annotation_help( env, annotation, @@ -47,16 +47,9 @@ pub fn canonicalize_annotation( scope, var_store, &mut rigids, - &mut local_aliases, + &mut aliases, ); - let mut aliases = SendMap::default(); - for (symbol, (vars, typ)) in local_aliases { - let alias = Alias { region, vars, typ }; - - aliases.insert(symbol, alias); - } - let mut ftv = MutMap::default(); for (k, v) in rigids.clone() { @@ -79,7 +72,7 @@ fn can_annotation_help( scope: &mut Scope, var_store: &VarStore, rigids: &mut ImMap, - local_aliases: &mut Vec<(Symbol, (Vec>, Type))>, + local_aliases: &mut SendMap, ) -> (Type, MutSet) { use crate::parse::ast::TypeAnnotation::*; @@ -172,41 +165,7 @@ fn can_annotation_help( args.push(arg_ann); } - if let Some(alias) = scope.lookup_alias(symbol) { - let ftv = &alias.vars; - let actual = &alias.typ; - - if args.len() != ftv.len() { - panic!("TODO alias applied to incorrect number of type arguments"); - } - let mut zipped_args: Vec<(Lowercase, Type)> = Vec::with_capacity(args.len()); - let mut substitution = ImMap::default(); - - for (loc_var, arg) in ftv.iter().zip(args.iter()) { - substitution.insert(loc_var.value.1, arg.clone()); - zipped_args.push((loc_var.value.0.clone(), arg.clone())); - } - - let mut instantiated = actual.clone(); - instantiated.substitute(&substitution); - - if let Type::RecursiveTagUnion(rec, _, _) = &mut instantiated { - let new_rec = var_store.fresh(); - let old = *rec; - *rec = new_rec; - - let mut rec_substitution = ImMap::default(); - rec_substitution.insert(old, Type::Variable(new_rec)); - instantiated.substitute(&rec_substitution); - } - - ( - Type::Alias(symbol, zipped_args, Box::new(instantiated)), - references, - ) - } else { - (Type::Apply(symbol, args), references) - } + (Type::Apply(symbol, args), references) } BoundVariable(v) => { let name = Lowercase::from(*v); @@ -295,16 +254,20 @@ fn can_annotation_help( } new_tags.push((tag_name.clone(), new_args)); } - let rec_tag_union = Type::RecursiveTagUnion(rec_var, new_tags, ext); - rec_tag_union + Type::RecursiveTagUnion(rec_var, new_tags, ext) } else { inner_type }; - let alias = Type::Alias(symbol, vars, Box::new(alias_actual.clone())); - local_aliases.push((symbol, (lowercase_vars, alias_actual))); + let alias = Alias { + region, + vars: lowercase_vars, + typ: alias_actual.clone(), + }; + local_aliases.insert(symbol, alias); - (alias, references) + let type_alias = Type::Alias(symbol, vars, Box::new(alias_actual)); + (type_alias, references) } _ => { // This is a syntactically invalid type alias. @@ -407,7 +370,7 @@ fn can_assigned_field<'a>( scope: &mut Scope, var_store: &VarStore, rigids: &mut ImMap, - local_aliases: &mut Vec<(Symbol, (Vec>, Type))>, + local_aliases: &mut SendMap, field_types: &mut SendMap, ) -> MutSet { use crate::parse::ast::AssignedField::*; @@ -469,7 +432,7 @@ fn can_tag<'a>( scope: &mut Scope, var_store: &VarStore, rigids: &mut ImMap, - local_aliases: &mut Vec<(Symbol, (Vec>, Type))>, + local_aliases: &mut SendMap, tag_types: &mut Vec<(TagName, Vec)>, ) -> MutSet { match tag { diff --git a/src/can/def.rs b/src/can/def.rs index ee3515d7a4..1726dec613 100644 --- a/src/can/def.rs +++ b/src/can/def.rs @@ -23,6 +23,7 @@ use std::cmp::Ordering; use std::collections::HashMap; use std::fmt::Debug; +#[allow(clippy::type_complexity)] #[derive(Clone, Debug, PartialEq)] pub struct Def { pub loc_pattern: Located, @@ -39,6 +40,7 @@ pub struct CanDefs { pub refs_by_symbol: MutMap, References)>, pub can_defs_by_symbol: MutMap, pub symbols_introduced: MutMap, + pub aliases: SendMap, } /// A Def that has had patterns and type annnotations canonicalized, /// but no Expr canonicalization has happened yet. Also, it has had spaces @@ -186,6 +188,8 @@ pub fn canonicalize_defs<'a>( pending.sort_by(aliases_first); + let mut aliases = SendMap::default(); + // Now that we have the scope completely assembled, and shadowing resolved, // we're ready to canonicalize any body exprs. for pending_def in pending.into_iter() { @@ -198,6 +202,7 @@ pub fn canonicalize_defs<'a>( &mut can_defs_by_symbol, var_store, &mut refs_by_symbol, + &mut aliases, ); // TODO we should do something with these references; they include @@ -228,6 +233,7 @@ pub fn canonicalize_defs<'a>( refs_by_symbol, can_defs_by_symbol, symbols_introduced, + aliases, }, scope, ) @@ -243,8 +249,13 @@ pub fn sort_can_defs( symbols_introduced, refs_by_symbol, can_defs_by_symbol, + aliases, } = defs; + for (symbol, alias) in aliases.clone() { + output.aliases.insert(symbol, alias); + } + // Determine the full set of references by traversing the graph. let mut visited_symbols = MutSet::default(); let returned_lookups = ImSet::clone(&output.references.lookups); @@ -654,6 +665,7 @@ fn canonicalize_pending_def<'a>( can_defs_by_symbol: &mut MutMap, var_store: &VarStore, refs_by_symbol: &mut MutMap, References)>, + aliases: &mut SendMap, ) { use PendingDef::*; @@ -668,6 +680,10 @@ fn canonicalize_pending_def<'a>( // use them. We discard them! let ann = loc_ann.value; + for (symbol, alias) in ann.aliases.clone() { + aliases.insert(symbol, alias); + } + // union seen rigids with already found ones for (k, v) in ann.ftv { found_rigids.insert(k, v); @@ -747,9 +763,14 @@ fn canonicalize_pending_def<'a>( } } - Alias { ann, .. } => { + Alias { ann, name, .. } => { let can_ann = canonicalize_annotation(env, scope, &ann.value, ann.region, var_store); + // For now, use the alias from the scope (which already deals with (mutual) recursion) + if let Some(alias) = scope.lookup_alias(name.value) { + aliases.insert(name.value, alias.clone()); + } + // TODO should probably incorporate can_ann.references here - possibly by // inserting them into refs_by_symbol? @@ -767,6 +788,10 @@ fn canonicalize_pending_def<'a>( let ann = loc_ann.value; let typ = ann.typ; + for (symbol, alias) in ann.aliases.clone() { + aliases.insert(symbol, alias); + } + // union seen rigids with already found ones for (k, v) in ann.ftv { found_rigids.insert(k, v); @@ -1061,7 +1086,7 @@ pub fn can_defs_with_return<'a>( for declaration in decls.into_iter().rev() { loc_expr = Located { region: Region::zero(), - value: decl_to_let(var_store, declaration, loc_expr), + value: decl_to_let(var_store, declaration, loc_expr, output.aliases.clone()), }; } @@ -1071,12 +1096,19 @@ pub fn can_defs_with_return<'a>( } } -fn decl_to_let(var_store: &VarStore, decl: Declaration, loc_ret: Located) -> Expr { +fn decl_to_let( + var_store: &VarStore, + decl: Declaration, + loc_ret: Located, + aliases: SendMap, +) -> Expr { match decl { Declaration::Declare(def) => { - Expr::LetNonRec(Box::new(def), Box::new(loc_ret), var_store.fresh()) + Expr::LetNonRec(Box::new(def), Box::new(loc_ret), var_store.fresh(), aliases) + } + Declaration::DeclareRec(defs) => { + Expr::LetRec(defs, Box::new(loc_ret), var_store.fresh(), aliases) } - Declaration::DeclareRec(defs) => Expr::LetRec(defs, Box::new(loc_ret), var_store.fresh()), Declaration::InvalidCycle(symbols, regions) => { Expr::RuntimeError(RuntimeError::CircularDef(symbols, regions)) } diff --git a/src/can/expr.rs b/src/can/expr.rs index b570c2be98..b608e9b56b 100644 --- a/src/can/expr.rs +++ b/src/can/expr.rs @@ -16,6 +16,7 @@ use crate::operator::CalledVia; use crate::parse::ast; use crate::region::{Located, Region}; use crate::subs::{VarStore, Variable}; +use crate::types::Alias; use std::fmt::Debug; use std::i64; use std::ops::Neg; @@ -25,6 +26,7 @@ pub struct Output { pub references: References, pub tail_call: Option, pub rigids: SendMap, + pub aliases: SendMap, } #[derive(Clone, Debug, PartialEq)] @@ -56,8 +58,8 @@ pub enum Expr { }, // Let - LetRec(Vec, Box>, Variable), - LetNonRec(Box, Box>, Variable), + LetRec(Vec, Box>, Variable, Aliases), + LetNonRec(Box, Box>, Variable, Aliases), /// This is *only* for calling functions, not for tag application. /// The Tag variant contains any applied values inside it. @@ -114,6 +116,8 @@ pub enum Expr { RuntimeError(RuntimeError), } +type Aliases = SendMap; + #[derive(Clone, Debug, PartialEq)] pub struct Field { pub var: Variable, diff --git a/src/can/module.rs b/src/can/module.rs index c3fd6bc87d..2392c2bc56 100644 --- a/src/can/module.rs +++ b/src/can/module.rs @@ -11,10 +11,12 @@ use crate::module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol}; use crate::parse::ast; use crate::region::{Located, Region}; use crate::subs::{VarStore, Variable}; +use crate::types::Alias; use bumpalo::Bump; #[derive(Debug)] pub struct ModuleOutput { + pub aliases: MutMap, pub declarations: Vec, pub exposed_imports: MutMap, pub lookups: Vec<(Symbol, Variable, Region)>, @@ -99,7 +101,7 @@ pub fn canonicalize_module_defs<'a>( } let mut output = Output::default(); - let (defs, _) = canonicalize_defs( + let (defs, populated_scope) = canonicalize_defs( &mut env, &mut output.rigids, var_store, @@ -167,7 +169,14 @@ pub fn canonicalize_module_defs<'a>( references.insert(symbol); } + let mut aliases = MutMap::default(); + + for (symbol, alias) in populated_scope.aliases() { + aliases.insert(*symbol, alias.clone()); + } + Ok(ModuleOutput { + aliases, declarations, references, exposed_imports: can_exposed_imports, diff --git a/src/constrain/expr.rs b/src/constrain/expr.rs index 6087504ac7..c5d3bdcf81 100644 --- a/src/constrain/expr.rs +++ b/src/constrain/expr.rs @@ -49,6 +49,22 @@ pub fn exists(flex_vars: Vec, constraint: Constraint) -> Constraint { })) } +#[inline(always)] +pub fn exists_with_aliases( + aliases: SendMap, + flex_vars: Vec, + constraint: Constraint, +) -> Constraint { + Let(Box::new(LetConstraint { + rigid_vars: Vec::new(), + flex_vars, + def_types: SendMap::default(), + def_aliases: aliases, + defs_constraint: constraint, + ret_constraint: Constraint::True, + })) +} + pub struct Env { /// Whenever we encounter a user-defined type variable (a "rigid" var for short), /// for example `a` in the annotation `identity : a -> a`, we add it to this @@ -543,10 +559,11 @@ pub fn constrain_expr( ), ) } - LetRec(defs, loc_ret, var) => { + LetRec(defs, loc_ret, var, aliases) => { let body_con = constrain_expr(env, loc_ret.region, &loc_ret.value, expected.clone()); - exists( + exists_with_aliases( + aliases.clone(), vec![*var], And(vec![ constrain_recursive_defs(env, defs, body_con), @@ -556,10 +573,11 @@ pub fn constrain_expr( ]), ) } - LetNonRec(def, loc_ret, var) => { + LetNonRec(def, loc_ret, var, aliases) => { let body_con = constrain_expr(env, loc_ret.region, &loc_ret.value, expected.clone()); - exists( + exists_with_aliases( + aliases.clone(), vec![*var], And(vec![ constrain_def(env, def, body_con), @@ -715,7 +733,6 @@ fn constrain_def_pattern(loc_pattern: &Located, expr_type: Type) -> Pat pub fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint { let expr_var = def.expr_var; let expr_type = Type::Variable(expr_var); - let mut def_aliases: SendMap = SendMap::default(); let mut pattern_state = constrain_def_pattern(&def.loc_pattern, expr_type.clone()); @@ -824,6 +841,7 @@ pub fn rec_defs_help( mut rigid_info: Info, mut flex_info: Info, ) -> Constraint { + let mut def_aliases = SendMap::default(); for def in defs { let expr_var = def.expr_var; let expr_type = Type::Variable(expr_var); @@ -870,7 +888,11 @@ pub fn rec_defs_help( flex_info.def_types.extend(pattern_state.headers); } - Some((annotation, seen_rigids, def_aliases)) => { + Some((annotation, seen_rigids, ann_def_aliases)) => { + for (symbol, alias) in ann_def_aliases.clone() { + def_aliases.insert(symbol, alias); + } + // TODO also do this for more complex patterns if let Pattern::Identifier(symbol) = def.loc_pattern.value { pattern_state.headers.insert( @@ -945,7 +967,7 @@ pub fn rec_defs_help( rigid_vars: rigid_info.vars, flex_vars: Vec::new(), def_types: rigid_info.def_types, - def_aliases: SendMap::default(), + def_aliases, defs_constraint: True, ret_constraint: Let(Box::new(LetConstraint { rigid_vars: Vec::new(), diff --git a/src/load/mod.rs b/src/load/mod.rs index 242fcf76c6..976dd38fc3 100644 --- a/src/load/mod.rs +++ b/src/load/mod.rs @@ -10,7 +10,7 @@ use crate::parse::parser::{Fail, Parser, State}; use crate::region::{Located, Region}; use crate::solve::{self, ExposedModuleTypes, Solved, SolvedType, SubsByModule}; use crate::subs::{Subs, VarStore, Variable}; -use crate::types::{Constraint, Problem}; +use crate::types::{Alias, Constraint, Problem}; use bumpalo::Bump; use std::collections::{HashMap, HashSet}; use std::fs::read_to_string; @@ -33,6 +33,7 @@ pub struct Module { pub exposed_imports: MutMap, pub exposed_vars_by_symbol: Vec<(Symbol, Variable)>, pub references: MutSet, + pub aliases: MutMap, } pub struct LoadedModule { @@ -78,7 +79,7 @@ enum Msg { solved_types: MutMap, subs: Arc>, problems: Vec, - new_vars_by_symbol: solve::Env, + solved_env: solve::Env, }, } @@ -194,7 +195,9 @@ pub async fn load<'a>( let mut solve_listeners: MutMap> = MutMap::default(); let mut unsolved_modules: MutMap = MutMap::default(); - let mut vars_by_symbol = SendMap::default(); + + // TODO can be removed I think + let vars_by_symbol = SendMap::default(); // Parse and canonicalize the module's deps while let Some(msg) = msg_rx.recv().await { @@ -370,7 +373,7 @@ pub async fn load<'a>( solved_types, subs, problems, - new_vars_by_symbol, + .. } => { all_problems.extend(problems); @@ -779,6 +782,12 @@ fn solve_module( let exposed_vars_by_symbol: Vec<(Symbol, Variable)> = module.exposed_vars_by_symbol; + let mut aliases = SendMap::default(); + + for (symbol, alias) in module.aliases.clone() { + aliases.insert(symbol, alias); + } + // Start solving this module in the background. spawn_blocking(move || { // Now that the module is parsed, canonicalized, and constrained, @@ -788,11 +797,11 @@ fn solve_module( let env = solve::Env { vars_by_symbol, - aliases: SendMap::default(), + aliases, }; // Run the solver to populate Subs. - let (solved_subs, new_vars_by_symbol) = solve::run(&env, &mut problems, subs, &constraint); + let (solved_subs, solved_env) = solve::run(&env, &mut problems, subs, &constraint); let mut solved_types = MutMap::default(); @@ -815,7 +824,7 @@ fn solve_module( module_id: home, subs: Arc::new(solved_subs), solved_types, - new_vars_by_symbol, + solved_env, problems, }) .await @@ -918,6 +927,7 @@ fn parse_and_constrain( ident_ids, exposed_vars_by_symbol, references, + aliases, .. }) => { let constraint = constrain_module(module_id, &declarations, lookups); @@ -928,6 +938,7 @@ fn parse_and_constrain( exposed_imports, exposed_vars_by_symbol, references, + aliases, }; (module, ident_ids, constraint) diff --git a/src/mono/expr.rs b/src/mono/expr.rs index 82ed01e1fc..e095d3f351 100644 --- a/src/mono/expr.rs +++ b/src/mono/expr.rs @@ -124,7 +124,7 @@ fn from_can<'a>( Float(_, val) => Expr::Float(val), Str(string) | BlockStr(string) => Expr::Str(env.arena.alloc(string)), Var(symbol) => Expr::Load(symbol.emit()), - LetNonRec(def, ret_expr, _) => { + LetNonRec(def, ret_expr, _, _) => { let arena = env.arena; let loc_pattern = def.loc_pattern; let loc_expr = def.loc_expr; diff --git a/src/solve.rs b/src/solve.rs index cbd80439ea..6c9ac8c4c6 100644 --- a/src/solve.rs +++ b/src/solve.rs @@ -368,10 +368,16 @@ fn solve( True if let_con.rigid_vars.is_empty() => { introduce(subs, rank, pools, &let_con.flex_vars); + let mut new_env = env.clone(); + + for (symbol, alias) in let_con.def_aliases.iter() { + new_env.aliases.insert(*symbol, alias.clone()); + } + // If the return expression is guaranteed to solve, // solve the assignments themselves and move on. solve( - env, + &new_env, state, rank, pools, @@ -572,7 +578,6 @@ fn type_to_var( aliases: &SendMap, typ: &Type, ) -> Variable { - dbg!(&aliases); type_to_variable(subs, rank, pools, aliases, typ) } @@ -587,20 +592,48 @@ fn type_to_variable( Variable(var) => *var, Apply(symbol, args) => { if let Some(alias) = aliases.get(symbol) { - /* - let mut arg_vars = Vec::with_capacity(args.len()); - let mut new_aliases = ImMap::default(); - - for (arg, arg_type) in alias.args { - let arg_var = type_to_variable(subs, rank, pools, aliases, arg_type); - - arg_vars.push((arg.clone(), arg_var)); - new_aliases.insert(arg.clone(), arg_var); + if args.len() != alias.vars.len() { + panic!( + "Alias {:?} applied to incorrect number of arguments", + symbol + ); } - */ - let alias_var = type_to_variable(subs, rank, pools, aliases, &alias.typ); - let content = Content::Alias(*symbol, vec![], alias_var); + let mut actual = alias.typ.clone(); + let mut substitution = ImMap::default(); + let mut arg_vars = Vec::with_capacity(args.len()); + + for ( + tipe, + Located { + value: (lowercase, var), + .. + }, + ) in args.iter().zip(alias.vars.iter()) + { + let new_var = type_to_variable(subs, rank, pools, aliases, tipe); + substitution.insert(*var, Type::Variable(new_var)); + arg_vars.push((lowercase.clone(), new_var)); + } + + actual.substitute(&substitution); + + // We must instantiate the recursion variable, otherwise all e.g. lists will be + // unified, List Int ~ List Float + if let Type::RecursiveTagUnion(rec_var, _, _) = actual { + let new_rec_var = subs.fresh_unnamed_flex_var(); + substitution.clear(); + substitution.insert(rec_var, Type::Variable(new_rec_var)); + + actual.substitute(&substitution); + + if let Type::RecursiveTagUnion(_, tags, ext_var) = actual { + actual = Type::RecursiveTagUnion(new_rec_var, tags, ext_var); + } + } + + let alias_var = type_to_variable(subs, rank, pools, aliases, &actual); + let content = Content::Alias(*symbol, arg_vars, alias_var); register(subs, rank, pools, content) } else { diff --git a/src/uniqueness/mod.rs b/src/uniqueness/mod.rs index 4a1e0375fe..58412c62bb 100644 --- a/src/uniqueness/mod.rs +++ b/src/uniqueness/mod.rs @@ -5,7 +5,7 @@ use crate::can::ident::{Ident, Lowercase, TagName}; use crate::can::pattern::{Pattern, RecordDestruct}; use crate::collections::{ImMap, ImSet, SendMap}; use crate::constrain::builtins; -use crate::constrain::expr::{exists, Env, Info}; +use crate::constrain::expr::{exists, exists_with_aliases, Env, Info}; use crate::module::symbol::{ModuleId, Symbol}; use crate::region::{Located, Region}; use crate::subs::{VarStore, Variable}; @@ -616,7 +616,7 @@ pub fn constrain_expr( ]), ) } - LetRec(defs, loc_ret, var) => { + LetRec(defs, loc_ret, var, aliases) => { // NOTE doesn't currently unregister bound symbols // may be a problem when symbols are not globally unique let body_con = constrain_expr( @@ -628,7 +628,9 @@ pub fn constrain_expr( &loc_ret.value, expected.clone(), ); - exists( + + exists_with_aliases( + aliases.clone(), vec![*var], And(vec![ constrain_recursive_defs( @@ -645,7 +647,7 @@ pub fn constrain_expr( ]), ) } - LetNonRec(def, loc_ret, var) => { + LetNonRec(def, loc_ret, var, aliases) => { // NOTE doesn't currently unregister bound symbols // may be a problem when symbols are not globally unique let body_con = constrain_expr( @@ -658,7 +660,8 @@ pub fn constrain_expr( expected.clone(), ); - exists( + exists_with_aliases( + aliases.clone(), vec![*var], And(vec![ constrain_def( @@ -1530,6 +1533,7 @@ pub fn rec_defs_help( mut rigid_info: Info, mut flex_info: Info, ) -> Constraint { + let mut def_aliases = SendMap::default(); for def in defs { let expr_var = def.expr_var; let expr_type = Type::Variable(expr_var); @@ -1552,7 +1556,6 @@ pub fn rec_defs_help( ); // TODO see where aliases should go - let mut def_aliases = SendMap::default(); let mut new_rigids = Vec::new(); match &def.annotation { None => { @@ -1582,7 +1585,10 @@ pub fn rec_defs_help( } Some((annotation, seen_rigids, ann_def_aliases)) => { - def_aliases = ann_def_aliases.clone(); + for (symbol, alias) in ann_def_aliases.clone() { + def_aliases.insert(symbol, alias); + } + let (uniq_vars, annotation) = annotation_to_attr_type(var_store, annotation); // TODO also do this for more complex patterns @@ -1692,7 +1698,7 @@ pub fn rec_defs_help( rigid_vars: rigid_info.vars, flex_vars: Vec::new(), def_types: rigid_info.def_types, - def_aliases: SendMap::default(), + def_aliases, defs_constraint: True, ret_constraint: Let(Box::new(LetConstraint { rigid_vars: Vec::new(), diff --git a/src/uniqueness/sharing.rs b/src/uniqueness/sharing.rs index cd2403a334..04c8f03b3f 100644 --- a/src/uniqueness/sharing.rs +++ b/src/uniqueness/sharing.rs @@ -338,11 +338,11 @@ pub fn annotate_usage(expr: &Expr, usage: &mut VarUsage) { annotate_usage(&loc_elem.value, usage); } } - LetNonRec(def, loc_expr, _) => { + LetNonRec(def, loc_expr, _, _) => { annotate_usage(&def.loc_expr.value, usage); annotate_usage(&loc_expr.value, usage); } - LetRec(defs, loc_expr, _) => { + LetRec(defs, loc_expr, _, _) => { // TODO test this with a practical example. if defs.len() == 1 { // just like a letrec, but mark defined symbol as Shared From 143d06739d71ee80000a7628a4a49a6989b9dba6 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 12 Feb 2020 00:28:17 +0100 Subject: [PATCH 3/3] fix canonicalization test --- tests/test_canonicalize.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_canonicalize.rs b/tests/test_canonicalize.rs index bb9254b23d..44bdb09f62 100644 --- a/tests/test_canonicalize.rs +++ b/tests/test_canonicalize.rs @@ -222,7 +222,7 @@ mod test_canonicalize { fn get_closure(expr: &Expr, i: usize) -> roc::can::expr::Recursive { match expr { - LetRec(assignments, body, _) => { + LetRec(assignments, body, _, _) => { match &assignments.get(i).map(|def| &def.loc_expr.value) { Some(Closure(_, _, recursion, _, _)) => recursion.clone(), Some(other @ _) => { @@ -237,7 +237,7 @@ mod test_canonicalize { } } } - LetNonRec(def, body, _) => { + LetNonRec(def, body, _, _) => { if i > 0 { // recurse in the body (not the def!) get_closure(&body.value, i - 1)