mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
Merge branch 'main' into specialize-exprs
This commit is contained in:
commit
2e96aca0fd
797 changed files with 17394 additions and 12632 deletions
|
@ -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"] }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 }",
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue