mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
Merge pull request #4304 from roc-lang/i4259
Make sure type variables bound to abilities are instantiated in aliases
This commit is contained in:
commit
c1c339dbdf
8 changed files with 440 additions and 66 deletions
|
@ -553,7 +553,7 @@ fn can_annotation_help(
|
||||||
references,
|
references,
|
||||||
);
|
);
|
||||||
|
|
||||||
args.push(arg_ann);
|
args.push(Loc::at(arg.region, arg_ann));
|
||||||
}
|
}
|
||||||
|
|
||||||
match scope.lookup_alias(symbol) {
|
match scope.lookup_alias(symbol) {
|
||||||
|
@ -573,8 +573,14 @@ fn can_annotation_help(
|
||||||
|
|
||||||
let mut type_var_to_arg = Vec::new();
|
let mut type_var_to_arg = Vec::new();
|
||||||
|
|
||||||
for (_, arg_ann) in alias.type_variables.iter().zip(args) {
|
for (alias_arg, arg_ann) in alias.type_variables.iter().zip(args) {
|
||||||
type_var_to_arg.push(arg_ann);
|
type_var_to_arg.push(Loc::at(
|
||||||
|
arg_ann.region,
|
||||||
|
OptAbleType {
|
||||||
|
typ: arg_ann.value,
|
||||||
|
opt_ability: alias_arg.value.opt_bound_ability,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut lambda_set_variables =
|
let mut lambda_set_variables =
|
||||||
|
|
|
@ -829,7 +829,15 @@ fn canonicalize_opaque<'a>(
|
||||||
type_arguments: alias
|
type_arguments: alias
|
||||||
.type_variables
|
.type_variables
|
||||||
.iter()
|
.iter()
|
||||||
.map(|_| Type::Variable(var_store.fresh()))
|
.map(|alias_var| {
|
||||||
|
Loc::at(
|
||||||
|
alias_var.region,
|
||||||
|
OptAbleType {
|
||||||
|
typ: Type::Variable(var_store.fresh()),
|
||||||
|
opt_ability: alias_var.value.opt_bound_ability,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
lambda_set_variables: alias
|
lambda_set_variables: alias
|
||||||
.lambda_set_variables
|
.lambda_set_variables
|
||||||
|
|
|
@ -3,7 +3,7 @@ use roc_can::constraint::{Constraint, Constraints};
|
||||||
use roc_can::expected::Expected::{self, *};
|
use roc_can::expected::Expected::{self, *};
|
||||||
use roc_can::num::{FloatBound, FloatWidth, IntBound, IntLitWidth, NumBound, SignDemand};
|
use roc_can::num::{FloatBound, FloatWidth, IntBound, IntLitWidth, NumBound, SignDemand};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::Region;
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::num::{NumericRange, SingleQuoteBound};
|
use roc_types::num::{NumericRange, SingleQuoteBound};
|
||||||
use roc_types::subs::Variable;
|
use roc_types::subs::Variable;
|
||||||
use roc_types::types::Type::{self, *};
|
use roc_types::types::Type::{self, *};
|
||||||
|
@ -198,7 +198,11 @@ pub fn num_literal(
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn builtin_type(symbol: Symbol, args: Vec<Type>) -> Type {
|
pub fn builtin_type(symbol: Symbol, args: Vec<Type>) -> Type {
|
||||||
Type::Apply(symbol, args, Region::zero())
|
Type::Apply(
|
||||||
|
symbol,
|
||||||
|
args.into_iter().map(Loc::at_zero).collect(),
|
||||||
|
Region::zero(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
|
@ -50,7 +50,14 @@ pub struct PendingDerivesTable(
|
||||||
);
|
);
|
||||||
|
|
||||||
impl PendingDerivesTable {
|
impl PendingDerivesTable {
|
||||||
pub fn new(subs: &mut Subs, aliases: &mut Aliases, pending_derives: PendingDerives) -> Self {
|
pub fn new(
|
||||||
|
subs: &mut Subs,
|
||||||
|
aliases: &mut Aliases,
|
||||||
|
pending_derives: PendingDerives,
|
||||||
|
problems: &mut Vec<TypeError>,
|
||||||
|
abilities_store: &mut AbilitiesStore,
|
||||||
|
obligation_cache: &mut ObligationCache,
|
||||||
|
) -> Self {
|
||||||
let mut table = VecMap::with_capacity(pending_derives.len());
|
let mut table = VecMap::with_capacity(pending_derives.len());
|
||||||
|
|
||||||
for (opaque, (typ, derives)) in pending_derives.into_iter() {
|
for (opaque, (typ, derives)) in pending_derives.into_iter() {
|
||||||
|
@ -66,8 +73,16 @@ impl PendingDerivesTable {
|
||||||
let derive_key = RequestedDeriveKey { opaque, ability };
|
let derive_key = RequestedDeriveKey { opaque, ability };
|
||||||
|
|
||||||
// Neither rank nor pools should matter here.
|
// Neither rank nor pools should matter here.
|
||||||
let opaque_var =
|
let opaque_var = type_to_var(
|
||||||
type_to_var(subs, Rank::toplevel(), &mut Pools::default(), aliases, &typ);
|
subs,
|
||||||
|
Rank::toplevel(),
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
&mut Pools::default(),
|
||||||
|
aliases,
|
||||||
|
&typ,
|
||||||
|
);
|
||||||
let real_var = match subs.get_content_without_compacting(opaque_var) {
|
let real_var = match subs.get_content_without_compacting(opaque_var) {
|
||||||
Content::Alias(_, _, real_var, AliasKind::Opaque) => real_var,
|
Content::Alias(_, _, real_var, AliasKind::Opaque) => real_var,
|
||||||
_ => internal_error!("Non-opaque in derives table"),
|
_ => internal_error!("Non-opaque in derives table"),
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(clippy::too_many_arguments)]
|
||||||
|
|
||||||
use crate::ability::{
|
use crate::ability::{
|
||||||
resolve_ability_specialization, type_implementing_specialization, AbilityImplError,
|
resolve_ability_specialization, type_implementing_specialization, AbilityImplError,
|
||||||
CheckedDerives, ObligationCache, PendingDerivesTable, Resolved,
|
CheckedDerives, ObligationCache, PendingDerivesTable, Resolved,
|
||||||
|
@ -274,6 +276,9 @@ impl Aliases {
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
pools: &mut Pools,
|
||||||
|
problems: &mut Vec<TypeError>,
|
||||||
|
abilities_store: &AbilitiesStore,
|
||||||
|
obligation_cache: &mut ObligationCache,
|
||||||
arena: &bumpalo::Bump,
|
arena: &bumpalo::Bump,
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
alias_variables: AliasVariables,
|
alias_variables: AliasVariables,
|
||||||
|
@ -375,7 +380,18 @@ impl Aliases {
|
||||||
if !can_reuse_old_definition {
|
if !can_reuse_old_definition {
|
||||||
let mut typ = typ.clone();
|
let mut typ = typ.clone();
|
||||||
typ.substitute_variables(&substitutions);
|
typ.substitute_variables(&substitutions);
|
||||||
let alias_variable = type_to_variable(subs, rank, pools, arena, self, &typ, false);
|
let alias_variable = type_to_variable(
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
arena,
|
||||||
|
self,
|
||||||
|
&typ,
|
||||||
|
false,
|
||||||
|
);
|
||||||
(alias_variable, kind)
|
(alias_variable, kind)
|
||||||
} else {
|
} else {
|
||||||
if !substitutions.is_empty() {
|
if !substitutions.is_empty() {
|
||||||
|
@ -389,7 +405,18 @@ impl Aliases {
|
||||||
// assumption: an alias does not (transitively) syntactically contain itself
|
// assumption: an alias does not (transitively) syntactically contain itself
|
||||||
// (if it did it would have to be a recursive tag union, which we should have fixed up
|
// (if it did it would have to be a recursive tag union, which we should have fixed up
|
||||||
// during canonicalization)
|
// during canonicalization)
|
||||||
let alias_variable = type_to_variable(subs, rank, pools, arena, self, &t, false);
|
let alias_variable = type_to_variable(
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
arena,
|
||||||
|
self,
|
||||||
|
&t,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
match self.aliases.iter_mut().find(|(s, _, _, _)| *s == symbol) {
|
match self.aliases.iter_mut().find(|(s, _, _, _)| *s == symbol) {
|
||||||
|
@ -562,7 +589,14 @@ fn run_in_place(
|
||||||
let mut obligation_cache = ObligationCache::default();
|
let mut obligation_cache = ObligationCache::default();
|
||||||
let mut awaiting_specializations = AwaitingSpecializations::default();
|
let mut awaiting_specializations = AwaitingSpecializations::default();
|
||||||
|
|
||||||
let pending_derives = PendingDerivesTable::new(subs, aliases, pending_derives);
|
let pending_derives = PendingDerivesTable::new(
|
||||||
|
subs,
|
||||||
|
aliases,
|
||||||
|
pending_derives,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
&mut obligation_cache,
|
||||||
|
);
|
||||||
let CheckedDerives {
|
let CheckedDerives {
|
||||||
legal_derives: _,
|
legal_derives: _,
|
||||||
problems: derives_problems,
|
problems: derives_problems,
|
||||||
|
@ -687,6 +721,9 @@ fn solve(
|
||||||
constraints,
|
constraints,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
aliases,
|
aliases,
|
||||||
subs,
|
subs,
|
||||||
let_con.def_types,
|
let_con.def_types,
|
||||||
|
@ -747,6 +784,9 @@ fn solve(
|
||||||
constraints,
|
constraints,
|
||||||
next_rank,
|
next_rank,
|
||||||
pools,
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
aliases,
|
aliases,
|
||||||
subs,
|
subs,
|
||||||
let_con.def_types,
|
let_con.def_types,
|
||||||
|
@ -858,11 +898,29 @@ fn solve(
|
||||||
Eq(roc_can::constraint::Eq(type_index, expectation_index, category_index, region)) => {
|
Eq(roc_can::constraint::Eq(type_index, expectation_index, category_index, region)) => {
|
||||||
let category = &constraints.categories[category_index.index()];
|
let category = &constraints.categories[category_index.index()];
|
||||||
|
|
||||||
let actual =
|
let actual = either_type_index_to_var(
|
||||||
either_type_index_to_var(constraints, subs, rank, pools, aliases, *type_index);
|
constraints,
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
aliases,
|
||||||
|
*type_index,
|
||||||
|
);
|
||||||
|
|
||||||
let expectation = &constraints.expectations[expectation_index.index()];
|
let expectation = &constraints.expectations[expectation_index.index()];
|
||||||
let expected = type_to_var(subs, rank, pools, aliases, expectation.get_type_ref());
|
let expected = type_to_var(
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
pools,
|
||||||
|
aliases,
|
||||||
|
expectation.get_type_ref(),
|
||||||
|
);
|
||||||
|
|
||||||
match unify(&mut UEnv::new(subs), actual, expected, Mode::EQ) {
|
match unify(&mut UEnv::new(subs), actual, expected, Mode::EQ) {
|
||||||
Success {
|
Success {
|
||||||
|
@ -927,6 +985,9 @@ fn solve(
|
||||||
subs,
|
subs,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
pools,
|
||||||
|
&mut vec![], // don't report any extra errors
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
aliases,
|
aliases,
|
||||||
*source_index,
|
*source_index,
|
||||||
);
|
);
|
||||||
|
@ -962,8 +1023,16 @@ fn solve(
|
||||||
let actual = deep_copy_var_in(subs, rank, pools, var, arena);
|
let actual = deep_copy_var_in(subs, rank, pools, var, arena);
|
||||||
let expectation = &constraints.expectations[expectation_index.index()];
|
let expectation = &constraints.expectations[expectation_index.index()];
|
||||||
|
|
||||||
let expected =
|
let expected = type_to_var(
|
||||||
type_to_var(subs, rank, pools, aliases, expectation.get_type_ref());
|
subs,
|
||||||
|
rank,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
pools,
|
||||||
|
aliases,
|
||||||
|
expectation.get_type_ref(),
|
||||||
|
);
|
||||||
|
|
||||||
match unify(&mut UEnv::new(subs), actual, expected, Mode::EQ) {
|
match unify(&mut UEnv::new(subs), actual, expected, Mode::EQ) {
|
||||||
Success {
|
Success {
|
||||||
|
@ -1048,11 +1117,29 @@ fn solve(
|
||||||
| PatternPresence(type_index, expectation_index, category_index, region) => {
|
| PatternPresence(type_index, expectation_index, category_index, region) => {
|
||||||
let category = &constraints.pattern_categories[category_index.index()];
|
let category = &constraints.pattern_categories[category_index.index()];
|
||||||
|
|
||||||
let actual =
|
let actual = either_type_index_to_var(
|
||||||
either_type_index_to_var(constraints, subs, rank, pools, aliases, *type_index);
|
constraints,
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
aliases,
|
||||||
|
*type_index,
|
||||||
|
);
|
||||||
|
|
||||||
let expectation = &constraints.pattern_expectations[expectation_index.index()];
|
let expectation = &constraints.pattern_expectations[expectation_index.index()];
|
||||||
let expected = type_to_var(subs, rank, pools, aliases, expectation.get_type_ref());
|
let expected = type_to_var(
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
pools,
|
||||||
|
aliases,
|
||||||
|
expectation.get_type_ref(),
|
||||||
|
);
|
||||||
|
|
||||||
let mode = match constraint {
|
let mode = match constraint {
|
||||||
PatternPresence(..) => Mode::PRESENT,
|
PatternPresence(..) => Mode::PRESENT,
|
||||||
|
@ -1209,8 +1296,17 @@ fn solve(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IsOpenType(type_index) => {
|
IsOpenType(type_index) => {
|
||||||
let actual =
|
let actual = either_type_index_to_var(
|
||||||
either_type_index_to_var(constraints, subs, rank, pools, aliases, *type_index);
|
constraints,
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
aliases,
|
||||||
|
*type_index,
|
||||||
|
);
|
||||||
|
|
||||||
open_tag_union(subs, actual);
|
open_tag_union(subs, actual);
|
||||||
|
|
||||||
|
@ -1231,12 +1327,30 @@ fn solve(
|
||||||
let tys = &constraints.types[types.indices()];
|
let tys = &constraints.types[types.indices()];
|
||||||
let pattern_category = &constraints.pattern_categories[pattern_category.index()];
|
let pattern_category = &constraints.pattern_categories[pattern_category.index()];
|
||||||
|
|
||||||
let actual = type_to_var(subs, rank, pools, aliases, typ);
|
let actual = type_to_var(
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
pools,
|
||||||
|
aliases,
|
||||||
|
typ,
|
||||||
|
);
|
||||||
let tag_ty = Type::TagUnion(
|
let tag_ty = Type::TagUnion(
|
||||||
vec![(tag_name.clone(), tys.to_vec())],
|
vec![(tag_name.clone(), tys.to_vec())],
|
||||||
TypeExtension::Closed,
|
TypeExtension::Closed,
|
||||||
);
|
);
|
||||||
let includes = type_to_var(subs, rank, pools, aliases, &tag_ty);
|
let includes = type_to_var(
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
pools,
|
||||||
|
aliases,
|
||||||
|
&tag_ty,
|
||||||
|
);
|
||||||
|
|
||||||
match unify(&mut UEnv::new(subs), actual, includes, Mode::PRESENT) {
|
match unify(&mut UEnv::new(subs), actual, includes, Mode::PRESENT) {
|
||||||
Success {
|
Success {
|
||||||
|
@ -1337,10 +1451,28 @@ fn solve(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let real_var =
|
let real_var = either_type_index_to_var(
|
||||||
either_type_index_to_var(constraints, subs, rank, pools, aliases, real_var);
|
constraints,
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
aliases,
|
||||||
|
real_var,
|
||||||
|
);
|
||||||
|
|
||||||
let branches_var = type_to_var(subs, rank, pools, aliases, expected_type);
|
let branches_var = type_to_var(
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
pools,
|
||||||
|
aliases,
|
||||||
|
expected_type,
|
||||||
|
);
|
||||||
|
|
||||||
let real_content = subs.get_content_without_compacting(real_var);
|
let real_content = subs.get_content_without_compacting(real_var);
|
||||||
let branches_content = subs.get_content_without_compacting(branches_var);
|
let branches_content = subs.get_content_without_compacting(branches_var);
|
||||||
|
@ -1889,6 +2021,9 @@ impl LocalDefVarsVec<(Symbol, Loc<Variable>)> {
|
||||||
constraints: &Constraints,
|
constraints: &Constraints,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
pools: &mut Pools,
|
||||||
|
problems: &mut Vec<TypeError>,
|
||||||
|
abilities_store: &mut AbilitiesStore,
|
||||||
|
obligation_cache: &mut ObligationCache,
|
||||||
aliases: &mut Aliases,
|
aliases: &mut Aliases,
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
def_types_slice: roc_can::constraint::DefTypes,
|
def_types_slice: roc_can::constraint::DefTypes,
|
||||||
|
@ -1899,7 +2034,16 @@ impl LocalDefVarsVec<(Symbol, Loc<Variable>)> {
|
||||||
let mut local_def_vars = Self::with_length(types_slice.len());
|
let mut local_def_vars = Self::with_length(types_slice.len());
|
||||||
|
|
||||||
for (&(symbol, region), typ) in (loc_symbols_slice.iter()).zip(types_slice) {
|
for (&(symbol, region), typ) in (loc_symbols_slice.iter()).zip(types_slice) {
|
||||||
let var = type_to_var(subs, rank, pools, aliases, typ);
|
let var = type_to_var(
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
pools,
|
||||||
|
aliases,
|
||||||
|
typ,
|
||||||
|
);
|
||||||
|
|
||||||
local_def_vars.push((symbol, Loc { value: var, region }));
|
local_def_vars.push((symbol, Loc { value: var, region }));
|
||||||
}
|
}
|
||||||
|
@ -1930,6 +2074,9 @@ fn either_type_index_to_var(
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
pools: &mut Pools,
|
||||||
|
problems: &mut Vec<TypeError>,
|
||||||
|
abilities_store: &mut AbilitiesStore,
|
||||||
|
obligation_cache: &mut ObligationCache,
|
||||||
aliases: &mut Aliases,
|
aliases: &mut Aliases,
|
||||||
either_type_index: roc_collections::soa::EitherIndex<Type, Variable>,
|
either_type_index: roc_collections::soa::EitherIndex<Type, Variable>,
|
||||||
) -> Variable {
|
) -> Variable {
|
||||||
|
@ -1937,7 +2084,16 @@ fn either_type_index_to_var(
|
||||||
Ok(type_index) => {
|
Ok(type_index) => {
|
||||||
let typ = &constraints.types[type_index.index()];
|
let typ = &constraints.types[type_index.index()];
|
||||||
|
|
||||||
type_to_var(subs, rank, pools, aliases, typ)
|
type_to_var(
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
pools,
|
||||||
|
aliases,
|
||||||
|
typ,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Err(var_index) => {
|
Err(var_index) => {
|
||||||
// we cheat, and store the variable directly in the index
|
// we cheat, and store the variable directly in the index
|
||||||
|
@ -1949,6 +2105,9 @@ fn either_type_index_to_var(
|
||||||
pub(crate) fn type_to_var(
|
pub(crate) fn type_to_var(
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
|
problems: &mut Vec<TypeError>,
|
||||||
|
abilities_store: &mut AbilitiesStore,
|
||||||
|
obligation_cache: &mut ObligationCache,
|
||||||
pools: &mut Pools,
|
pools: &mut Pools,
|
||||||
aliases: &mut Aliases,
|
aliases: &mut Aliases,
|
||||||
typ: &Type,
|
typ: &Type,
|
||||||
|
@ -1958,7 +2117,18 @@ pub(crate) fn type_to_var(
|
||||||
} else {
|
} else {
|
||||||
let mut arena = take_scratchpad();
|
let mut arena = take_scratchpad();
|
||||||
|
|
||||||
let var = type_to_variable(subs, rank, pools, &arena, aliases, typ, false);
|
let var = type_to_variable(
|
||||||
|
subs,
|
||||||
|
rank,
|
||||||
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
&arena,
|
||||||
|
aliases,
|
||||||
|
typ,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
arena.reset();
|
arena.reset();
|
||||||
put_scratchpad(arena);
|
put_scratchpad(arena);
|
||||||
|
@ -2109,6 +2279,9 @@ fn type_to_variable<'a>(
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
pools: &mut Pools,
|
||||||
|
problems: &mut Vec<TypeError>,
|
||||||
|
abilities_store: &AbilitiesStore,
|
||||||
|
obligation_cache: &mut ObligationCache,
|
||||||
arena: &'a bumpalo::Bump,
|
arena: &'a bumpalo::Bump,
|
||||||
aliases: &mut Aliases,
|
aliases: &mut Aliases,
|
||||||
typ: &Type,
|
typ: &Type,
|
||||||
|
@ -2118,6 +2291,7 @@ fn type_to_variable<'a>(
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
|
|
||||||
let mut stack = Vec::with_capacity_in(8, arena);
|
let mut stack = Vec::with_capacity_in(8, arena);
|
||||||
|
let mut bind_to_ability = Vec::new_in(arena);
|
||||||
|
|
||||||
macro_rules! helper {
|
macro_rules! helper {
|
||||||
($typ:expr, $ambient_function_policy:expr) => {{
|
($typ:expr, $ambient_function_policy:expr) => {{
|
||||||
|
@ -2165,7 +2339,7 @@ fn type_to_variable<'a>(
|
||||||
Apply(symbol, arguments, _) => {
|
Apply(symbol, arguments, _) => {
|
||||||
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
||||||
for (target_index, var_index) in (new_arguments.indices()).zip(arguments) {
|
for (target_index, var_index) in (new_arguments.indices()).zip(arguments) {
|
||||||
let var = helper!(var_index);
|
let var = helper!(&var_index.value);
|
||||||
subs.variables[target_index] = var;
|
subs.variables[target_index] = var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2356,8 +2530,11 @@ fn type_to_variable<'a>(
|
||||||
let new_variables = VariableSubsSlice::reserve_into_subs(subs, length);
|
let new_variables = VariableSubsSlice::reserve_into_subs(subs, length);
|
||||||
|
|
||||||
for (target_index, arg_type) in (new_variables.indices()).zip(type_arguments) {
|
for (target_index, arg_type) in (new_variables.indices()).zip(type_arguments) {
|
||||||
let copy_var = helper!(arg_type);
|
let copy_var = helper!(&arg_type.value.typ);
|
||||||
subs.variables[target_index] = copy_var;
|
subs.variables[target_index] = copy_var;
|
||||||
|
if let Some(ability) = arg_type.value.opt_ability {
|
||||||
|
bind_to_ability.push((Loc::at(arg_type.region, copy_var), ability));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let it = (new_variables.indices().skip(type_arguments.len()))
|
let it = (new_variables.indices().skip(type_arguments.len()))
|
||||||
|
@ -2365,8 +2542,18 @@ fn type_to_variable<'a>(
|
||||||
for (target_index, ls) in it {
|
for (target_index, ls) in it {
|
||||||
// We MUST do this now, otherwise when linking the ambient function during
|
// We MUST do this now, otherwise when linking the ambient function during
|
||||||
// instantiation of the real var, there will be nothing to link against.
|
// instantiation of the real var, there will be nothing to link against.
|
||||||
let copy_var =
|
let copy_var = type_to_variable(
|
||||||
type_to_variable(subs, rank, pools, arena, aliases, &ls.0, true);
|
subs,
|
||||||
|
rank,
|
||||||
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
arena,
|
||||||
|
aliases,
|
||||||
|
&ls.0,
|
||||||
|
true,
|
||||||
|
);
|
||||||
subs.variables[target_index] = copy_var;
|
subs.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2381,6 +2568,9 @@ fn type_to_variable<'a>(
|
||||||
subs,
|
subs,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
arena,
|
arena,
|
||||||
*symbol,
|
*symbol,
|
||||||
alias_variables,
|
alias_variables,
|
||||||
|
@ -2488,8 +2678,18 @@ fn type_to_variable<'a>(
|
||||||
for (target_index, ls) in it {
|
for (target_index, ls) in it {
|
||||||
// We MUST do this now, otherwise when linking the ambient function during
|
// We MUST do this now, otherwise when linking the ambient function during
|
||||||
// instantiation of the real var, there will be nothing to link against.
|
// instantiation of the real var, there will be nothing to link against.
|
||||||
let copy_var =
|
let copy_var = type_to_variable(
|
||||||
type_to_variable(subs, rank, pools, arena, aliases, &ls.0, true);
|
subs,
|
||||||
|
rank,
|
||||||
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
arena,
|
||||||
|
aliases,
|
||||||
|
&ls.0,
|
||||||
|
true,
|
||||||
|
);
|
||||||
subs.variables[target_index] = copy_var;
|
subs.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2501,8 +2701,18 @@ fn type_to_variable<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
// cannot use helper! here because this variable may be involved in unification below
|
// cannot use helper! here because this variable may be involved in unification below
|
||||||
let alias_variable =
|
let alias_variable = type_to_variable(
|
||||||
type_to_variable(subs, rank, pools, arena, aliases, alias_type, false);
|
subs,
|
||||||
|
rank,
|
||||||
|
pools,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
obligation_cache,
|
||||||
|
arena,
|
||||||
|
aliases,
|
||||||
|
alias_type,
|
||||||
|
false,
|
||||||
|
);
|
||||||
// TODO(opaques): I think host-exposed aliases should always be structural
|
// TODO(opaques): I think host-exposed aliases should always be structural
|
||||||
// (when does it make sense to give a host an opaque type?)
|
// (when does it make sense to give a host an opaque type?)
|
||||||
let content = Content::Alias(
|
let content = Content::Alias(
|
||||||
|
@ -2533,6 +2743,67 @@ fn type_to_variable<'a>(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Loc { value: var, region }, ability) in bind_to_ability {
|
||||||
|
match *subs.get_content_unchecked(var) {
|
||||||
|
Content::RigidVar(a) => {
|
||||||
|
subs.set_content(var, Content::RigidAbleVar(a, ability));
|
||||||
|
}
|
||||||
|
Content::RigidAbleVar(_, ab) if ab == ability => {
|
||||||
|
// pass, already bound
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let flex_ability = subs.fresh(Descriptor {
|
||||||
|
content: Content::FlexAbleVar(None, ability),
|
||||||
|
rank,
|
||||||
|
mark: Mark::NONE,
|
||||||
|
copy: OptVariable::NONE,
|
||||||
|
});
|
||||||
|
|
||||||
|
let category = Category::OpaqueArg;
|
||||||
|
match unify(&mut UEnv::new(subs), var, flex_ability, Mode::EQ) {
|
||||||
|
Success {
|
||||||
|
vars: _,
|
||||||
|
must_implement_ability,
|
||||||
|
lambda_sets_to_specialize,
|
||||||
|
extra_metadata: _,
|
||||||
|
} => {
|
||||||
|
// No introduction needed
|
||||||
|
|
||||||
|
if !must_implement_ability.is_empty() {
|
||||||
|
let new_problems = obligation_cache.check_obligations(
|
||||||
|
subs,
|
||||||
|
abilities_store,
|
||||||
|
must_implement_ability,
|
||||||
|
AbilityImplError::BadExpr(region, category, flex_ability),
|
||||||
|
);
|
||||||
|
problems.extend(new_problems);
|
||||||
|
}
|
||||||
|
debug_assert!(lambda_sets_to_specialize
|
||||||
|
.drain()
|
||||||
|
.all(|(_, vals)| vals.is_empty()));
|
||||||
|
}
|
||||||
|
Failure(_vars, actual_type, expected_type, _bad_impls) => {
|
||||||
|
// No introduction needed
|
||||||
|
|
||||||
|
let problem = TypeError::BadExpr(
|
||||||
|
region,
|
||||||
|
category,
|
||||||
|
actual_type,
|
||||||
|
Expected::NoExpectation(expected_type),
|
||||||
|
);
|
||||||
|
|
||||||
|
problems.push(problem);
|
||||||
|
}
|
||||||
|
BadType(_vars, problem) => {
|
||||||
|
// No introduction needed
|
||||||
|
|
||||||
|
problems.push(TypeError::BadType(problem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7991,4 +7991,22 @@ mod solve_expr {
|
||||||
"Bool",
|
"Bool",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn expand_able_variables_in_type_alias() {
|
||||||
|
infer_queries!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
F a : a | a has Hash
|
||||||
|
|
||||||
|
main : F a -> F a
|
||||||
|
#^^^^{-1}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
@"main : a -[[main(0)]]-> a | a has Hash"
|
||||||
|
print_only_under_alias: true
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,7 +209,7 @@ impl LambdaSet {
|
||||||
#[derive(PartialEq, Eq, Clone)]
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
pub struct AliasCommon {
|
pub struct AliasCommon {
|
||||||
pub symbol: Symbol,
|
pub symbol: Symbol,
|
||||||
pub type_arguments: Vec<Type>,
|
pub type_arguments: Vec<Loc<OptAbleType>>,
|
||||||
pub lambda_set_variables: Vec<LambdaSet>,
|
pub lambda_set_variables: Vec<LambdaSet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ pub enum Type {
|
||||||
},
|
},
|
||||||
RecursiveTagUnion(Variable, Vec<(TagName, Vec<Type>)>, TypeExtension),
|
RecursiveTagUnion(Variable, Vec<(TagName, Vec<Type>)>, TypeExtension),
|
||||||
/// Applying a type to some arguments (e.g. Dict.Dict String Int)
|
/// Applying a type to some arguments (e.g. Dict.Dict String Int)
|
||||||
Apply(Symbol, Vec<Type>, Region),
|
Apply(Symbol, Vec<Loc<Type>>, Region),
|
||||||
Variable(Variable),
|
Variable(Variable),
|
||||||
RangedNumber(NumericRange),
|
RangedNumber(NumericRange),
|
||||||
/// A type error, which will code gen to a runtime error
|
/// A type error, which will code gen to a runtime error
|
||||||
|
@ -793,7 +793,7 @@ impl Type {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
for value in type_arguments.iter_mut() {
|
for value in type_arguments.iter_mut() {
|
||||||
stack.push(value);
|
stack.push(&mut value.value.typ);
|
||||||
}
|
}
|
||||||
|
|
||||||
for lambda_set in lambda_set_variables.iter_mut() {
|
for lambda_set in lambda_set_variables.iter_mut() {
|
||||||
|
@ -833,7 +833,7 @@ impl Type {
|
||||||
stack.push(actual_type);
|
stack.push(actual_type);
|
||||||
}
|
}
|
||||||
Apply(_, args, _) => {
|
Apply(_, args, _) => {
|
||||||
stack.extend(args);
|
stack.extend(args.iter_mut().map(|t| &mut t.value));
|
||||||
}
|
}
|
||||||
RangedNumber(_) => {}
|
RangedNumber(_) => {}
|
||||||
UnspecializedLambdaSet {
|
UnspecializedLambdaSet {
|
||||||
|
@ -915,7 +915,7 @@ impl Type {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
for value in type_arguments.iter_mut() {
|
for value in type_arguments.iter_mut() {
|
||||||
stack.push(value);
|
stack.push(&mut value.value.typ);
|
||||||
}
|
}
|
||||||
|
|
||||||
for lambda_set in lambda_set_variables.iter_mut() {
|
for lambda_set in lambda_set_variables.iter_mut() {
|
||||||
|
@ -954,7 +954,7 @@ impl Type {
|
||||||
stack.push(actual_type);
|
stack.push(actual_type);
|
||||||
}
|
}
|
||||||
Apply(_, args, _) => {
|
Apply(_, args, _) => {
|
||||||
stack.extend(args);
|
stack.extend(args.iter_mut().map(|t| &mut t.value));
|
||||||
}
|
}
|
||||||
RangedNumber(_) => {}
|
RangedNumber(_) => {}
|
||||||
UnspecializedLambdaSet {
|
UnspecializedLambdaSet {
|
||||||
|
@ -1021,7 +1021,9 @@ impl Type {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
for ta in type_arguments {
|
for ta in type_arguments {
|
||||||
ta.substitute_alias(rep_symbol, rep_args, actual)?;
|
ta.value
|
||||||
|
.typ
|
||||||
|
.substitute_alias(rep_symbol, rep_args, actual)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1042,13 +1044,16 @@ impl Type {
|
||||||
} => actual_type.substitute_alias(rep_symbol, rep_args, actual),
|
} => actual_type.substitute_alias(rep_symbol, rep_args, actual),
|
||||||
Apply(symbol, args, region) if *symbol == rep_symbol => {
|
Apply(symbol, args, region) if *symbol == rep_symbol => {
|
||||||
if args.len() == rep_args.len()
|
if args.len() == rep_args.len()
|
||||||
&& args.iter().zip(rep_args.iter()).all(|(t1, t2)| t1 == t2)
|
&& args
|
||||||
|
.iter()
|
||||||
|
.zip(rep_args.iter())
|
||||||
|
.all(|(t1, t2)| &t1.value == t2)
|
||||||
{
|
{
|
||||||
*self = actual.clone();
|
*self = actual.clone();
|
||||||
|
|
||||||
if let Apply(_, args, _) = self {
|
if let Apply(_, args, _) = self {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
arg.substitute_alias(rep_symbol, rep_args, actual)?;
|
arg.value.substitute_alias(rep_symbol, rep_args, actual)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -1057,7 +1062,7 @@ impl Type {
|
||||||
}
|
}
|
||||||
Apply(_, args, _) => {
|
Apply(_, args, _) => {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
arg.substitute_alias(rep_symbol, rep_args, actual)?;
|
arg.value.substitute_alias(rep_symbol, rep_args, actual)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1103,7 +1108,9 @@ impl Type {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
symbol == &rep_symbol
|
symbol == &rep_symbol
|
||||||
|| type_arguments.iter().any(|v| v.contains_symbol(rep_symbol))
|
|| type_arguments
|
||||||
|
.iter()
|
||||||
|
.any(|v| v.value.typ.contains_symbol(rep_symbol))
|
||||||
|| lambda_set_variables
|
|| lambda_set_variables
|
||||||
.iter()
|
.iter()
|
||||||
.any(|v| v.0.contains_symbol(rep_symbol))
|
.any(|v| v.0.contains_symbol(rep_symbol))
|
||||||
|
@ -1117,7 +1124,7 @@ impl Type {
|
||||||
name == &rep_symbol || actual.contains_symbol(rep_symbol)
|
name == &rep_symbol || actual.contains_symbol(rep_symbol)
|
||||||
}
|
}
|
||||||
Apply(symbol, _, _) if *symbol == rep_symbol => true,
|
Apply(symbol, _, _) if *symbol == rep_symbol => true,
|
||||||
Apply(_, args, _) => args.iter().any(|arg| arg.contains_symbol(rep_symbol)),
|
Apply(_, args, _) => args.iter().any(|arg| arg.value.contains_symbol(rep_symbol)),
|
||||||
RangedNumber(_) => false,
|
RangedNumber(_) => false,
|
||||||
UnspecializedLambdaSet {
|
UnspecializedLambdaSet {
|
||||||
unspecialized: Uls(_, sym, _),
|
unspecialized: Uls(_, sym, _),
|
||||||
|
@ -1174,7 +1181,9 @@ impl Type {
|
||||||
..
|
..
|
||||||
} => actual_type.contains_variable(rep_variable),
|
} => actual_type.contains_variable(rep_variable),
|
||||||
HostExposedAlias { actual, .. } => actual.contains_variable(rep_variable),
|
HostExposedAlias { actual, .. } => actual.contains_variable(rep_variable),
|
||||||
Apply(_, args, _) => args.iter().any(|arg| arg.contains_variable(rep_variable)),
|
Apply(_, args, _) => args
|
||||||
|
.iter()
|
||||||
|
.any(|arg| arg.value.contains_variable(rep_variable)),
|
||||||
RangedNumber(_) => false,
|
RangedNumber(_) => false,
|
||||||
EmptyRec | EmptyTagUnion | Erroneous(_) => false,
|
EmptyRec | EmptyTagUnion | Erroneous(_) => false,
|
||||||
}
|
}
|
||||||
|
@ -1259,7 +1268,12 @@ impl Type {
|
||||||
.iter()
|
.iter()
|
||||||
.all(|lambda_set| matches!(lambda_set.0, Type::Variable(..))));
|
.all(|lambda_set| matches!(lambda_set.0, Type::Variable(..))));
|
||||||
type_arguments.iter_mut().for_each(|t| {
|
type_arguments.iter_mut().for_each(|t| {
|
||||||
t.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables)
|
t.value.typ.instantiate_aliases(
|
||||||
|
region,
|
||||||
|
aliases,
|
||||||
|
var_store,
|
||||||
|
new_lambda_set_variables,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
HostExposedAlias {
|
HostExposedAlias {
|
||||||
|
@ -1316,8 +1330,14 @@ impl Type {
|
||||||
if false {
|
if false {
|
||||||
let mut type_var_to_arg = Vec::new();
|
let mut type_var_to_arg = Vec::new();
|
||||||
|
|
||||||
for (_, arg_ann) in alias.type_variables.iter().zip(args) {
|
for (alias_var, arg_ann) in alias.type_variables.iter().zip(args) {
|
||||||
type_var_to_arg.push(arg_ann.clone());
|
type_var_to_arg.push(Loc::at(
|
||||||
|
arg_ann.region,
|
||||||
|
OptAbleType {
|
||||||
|
typ: arg_ann.value.clone(),
|
||||||
|
opt_ability: alias_var.value.opt_bound_ability,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut lambda_set_variables =
|
let mut lambda_set_variables =
|
||||||
|
@ -1370,17 +1390,17 @@ impl Type {
|
||||||
) in alias.type_variables.iter().zip(args.iter())
|
) in alias.type_variables.iter().zip(args.iter())
|
||||||
{
|
{
|
||||||
let mut filler = filler.clone();
|
let mut filler = filler.clone();
|
||||||
filler.instantiate_aliases(
|
filler.value.instantiate_aliases(
|
||||||
region,
|
region,
|
||||||
aliases,
|
aliases,
|
||||||
var_store,
|
var_store,
|
||||||
new_lambda_set_variables,
|
new_lambda_set_variables,
|
||||||
);
|
);
|
||||||
named_args.push(OptAbleType {
|
named_args.push(OptAbleType {
|
||||||
typ: filler.clone(),
|
typ: filler.value.clone(),
|
||||||
opt_ability: *opt_bound_ability,
|
opt_ability: *opt_bound_ability,
|
||||||
});
|
});
|
||||||
substitution.insert(*placeholder, filler);
|
substitution.insert(*placeholder, filler.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure hidden variables are freshly instantiated
|
// make sure hidden variables are freshly instantiated
|
||||||
|
@ -1435,7 +1455,12 @@ impl Type {
|
||||||
} else {
|
} else {
|
||||||
// one of the special-cased Apply types.
|
// one of the special-cased Apply types.
|
||||||
for x in args {
|
for x in args {
|
||||||
x.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
|
x.value.instantiate_aliases(
|
||||||
|
region,
|
||||||
|
aliases,
|
||||||
|
var_store,
|
||||||
|
new_lambda_set_variables,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1552,7 +1577,7 @@ fn symbols_help(initial: &Type) -> Vec<Symbol> {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
output.push(*symbol);
|
output.push(*symbol);
|
||||||
stack.extend(type_arguments);
|
stack.extend(type_arguments.iter().map(|ta| &ta.value.typ));
|
||||||
}
|
}
|
||||||
Alias {
|
Alias {
|
||||||
symbol: alias_symbol,
|
symbol: alias_symbol,
|
||||||
|
@ -1572,7 +1597,7 @@ fn symbols_help(initial: &Type) -> Vec<Symbol> {
|
||||||
}
|
}
|
||||||
Apply(symbol, args, _) => {
|
Apply(symbol, args, _) => {
|
||||||
output.push(*symbol);
|
output.push(*symbol);
|
||||||
stack.extend(args);
|
stack.extend(args.iter().map(|t| &t.value));
|
||||||
}
|
}
|
||||||
Erroneous(Problem::CyclicAlias(alias, _, _)) => {
|
Erroneous(Problem::CyclicAlias(alias, _, _)) => {
|
||||||
output.push(*alias);
|
output.push(*alias);
|
||||||
|
@ -1679,7 +1704,7 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
for arg in type_arguments {
|
for arg in type_arguments {
|
||||||
variables_help(arg, accum);
|
variables_help(&arg.value.typ, accum);
|
||||||
}
|
}
|
||||||
|
|
||||||
for lambda_set in lambda_set_variables {
|
for lambda_set in lambda_set_variables {
|
||||||
|
@ -1709,7 +1734,7 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
|
||||||
RangedNumber(_) => {}
|
RangedNumber(_) => {}
|
||||||
Apply(_, args, _) => {
|
Apply(_, args, _) => {
|
||||||
for x in args {
|
for x in args {
|
||||||
variables_help(x, accum);
|
variables_help(&x.value, accum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1823,7 +1848,7 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
for arg in type_arguments {
|
for arg in type_arguments {
|
||||||
variables_help_detailed(arg, accum);
|
variables_help_detailed(&arg.value.typ, accum);
|
||||||
}
|
}
|
||||||
|
|
||||||
for lambda_set in lambda_set_variables {
|
for lambda_set in lambda_set_variables {
|
||||||
|
@ -1857,7 +1882,7 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
|
||||||
RangedNumber(_) => {}
|
RangedNumber(_) => {}
|
||||||
Apply(_, args, _) => {
|
Apply(_, args, _) => {
|
||||||
for x in args {
|
for x in args {
|
||||||
variables_help_detailed(x, accum);
|
variables_help_detailed(&x.value, accum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2928,7 +2953,7 @@ fn instantiate_lambda_sets_as_unspecialized(
|
||||||
debug_assert!(matches!(lambda_set.0, Type::Variable(_)));
|
debug_assert!(matches!(lambda_set.0, Type::Variable(_)));
|
||||||
lambda_set.0 = new_uls();
|
lambda_set.0 = new_uls();
|
||||||
}
|
}
|
||||||
stack.extend(type_arguments.iter_mut().rev());
|
stack.extend(type_arguments.iter_mut().rev().map(|ta| &mut ta.value.typ));
|
||||||
}
|
}
|
||||||
Type::Alias {
|
Type::Alias {
|
||||||
symbol: _,
|
symbol: _,
|
||||||
|
@ -2959,7 +2984,7 @@ fn instantiate_lambda_sets_as_unspecialized(
|
||||||
stack.extend(type_arguments.iter_mut().rev());
|
stack.extend(type_arguments.iter_mut().rev());
|
||||||
}
|
}
|
||||||
Type::Apply(_sym, args, _region) => {
|
Type::Apply(_sym, args, _region) => {
|
||||||
stack.extend(args.iter_mut().rev());
|
stack.extend(args.iter_mut().rev().map(|t| &mut t.value));
|
||||||
}
|
}
|
||||||
Type::Variable(_) => {}
|
Type::Variable(_) => {}
|
||||||
Type::RangedNumber(_) => {}
|
Type::RangedNumber(_) => {}
|
||||||
|
|
|
@ -11430,4 +11430,31 @@ All branches in an `if` must have the same type!
|
||||||
Bool.false
|
Bool.false
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_report!(
|
||||||
|
expand_ability_from_type_alias_mismatch,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [f] to "./platform"
|
||||||
|
|
||||||
|
F a : a | a has Hash
|
||||||
|
|
||||||
|
f : F ({} -> {})
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
@r###"
|
||||||
|
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
|
This expression has a type that does not implement the abilities it's expected to:
|
||||||
|
|
||||||
|
5│ f : F ({} -> {})
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
I can't generate an implementation of the `Hash` ability for
|
||||||
|
|
||||||
|
{} -> {}
|
||||||
|
|
||||||
|
Note: `Hash` cannot be generated for functions.
|
||||||
|
"###
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue