Merge branch 'main' into specialize-exprs

This commit is contained in:
Agus Zubiaga 2024-11-23 01:48:51 -03:00
commit 2e96aca0fd
No known key found for this signature in database
797 changed files with 17394 additions and 12632 deletions

View file

@ -27,6 +27,8 @@ roc_unify = { path = "../unify" }
arrayvec.workspace = true
bumpalo.workspace = true
soa.workspace = true
[dev-dependencies]
roc_builtins = { path = "../builtins" }
roc_derive = { path = "../derive", features = ["debug-derived-symbols"] }

View file

@ -612,14 +612,6 @@ trait DerivableVisitor {
})
}
#[inline(always)]
fn visit_empty_tuple(var: Variable) -> Result<(), NotDerivable> {
Err(NotDerivable {
var,
context: NotDerivableContext::NoContext,
})
}
#[inline(always)]
fn visit_empty_tag_union(var: Variable) -> Result<(), NotDerivable> {
Err(NotDerivable {
@ -726,11 +718,12 @@ trait DerivableVisitor {
push_var_slice!(vars)
}
}
Func(args, _clos, ret) => {
Func(args, _clos, ret, fx) => {
let descend = Self::visit_func(var)?;
if descend.0 {
push_var_slice!(args);
stack.push(ret);
stack.push(fx);
}
}
Record(fields, ext) => {
@ -786,8 +779,13 @@ trait DerivableVisitor {
}
}
EmptyRecord => Self::visit_empty_record(var)?,
EmptyTuple => Self::visit_empty_tuple(var)?,
EmptyTagUnion => Self::visit_empty_tag_union(var)?,
EffectfulFunc => {
return Err(NotDerivable {
var,
context: NotDerivableContext::NoContext,
})
}
},
Alias(
Symbol::NUM_NUM | Symbol::NUM_INTEGER,
@ -838,6 +836,12 @@ trait DerivableVisitor {
context: NotDerivableContext::NoContext,
})
}
Pure | Effectful => {
return Err(NotDerivable {
var,
context: NotDerivableContext::NoContext,
})
}
Error => {
return Err(NotDerivable {
var,

View file

@ -1,5 +1,5 @@
use roc_can::abilities::AbilitiesStore;
use roc_collections::{soa::Index, MutMap};
use roc_collections::{soa::slice_extend_new, MutMap};
use roc_error_macros::internal_error;
use roc_module::symbol::Symbol;
use roc_solve_problem::TypeError;
@ -7,6 +7,7 @@ use roc_types::{
subs::{AliasVariables, Content, FlatType, Rank, Subs, SubsSlice, TagExt, UnionTags, Variable},
types::{Alias, AliasKind, OptAbleVar, Type, TypeTag, Types},
};
use soa::Index;
use crate::to_var::type_to_var_help;
use crate::{ability::ObligationCache, env::InferenceEnv};
@ -131,7 +132,7 @@ impl Aliases {
let ok_slice = SubsSlice::new(alias_variables.variables_start, 1);
let variable_slices =
SubsSlice::extend_new(&mut env.subs.variable_slices, [err_slice, ok_slice]);
slice_extend_new(&mut env.subs.variable_slices, [err_slice, ok_slice]);
let union_tags = UnionTags::from_slices(tag_names_slice, variable_slices);
let ext_var = TagExt::Any(Variable::EMPTY_TAG_UNION);

View file

@ -1,11 +1,12 @@
use std::ops::ControlFlow;
use bumpalo::Bump;
use roc_collections::soa::slice_extend_new;
use roc_error_macros::internal_error;
use roc_types::{
subs::{
self, AliasVariables, Content, Descriptor, FlatType, GetSubsSlice, Mark, OptVariable, Rank,
RecordFields, Subs, SubsSlice, TagExt, TupleElems, UnionLabels, Variable,
RecordFields, Subs, TagExt, TupleElems, UnionLabels, Variable,
},
types::{RecordField, Uls},
};
@ -121,7 +122,7 @@ fn deep_copy_var_help(
macro_rules! copy_sequence {
($length:expr, $variables:expr) => {{
let new_variables = SubsSlice::reserve_into_subs(subs, $length as _);
let new_variables = subs.reserve_into_vars($length as _);
for (target_index, var_index) in (new_variables.indices()).zip($variables) {
let var = subs[var_index];
let copy_var = work!(var);
@ -134,7 +135,7 @@ fn deep_copy_var_help(
macro_rules! copy_union {
($tags:expr) => {{
let new_variable_slices = SubsSlice::reserve_variable_slices(subs, $tags.len());
let new_variable_slices = subs.reserve_variable_slices($tags.len());
let it = (new_variable_slices.indices()).zip($tags.variables());
for (target_index, index) in it {
@ -176,16 +177,17 @@ fn deep_copy_var_help(
Apply(symbol, new_arguments)
}
Func(arguments, closure_var, ret_var) => {
Func(arguments, closure_var, ret_var, fx_var) => {
let new_ret_var = work!(ret_var);
let new_closure_var = work!(closure_var);
let new_fx_var = work!(fx_var);
let new_arguments = copy_sequence!(arguments.len(), arguments);
Func(new_arguments, new_closure_var, new_ret_var)
Func(new_arguments, new_closure_var, new_ret_var, new_fx_var)
}
same @ EmptyRecord | same @ EmptyTuple | same @ EmptyTagUnion => same,
same @ (EmptyRecord | EmptyTagUnion | EffectfulFunc) => same,
Record(fields, ext_var) => {
let record_fields = {
@ -201,7 +203,7 @@ fn deep_copy_var_help(
let new_field_types_start = if has_rigid_optional_field {
let field_types = field_types.to_vec();
let slice = SubsSlice::extend_new(
let slice = slice_extend_new(
&mut subs.record_fields,
field_types.into_iter().map(|f| match f {
RecordField::RigidOptional(())
@ -212,7 +214,7 @@ fn deep_copy_var_help(
| RecordField::Optional(_) => f,
}),
);
slice.start
slice.start()
} else {
fields.field_types_start
};
@ -220,7 +222,7 @@ fn deep_copy_var_help(
RecordFields {
length: fields.length,
field_names_start: fields.field_names_start,
variables_start: new_variables.start,
variables_start: new_variables.start(),
field_types_start: new_field_types_start,
}
};
@ -234,7 +236,7 @@ fn deep_copy_var_help(
TupleElems {
length: elems.length,
variables_start: new_variables.start,
variables_start: new_variables.start(),
elem_index_start: elems.elem_index_start,
}
};
@ -262,7 +264,7 @@ fn deep_copy_var_help(
subs.set_content_unchecked(copy, Structure(new_flat_type));
}
FlexVar(_) | FlexAbleVar(_, _) | Error | ErasedLambda => {
FlexVar(_) | FlexAbleVar(_, _) | Error | ErasedLambda | Pure | Effectful => {
subs.set_content_unchecked(copy, content);
}
@ -291,7 +293,7 @@ fn deep_copy_var_help(
copy_sequence!(arguments.all_variables_len, arguments.all_variables());
let new_arguments = AliasVariables {
variables_start: new_variables.start,
variables_start: new_variables.start(),
..arguments
};
@ -311,7 +313,7 @@ fn deep_copy_var_help(
let new_solved = copy_union!(solved);
let new_rec_var = recursion_var.map(|v| work!(v));
let new_unspecialized = SubsSlice::reserve_uls_slice(subs, unspecialized.len());
let new_unspecialized = subs.reserve_uls_slice(unspecialized.len());
for (new_uls_index, uls_index) in
(new_unspecialized.into_iter()).zip(unspecialized.into_iter())

View file

@ -186,7 +186,9 @@ pub fn exposed_types_storage_subs(
.as_inner()
.get_content_without_compacting(imported_lset_ambient_function_var)
{
Content::Structure(FlatType::Func(_, lambda_set_var, _)) => *lambda_set_var,
Content::Structure(FlatType::Func(_, lambda_set_var, _, _)) => {
*lambda_set_var
}
content => internal_error!(
"ambient lambda set function import is not a function, found: {:?}",
roc_types::subs::SubsFmtContent(content, storage_subs.as_inner())

View file

@ -14,7 +14,9 @@ use crate::Aliases;
use bumpalo::Bump;
use roc_can::abilities::{AbilitiesStore, MemberSpecializationInfo};
use roc_can::constraint::Constraint::{self, *};
use roc_can::constraint::{Cycle, LetConstraint, OpportunisticResolve};
use roc_can::constraint::{
Cycle, FxCallConstraint, FxSuffixConstraint, FxSuffixKind, LetConstraint, OpportunisticResolve,
};
use roc_can::expected::{Expected, PExpected};
use roc_can::module::ModuleParams;
use roc_collections::VecMap;
@ -22,9 +24,10 @@ use roc_debug_flags::dbg_do;
#[cfg(debug_assertions)]
use roc_debug_flags::ROC_VERIFY_RIGID_LET_GENERALIZED;
use roc_error_macros::internal_error;
use roc_module::ident::IdentSuffix;
use roc_module::symbol::{ModuleId, Symbol};
use roc_problem::can::CycleEntry;
use roc_region::all::Loc;
use roc_region::all::{Loc, Region};
use roc_solve_problem::TypeError;
use roc_solve_schema::UnificationMode;
use roc_types::subs::{
@ -448,6 +451,14 @@ fn solve(
);
new_scope.insert_symbol_var_if_vacant(*symbol, loc_var.value);
solve_suffix_fx(
env,
problems,
FxSuffixKind::Let(*symbol),
loc_var.value,
&loc_var.region,
);
}
// Note that this vars_by_symbol is the one returned by the
@ -777,6 +788,122 @@ fn solve(
}
}
}
FxCall(index) => {
let FxCallConstraint {
call_fx_var,
call_kind,
call_region,
expectation,
} = &env.constraints.fx_call_constraints[index.index()];
let actual_desc = env.subs.get(*call_fx_var);
match (actual_desc.content, expectation) {
(Content::Pure, _) | (Content::FlexVar(_), _) | (Content::Error, _) => state,
(Content::Effectful, None) => {
let problem = TypeError::FxInTopLevel(*call_region, *call_kind);
problems.push(problem);
state
}
(Content::Effectful, Some(expectation)) => {
match env.subs.get_content_without_compacting(expectation.fx_var) {
Content::Effectful | Content::Error => state,
Content::FlexVar(_) => {
env.subs
.union(expectation.fx_var, *call_fx_var, actual_desc);
state
}
Content::Pure => {
let problem = TypeError::FxInPureFunction(
*call_region,
*call_kind,
expectation.ann_region,
);
problems.push(problem);
state
}
expected_content => {
internal_error!(
"CallFx: unexpected content: {:?}",
expected_content
)
}
}
}
actual_content => {
internal_error!("CallFx: unexpected content: {:?}", actual_content)
}
}
}
FxSuffix(constraint_index) => {
let FxSuffixConstraint {
type_index,
kind,
region,
} = &env.constraints.fx_suffix_constraints[constraint_index.index()];
let actual = either_type_index_to_var(
env,
rank,
problems,
abilities_store,
obligation_cache,
&mut can_types,
aliases,
*type_index,
);
solve_suffix_fx(env, problems, *kind, actual, region);
state
}
ExpectEffectful(variable, reason, region) => {
let content = env.subs.get_content_without_compacting(*variable);
match content {
Content::Pure | Content::FlexVar(_) => {
let problem = TypeError::ExpectedEffectful(*region, *reason);
problems.push(problem);
state
}
Content::Effectful | Content::Error => state,
Content::RigidVar(_)
| Content::FlexAbleVar(_, _)
| Content::RigidAbleVar(_, _)
| Content::RecursionVar { .. }
| Content::LambdaSet(_)
| Content::ErasedLambda
| Content::Structure(_)
| Content::Alias(_, _, _, _)
| Content::RangedNumber(_) => {
internal_error!("ExpectEffectful: unexpected content: {:?}", content)
}
}
}
FlexToPure(variable) => {
let content = env.subs.get_content_without_compacting(*variable);
match content {
Content::FlexVar(_) => {
let desc = env.subs.get(Variable::PURE);
env.subs.union(*variable, Variable::PURE, desc);
state
}
Content::Pure | Content::Effectful | Content::Error => state,
Content::RigidVar(_)
| Content::FlexAbleVar(_, _)
| Content::RigidAbleVar(_, _)
| Content::RecursionVar { .. }
| Content::LambdaSet(_)
| Content::ErasedLambda
| Content::Structure(_)
| Content::Alias(_, _, _, _)
| Content::RangedNumber(_) => {
internal_error!("FlexToPure: unexpected content: {:?}", content)
}
}
}
Let(index, pool_slice) => {
let let_con = &env.constraints.let_constraints[index.index()];
@ -1403,7 +1530,7 @@ fn solve(
}
ImportParams(opt_provided, module_id, region) => {
match (module_params_vars.get(module_id), opt_provided) {
(Some(expected), Some(provided)) => {
(Some(expected_og), Some(provided)) => {
let actual = either_type_index_to_var(
env,
rank,
@ -1415,10 +1542,18 @@ fn solve(
*provided,
);
let expected = {
// Similar to Lookup, we need to unify on a copy of the module params variable
// Otherwise, this import might make it less general than it really is
let mut solve_env = env.as_solve_env();
let solve_env = &mut solve_env;
deep_copy_var_in(solve_env, rank, *expected_og, solve_env.arena)
};
match unify(
&mut env.uenv(),
actual,
*expected,
expected,
UnificationMode::EQ,
Polarity::OF_VALUE,
) {
@ -1487,6 +1622,52 @@ fn solve(
state
}
fn solve_suffix_fx(
env: &mut InferenceEnv<'_>,
problems: &mut Vec<TypeError>,
kind: FxSuffixKind,
variable: Variable,
region: &Region,
) {
match kind.suffix() {
IdentSuffix::None => {
if let Content::Structure(FlatType::Func(_, _, _, fx)) =
env.subs.get_content_without_compacting(variable)
{
let fx = *fx;
match env.subs.get_content_without_compacting(fx) {
Content::Effectful => {
problems.push(TypeError::UnsuffixedEffectfulFunction(*region, kind));
}
Content::FlexVar(_) => {
env.subs.set_content(fx, Content::Pure);
}
_ => {}
}
}
}
IdentSuffix::Bang => match env.subs.get_content_without_compacting(variable) {
Content::Structure(FlatType::Func(_, _, _, fx)) => {
let fx = *fx;
match env.subs.get_content_without_compacting(fx) {
Content::Pure => {
problems.push(TypeError::SuffixedPureFunction(*region, kind));
}
Content::FlexVar(_) => {
env.subs.set_content(fx, Content::Effectful);
}
_ => {}
}
}
Content::FlexVar(_) => {
env.subs
.set_content(variable, Content::Structure(FlatType::EffectfulFunc));
}
_ => {}
},
}
}
fn chase_alias_content(subs: &Subs, mut var: Variable) -> (Variable, &Content) {
loop {
match subs.get_content_without_compacting(var) {
@ -2158,7 +2339,7 @@ fn adjust_rank_content(
rank
}
Func(arg_vars, closure_var, ret_var) => {
Func(arg_vars, closure_var, ret_var, _fx_var) => {
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ret_var);
// TODO investigate further.
@ -2184,7 +2365,7 @@ fn adjust_rank_content(
rank
}
EmptyRecord | EmptyTuple => {
EmptyRecord => {
// from elm-compiler: THEORY: an empty record never needs to get generalized
//
// But for us, that theory does not hold, because there might be type variables hidden
@ -2199,6 +2380,8 @@ fn adjust_rank_content(
// THEORY: an empty tag never needs to get generalized
EmptyTagUnion => Rank::toplevel(),
EffectfulFunc => Rank::toplevel(),
Record(fields, ext_var) => {
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
@ -2421,6 +2604,8 @@ fn adjust_rank_content(
ErasedLambda => group_rank,
Pure | Effectful => group_rank,
RangedNumber(_) => group_rank,
}
}

View file

@ -3,7 +3,7 @@
use std::collections::VecDeque;
use roc_can::abilities::{AbilitiesStore, ImplKey};
use roc_collections::{VecMap, VecSet};
use roc_collections::{soa::slice_extend_new, VecMap, VecSet};
use roc_debug_flags::dbg_do;
#[cfg(debug_assertions)]
use roc_debug_flags::ROC_TRACE_COMPACTION;
@ -14,7 +14,7 @@ use roc_solve_schema::UnificationMode;
use roc_types::{
subs::{
get_member_lambda_sets_at_region, Content, Descriptor, GetSubsSlice, LambdaSet, Mark,
OptVariable, Rank, Subs, SubsSlice, UlsOfVar, Variable,
OptVariable, Rank, Subs, UlsOfVar, Variable,
},
types::{AliasKind, MemberImpl, Polarity, Uls},
};
@ -360,7 +360,7 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
// The first lambda set contains one concrete lambda, plus all solved
// lambdas, plus all other unspecialized lambdas.
// l' = [solved_lambdas + t1 + ... + tm + C:f:r]
let unspecialized = SubsSlice::extend_new(
let unspecialized = slice_extend_new(
&mut env.subs.unspecialized_lambda_sets,
not_concrete
.drain(..)
@ -371,7 +371,7 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
// All the other lambda sets consists only of their respective concrete
// lambdas.
// ln = [[] + C:fn:rn]
let unspecialized = SubsSlice::extend_new(
let unspecialized = slice_extend_new(
&mut env.subs.unspecialized_lambda_sets,
[concrete_lambda],
);
@ -521,10 +521,7 @@ fn compact_lambda_set<P: Phase>(
let t_f1_lambda_set_without_concrete = LambdaSet {
solved,
recursion_var,
unspecialized: SubsSlice::extend_new(
&mut env.subs.unspecialized_lambda_sets,
new_unspecialized,
),
unspecialized: slice_extend_new(&mut env.subs.unspecialized_lambda_sets, new_unspecialized),
ambient_function: t_f1,
};
env.subs.set_content(
@ -670,6 +667,8 @@ fn make_specialization_decision<P: Phase>(
| RigidVar(..)
| LambdaSet(..)
| ErasedLambda
| Pure
| Effectful
| RangedNumber(..) => {
internal_error!("unexpected")
}

View file

@ -1,7 +1,7 @@
use std::cell::RefCell;
use roc_can::{abilities::AbilitiesStore, constraint::TypeOrVar, expected::Expected};
use roc_collections::soa::{Index, Slice};
use roc_collections::soa::slice_extend_new;
use roc_error_macros::internal_error;
use roc_module::{ident::TagName, symbol::Symbol};
use roc_region::all::Loc;
@ -19,6 +19,7 @@ use roc_types::{
},
};
use roc_unify::unify::{unify, Unified};
use soa::{Index, Slice};
use crate::{
ability::{AbilityImplError, ObligationCache},
@ -329,7 +330,7 @@ pub(crate) fn type_to_var_help(
region: _,
} => {
let arguments = types.get_type_arguments(typ_index);
let new_arguments = VariableSubsSlice::reserve_into_subs(env.subs, arguments.len());
let new_arguments = env.subs.reserve_into_vars(arguments.len());
for (target_index, var_index) in
(new_arguments.indices()).zip(arguments.into_iter())
{
@ -372,7 +373,7 @@ pub(crate) fn type_to_var_help(
}
}
UnspecializedLambdaSet { unspecialized } => {
let unspecialized_slice = SubsSlice::extend_new(
let unspecialized_slice = slice_extend_new(
&mut env.subs.unspecialized_lambda_sets,
std::iter::once(unspecialized),
);
@ -401,9 +402,9 @@ pub(crate) fn type_to_var_help(
env.register_with_known_var(destination, rank, content)
}
// This case is important for the rank of boolean variables
Function(closure_type, ret_type) => {
Function(closure_type, ret_type, fx_type) => {
let arguments = types.get_type_arguments(typ_index);
let new_arguments = VariableSubsSlice::reserve_into_subs(env.subs, arguments.len());
let new_arguments = env.subs.reserve_into_vars(arguments.len());
for (target_index, var_index) in
(new_arguments.indices()).zip(arguments.into_iter())
{
@ -412,10 +413,11 @@ pub(crate) fn type_to_var_help(
}
let ret_var = helper!(ret_type);
let fx_var = helper!(fx_type);
let closure_var =
helper!(closure_type, AmbientFunctionPolicy::Function(destination));
let content =
Content::Structure(FlatType::Func(new_arguments, closure_var, ret_var));
Content::Structure(FlatType::Func(new_arguments, closure_var, ret_var, fx_var));
env.register_with_known_var(destination, rank, content)
}
@ -545,8 +547,8 @@ pub(crate) fn type_to_var_help(
unreachable!("we assert that the ext var is empty; otherwise we'd already know it was a tag union!");
}
let tag_names = SubsSlice::extend_new(&mut env.subs.tag_names, [tag_name]);
let symbols = SubsSlice::extend_new(&mut env.subs.symbol_names, [symbol]);
let tag_names = slice_extend_new(&mut env.subs.tag_names, [tag_name]);
let symbols = slice_extend_new(&mut env.subs.symbol_names, [symbol]);
let content =
Content::Structure(FlatType::FunctionOrTagUnion(tag_names, symbols, ext));
@ -603,8 +605,7 @@ pub(crate) fn type_to_var_help(
let all_vars_length = type_arguments.len()
+ lambda_set_variables.len()
+ infer_ext_in_output_variables.len();
let new_variables =
VariableSubsSlice::reserve_into_subs(env.subs, all_vars_length);
let new_variables = env.subs.reserve_into_vars(all_vars_length);
let type_arguments_offset = 0;
let lambda_set_vars_offset = type_arguments_offset + type_arguments.len();
@ -652,7 +653,7 @@ pub(crate) fn type_to_var_help(
}
AliasVariables {
variables_start: new_variables.start,
variables_start: new_variables.start(),
type_variables_len: type_arguments.len() as _,
lambda_set_variables_len: lambda_set_variables.len() as _,
all_variables_len: all_vars_length as _,
@ -704,8 +705,7 @@ pub(crate) fn type_to_var_help(
let lambda_set_vars_offset = type_arguments_offset + type_arguments.len();
let infer_ext_vars_offset = lambda_set_vars_offset + lambda_set_variables.len();
let new_variables =
VariableSubsSlice::reserve_into_subs(env.subs, all_vars_length);
let new_variables = env.subs.reserve_into_vars(all_vars_length);
for (((target_index, typ), region), abilities) in
(new_variables.indices().skip(type_arguments_offset))
@ -736,7 +736,7 @@ pub(crate) fn type_to_var_help(
}
AliasVariables {
variables_start: new_variables.start,
variables_start: new_variables.start(),
type_variables_len: type_arguments.len() as _,
lambda_set_variables_len: lambda_set_variables.len() as _,
all_variables_len: all_vars_length as _,
@ -752,6 +752,16 @@ pub(crate) fn type_to_var_help(
env.register_with_known_var(destination, rank, content)
}
Pure => {
let content = Content::Pure;
env.register_with_known_var(destination, rank, content)
}
Effectful => {
let content = Content::Effectful;
env.register_with_known_var(destination, rank, content)
}
Error => {
let content = Content::Error;
@ -765,10 +775,8 @@ pub(crate) fn type_to_var_help(
match *env.subs.get_content_unchecked(var) {
Content::RigidVar(a) => {
// TODO(multi-abilities): check run cache
let abilities_slice = SubsSlice::extend_new(
&mut env.subs.symbol_names,
abilities.sorted_iter().copied(),
);
let abilities_slice =
slice_extend_new(&mut env.subs.symbol_names, abilities.sorted_iter().copied());
env.subs
.set_content(var, Content::RigidAbleVar(a, abilities_slice));
}
@ -778,10 +786,8 @@ pub(crate) fn type_to_var_help(
// pass, already bound
}
_ => {
let abilities_slice = SubsSlice::extend_new(
&mut env.subs.symbol_names,
abilities.sorted_iter().copied(),
);
let abilities_slice =
slice_extend_new(&mut env.subs.symbol_names, abilities.sorted_iter().copied());
let flex_ability = env.register(rank, Content::FlexAbleVar(None, abilities_slice));
@ -969,7 +975,7 @@ fn find_tag_name_run(slice: &[TagName], subs: &mut Subs) -> Option<SubsSlice<Tag
Some(occupied) => {
let subs_slice = *occupied;
let prefix_slice = SubsSlice::new(subs_slice.start, slice.len() as _);
let prefix_slice = SubsSlice::new(subs_slice.start(), slice.len() as _);
if slice.len() == 1 {
return Some(prefix_slice);
@ -978,7 +984,7 @@ fn find_tag_name_run(slice: &[TagName], subs: &mut Subs) -> Option<SubsSlice<Tag
match slice.len().cmp(&subs_slice.len()) {
Ordering::Less => {
// we might have a prefix
let tag_names = &subs.tag_names[subs_slice.start as usize..];
let tag_names = &subs.tag_names[subs_slice.start() as usize..];
for (from_subs, from_slice) in tag_names.iter().zip(slice.iter()) {
if from_subs != from_slice {
@ -1025,8 +1031,8 @@ fn register_tag_arguments(
if arguments.is_empty() {
VariableSubsSlice::default()
} else {
let new_variables = VariableSubsSlice::reserve_into_subs(env.subs, arguments.len());
let it = new_variables.indices().zip(arguments.into_iter());
let new_variables = env.subs.reserve_into_vars(arguments.len());
let it = new_variables.indices().zip(arguments);
for (target_index, argument) in it {
let var = RegisterVariable::with_stack(env, rank, arena, types, argument, stack);
@ -1056,8 +1062,7 @@ fn insert_tags_fast_path(
let variable_slice =
register_tag_arguments(env, rank, arena, types, stack, arguments_slice);
let new_variable_slices =
SubsSlice::extend_new(&mut env.subs.variable_slices, [variable_slice]);
let new_variable_slices = slice_extend_new(&mut env.subs.variable_slices, [variable_slice]);
macro_rules! subs_tag_name {
($tag_name_slice:expr) => {
@ -1075,10 +1080,10 @@ fn insert_tags_fast_path(
}
}
let new_variable_slices = SubsSlice::reserve_variable_slices(env.subs, tags.len());
let new_variable_slices = env.subs.reserve_variable_slices(tags.len());
match find_tag_name_run(&types[tags], env.subs) {
Some(new_tag_names) => {
let it = (new_variable_slices.indices()).zip(payload_slices.into_iter());
let it = (new_variable_slices.indices()).zip(payload_slices);
for (variable_slice_index, arguments_index) in it {
let arguments = types[arguments_index];
@ -1089,12 +1094,12 @@ fn insert_tags_fast_path(
UnionTags::from_slices(new_tag_names, new_variable_slices)
}
None => {
let new_tag_names = SubsSlice::reserve_tag_names(env.subs, tags.len());
let new_tag_names = env.subs.reserve_tag_names(tags.len());
let it = (new_variable_slices.indices())
.zip(new_tag_names.indices())
.zip(tags.into_iter())
.zip(payload_slices.into_iter());
.zip(tags)
.zip(payload_slices);
for (((variable_slice_index, tag_name_index), tag_name), arguments_index) in it {
let arguments = types[arguments_index];
@ -1124,7 +1129,7 @@ fn insert_tags_slow_path(
{
let tag_argument_types = &types[tag_argument_types_index];
let new_slice = VariableSubsSlice::reserve_into_subs(env.subs, tag_argument_types.len());
let new_slice = env.subs.reserve_into_vars(tag_argument_types.len());
for (i, arg) in (new_slice.indices()).zip(tag_argument_types.into_iter()) {
let var = RegisterVariable::with_stack(env, rank, arena, types, arg, stack);
@ -1208,10 +1213,9 @@ fn create_union_lambda(
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
) -> UnionLambdas {
let variable_slice = register_tag_arguments(env, rank, arena, types, stack, capture_types);
let new_variable_slices =
SubsSlice::extend_new(&mut env.subs.variable_slices, [variable_slice]);
let new_variable_slices = slice_extend_new(&mut env.subs.variable_slices, [variable_slice]);
let lambda_name_slice = SubsSlice::extend_new(&mut env.subs.symbol_names, [closure]);
let lambda_name_slice = slice_extend_new(&mut env.subs.symbol_names, [closure]);
UnionLambdas::from_slices(lambda_name_slice, new_variable_slices)
}

View file

@ -3863,7 +3863,7 @@ mod solve_expr {
#[test]
fn list_split() {
infer_eq_without_problem(
indoc!("List.split"),
indoc!("List.splitAt"),
"List elem, U64 -> { before : List elem, others : List elem }",
);
}