diff --git a/compiler/constrain/src/module.rs b/compiler/constrain/src/module.rs index 5a85609cab..7af9047d1b 100644 --- a/compiler/constrain/src/module.rs +++ b/compiler/constrain/src/module.rs @@ -207,16 +207,7 @@ fn to_type(solved_type: &SolvedType, free_vars: &mut FreeVars, var_store: &mut V Type::Variable(var) } } - Flex(var_id) => { - if let Some(var) = free_vars.unnamed_vars.get(&var_id) { - Type::Variable(*var) - } else { - let var = var_store.fresh(); - free_vars.unnamed_vars.insert(*var_id, var); - - Type::Variable(var) - } - } + Flex(var_id) => Type::Variable(var_id_to_flex_var(*var_id, free_vars, var_store)), Wildcard => { let var = var_store.fresh(); free_vars.wildcards.push(var); @@ -274,11 +265,11 @@ fn to_type(solved_type: &SolvedType, free_vars: &mut FreeVars, var_store: &mut V } Boolean(SolvedBool::SolvedShared) => Type::Boolean(Bool::Shared), Boolean(SolvedBool::SolvedContainer(solved_cvar, solved_mvars)) => { - let cvar = var_id_to_var(*solved_cvar, free_vars, var_store); + let cvar = var_id_to_flex_var(*solved_cvar, free_vars, var_store); let mvars = solved_mvars .iter() - .map(|var_id| var_id_to_var(*var_id, free_vars, var_store)); + .map(|var_id| var_id_to_flex_var(*var_id, free_vars, var_store)); Type::Boolean(Bool::container(cvar, mvars)) } @@ -298,7 +289,11 @@ fn to_type(solved_type: &SolvedType, free_vars: &mut FreeVars, var_store: &mut V } } -fn var_id_to_var(var_id: VarId, free_vars: &mut FreeVars, var_store: &mut VarStore) -> Variable { +fn var_id_to_flex_var( + var_id: VarId, + free_vars: &mut FreeVars, + var_store: &mut VarStore, +) -> Variable { if let Some(var) = free_vars.unnamed_vars.get(&var_id) { *var } else { diff --git a/compiler/load/tests/test_uniq_load.rs b/compiler/load/tests/test_uniq_load.rs index d641bdf3c8..5a62991a2f 100644 --- a/compiler/load/tests/test_uniq_load.rs +++ b/compiler/load/tests/test_uniq_load.rs @@ -286,7 +286,26 @@ mod test_uniq_load { "w" => "Attr * (Dep1.Identity (Attr * {}))", "succeed" => "Attr * (Attr b a -> Attr * (Dep1.Identity (Attr b a)))", "yay" => "Attr * (Res.Res (Attr * {}) (Attr * err))", - "withDefault" => "Attr * (Attr (* | * | *) (Res.Res (Attr * a) (Attr * *)), Attr * a -> Attr * a)", + "withDefault" => "Attr * (Attr (* | a | b) (Res.Res (Attr a c) (Attr b *)), Attr a c -> Attr a c)", + }, + ); + }); + } + + #[test] + fn load_custom_res() { + test_async(async { + let subs_by_module = MutMap::default(); + let loaded_module = load_fixture("interface_with_deps", "Res", subs_by_module).await; + + // the inferred signature for withDefault is wrong, part of the alias in alias issue. + // "withDefault" => "Attr * (Attr * (Res.Res (Attr a b) (Attr * *)), Attr a b -> Attr a b)", + expect_types( + loaded_module, + hashmap! { + "withDefault" =>"Attr * (Attr (* | b | c) (Res (Attr b a) (Attr c err)), Attr b a -> Attr b a)", + "map" => "Attr * (Attr (* | c | d) (Res (Attr d a) (Attr c err)), Attr * (Attr d a -> Attr e b) -> Attr * (Res (Attr e b) (Attr c err)))", + "andThen" => "Attr * (Attr (* | c | d) (Res (Attr d a) (Attr c err)), Attr * (Attr d a -> Attr e (Res (Attr f b) (Attr c err))) -> Attr e (Res (Attr f b) (Attr c err)))" }, ); }); diff --git a/compiler/types/src/solved_types.rs b/compiler/types/src/solved_types.rs index 25805ddc1b..d22ad91d54 100644 --- a/compiler/types/src/solved_types.rs +++ b/compiler/types/src/solved_types.rs @@ -62,15 +62,18 @@ pub enum SolvedBool { } impl SolvedBool { - pub fn from_bool(boolean: &boolean_algebra::Bool) -> Self { + pub fn from_bool(boolean: &boolean_algebra::Bool, subs: &Subs) -> Self { use boolean_algebra::Bool; // NOTE we blindly trust that `cvar` is a root and has a FlexVar as content match boolean { Bool::Shared => SolvedBool::SolvedShared, Bool::Container(cvar, mvars) => SolvedBool::SolvedContainer( - VarId::from_var(*cvar), - mvars.iter().map(|mvar| VarId::from_var(*mvar)).collect(), + VarId::from_var(*cvar, subs), + mvars + .iter() + .map(|mvar| VarId::from_var(*mvar, subs)) + .collect(), ), } } @@ -155,7 +158,7 @@ impl SolvedType { } SolvedType::RecursiveTagUnion( - VarId::from_var(rec_var), + VarId::from_var(rec_var, solved_subs.inner()), solved_tags, Box::new(solved_ext), ) @@ -171,7 +174,7 @@ impl SolvedType { SolvedType::Alias(symbol, solved_args, Box::new(solved_type)) } - Boolean(val) => SolvedType::Boolean(SolvedBool::from_bool(&val)), + Boolean(val) => SolvedType::Boolean(SolvedBool::from_bool(&val, solved_subs.inner())), Variable(var) => Self::from_var(solved_subs.inner(), var), } } @@ -180,7 +183,7 @@ impl SolvedType { use crate::subs::Content::*; match subs.get_without_compacting(var).content { - FlexVar(_) => SolvedType::Flex(VarId::from_var(var)), + FlexVar(_) => SolvedType::Flex(VarId::from_var(var, subs)), RigidVar(name) => SolvedType::Rigid(name), Structure(flat_type) => Self::from_flat_type(subs, flat_type), Alias(symbol, args, actual_var) => { @@ -270,11 +273,15 @@ impl SolvedType { let ext = Self::from_var(subs, ext_var); - SolvedType::RecursiveTagUnion(VarId::from_var(rec_var), new_tags, Box::new(ext)) + SolvedType::RecursiveTagUnion( + VarId::from_var(rec_var, subs), + new_tags, + Box::new(ext), + ) } EmptyRecord => SolvedType::EmptyRecord, EmptyTagUnion => SolvedType::EmptyTagUnion, - Boolean(val) => SolvedType::Boolean(SolvedBool::from_bool(&val)), + Boolean(val) => SolvedType::Boolean(SolvedBool::from_bool(&val, subs)), Erroneous(problem) => SolvedType::Erroneous(problem), } } diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 9c0af2ed4d..2be37f3d01 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -199,7 +199,8 @@ impl UnifyKey for Variable { pub struct VarId(u32); impl VarId { - pub fn from_var(var: Variable) -> Self { + pub fn from_var(var: Variable, subs: &Subs) -> Self { + let var = subs.get_root_key_without_compacting(var); let Variable(n) = var; VarId(n)