mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 11:52:19 +00:00
Merge pull request #4485 from roc-lang/types-soa
Types SoA and Type -> Variable conversion via SoA
This commit is contained in:
commit
95f8bac859
5 changed files with 980 additions and 217 deletions
|
@ -1,11 +1,24 @@
|
|||
use std::usize;
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct Index<T> {
|
||||
index: u32,
|
||||
_marker: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Eq for Index<T> {}
|
||||
|
||||
impl<T> PartialEq for Index<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.index == other.index
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::hash::Hash for Index<T> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.index.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Index<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
|
|
|
@ -16,6 +16,7 @@ use roc_can::expected::{Expected, PExpected};
|
|||
use roc_can::expr::PendingDerives;
|
||||
use roc_can::module::ExposedByModule;
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_collections::soa::{Index, Slice};
|
||||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
use roc_debug_flags::ROC_VERIFY_RIGID_LET_GENERALIZED;
|
||||
|
@ -31,10 +32,9 @@ use roc_types::subs::{
|
|||
OptVariable, Rank, RecordFields, Subs, SubsIndex, SubsSlice, UlsOfVar, UnionLabels,
|
||||
UnionLambdas, UnionTags, Variable, VariableSubsSlice,
|
||||
};
|
||||
use roc_types::types::Type::{self, *};
|
||||
use roc_types::types::{
|
||||
gather_fields_unsorted_iter, AliasCommon, AliasKind, Category, OptAbleType, OptAbleVar,
|
||||
Polarity, Reason, RecordField, TypeExtension, Uls,
|
||||
gather_fields_unsorted_iter, AliasKind, AliasShared, Category, OptAbleVar, Polarity, Reason,
|
||||
RecordField, Type, TypeExtension, TypeTag, Types, Uls,
|
||||
};
|
||||
use roc_unify::unify::{
|
||||
unify, unify_introduced_ability_specialization, Env as UEnv, Mode, Obligated,
|
||||
|
@ -300,6 +300,7 @@ impl Aliases {
|
|||
abilities_store: &AbilitiesStore,
|
||||
obligation_cache: &mut ObligationCache,
|
||||
arena: &bumpalo::Bump,
|
||||
types: &mut Types,
|
||||
symbol: Symbol,
|
||||
alias_variables: AliasVariables,
|
||||
) -> (Variable, AliasKind) {
|
||||
|
@ -416,6 +417,7 @@ impl Aliases {
|
|||
if !can_reuse_old_definition {
|
||||
let mut typ = typ.clone();
|
||||
typ.substitute_variables(&substitutions);
|
||||
let typ = types.from_old_type(&typ);
|
||||
let alias_variable = type_to_variable(
|
||||
subs,
|
||||
rank,
|
||||
|
@ -425,7 +427,8 @@ impl Aliases {
|
|||
obligation_cache,
|
||||
arena,
|
||||
self,
|
||||
&typ,
|
||||
types,
|
||||
typ,
|
||||
false,
|
||||
);
|
||||
(alias_variable, kind)
|
||||
|
@ -441,6 +444,7 @@ impl Aliases {
|
|||
// 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
|
||||
// during canonicalization)
|
||||
let t_index = types.from_old_type(&t);
|
||||
let alias_variable = type_to_variable(
|
||||
subs,
|
||||
rank,
|
||||
|
@ -450,7 +454,8 @@ impl Aliases {
|
|||
obligation_cache,
|
||||
arena,
|
||||
self,
|
||||
&t,
|
||||
types,
|
||||
t_index,
|
||||
false,
|
||||
);
|
||||
|
||||
|
@ -2368,6 +2373,8 @@ pub(crate) fn type_to_var(
|
|||
*var
|
||||
} else {
|
||||
let mut arena = take_scratchpad();
|
||||
let mut types = Types::new();
|
||||
let typ = types.from_old_type(typ);
|
||||
|
||||
let var = type_to_variable(
|
||||
subs,
|
||||
|
@ -2378,6 +2385,7 @@ pub(crate) fn type_to_var(
|
|||
obligation_cache,
|
||||
&arena,
|
||||
aliases,
|
||||
&mut types,
|
||||
typ,
|
||||
false,
|
||||
);
|
||||
|
@ -2403,30 +2411,21 @@ impl RegisterVariable {
|
|||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
arena: &'_ bumpalo::Bump,
|
||||
typ: &Type,
|
||||
types: &mut Types,
|
||||
typ: Index<TypeTag>,
|
||||
) -> Self {
|
||||
use RegisterVariable::*;
|
||||
|
||||
match typ {
|
||||
Type::Variable(var) => Direct(*var),
|
||||
EmptyRec => Direct(Variable::EMPTY_RECORD),
|
||||
EmptyTagUnion => Direct(Variable::EMPTY_TAG_UNION),
|
||||
Type::DelayedAlias(AliasCommon { symbol, .. }) => {
|
||||
if let Some(reserved) = Variable::get_reserved(*symbol) {
|
||||
if rank.is_none() {
|
||||
// reserved variables are stored with rank NONE
|
||||
return Direct(reserved);
|
||||
} else {
|
||||
// for any other rank, we need to copy; it takes care of adjusting the rank
|
||||
let copied = deep_copy_var_in(subs, rank, pools, reserved, arena);
|
||||
return Direct(copied);
|
||||
}
|
||||
}
|
||||
|
||||
Deferred
|
||||
}
|
||||
Type::Alias { symbol, .. } => {
|
||||
if let Some(reserved) = Variable::get_reserved(*symbol) {
|
||||
match types[typ] {
|
||||
TypeTag::Variable(var) => Direct(var),
|
||||
TypeTag::EmptyRecord => Direct(Variable::EMPTY_RECORD),
|
||||
TypeTag::EmptyTagUnion => Direct(Variable::EMPTY_TAG_UNION),
|
||||
TypeTag::DelayedAlias { shared }
|
||||
| TypeTag::StructuralAlias { shared, .. }
|
||||
| TypeTag::OpaqueAlias { shared, .. }
|
||||
| TypeTag::HostExposedAlias { shared, .. } => {
|
||||
let AliasShared { symbol, .. } = types[shared];
|
||||
if let Some(reserved) = Variable::get_reserved(symbol) {
|
||||
if rank.is_none() {
|
||||
// reserved variables are stored with rank NONE
|
||||
return Direct(reserved);
|
||||
|
@ -2444,15 +2443,16 @@ impl RegisterVariable {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn with_stack<'a>(
|
||||
fn with_stack(
|
||||
subs: &mut Subs,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
arena: &'_ bumpalo::Bump,
|
||||
typ: &'a Type,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>,
|
||||
types: &mut Types,
|
||||
typ: Index<TypeTag>,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
) -> Variable {
|
||||
match Self::from_type(subs, rank, pools, arena, typ) {
|
||||
match Self::from_type(subs, rank, pools, arena, types, typ) {
|
||||
Self::Direct(var) => var,
|
||||
Self::Deferred => {
|
||||
let var = subs.fresh_unnamed_flex_var();
|
||||
|
@ -2518,9 +2518,9 @@ impl AmbientFunctionPolicy {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum TypeToVar<'a> {
|
||||
enum TypeToVar {
|
||||
Defer {
|
||||
typ: &'a Type,
|
||||
typ: Index<TypeTag>,
|
||||
destination: Variable,
|
||||
ambient_function: AmbientFunctionPolicy,
|
||||
},
|
||||
|
@ -2536,7 +2536,8 @@ fn type_to_variable<'a>(
|
|||
obligation_cache: &mut ObligationCache,
|
||||
arena: &'a bumpalo::Bump,
|
||||
aliases: &mut Aliases,
|
||||
typ: &Type,
|
||||
types: &mut Types,
|
||||
typ: Index<TypeTag>,
|
||||
// Helpers for instantiating ambient functions of lambda set variables from type aliases.
|
||||
is_alias_lambda_set_arg: bool,
|
||||
) -> Variable {
|
||||
|
@ -2547,7 +2548,7 @@ fn type_to_variable<'a>(
|
|||
|
||||
macro_rules! helper {
|
||||
($typ:expr, $ambient_function_policy:expr) => {{
|
||||
match RegisterVariable::from_type(subs, rank, pools, arena, $typ) {
|
||||
match RegisterVariable::from_type(subs, rank, pools, arena, types, $typ) {
|
||||
RegisterVariable::Direct(var) => {
|
||||
// If the variable is just a type variable but we know we're in a lambda set
|
||||
// context, try to link to the ambient function.
|
||||
|
@ -2579,23 +2580,31 @@ fn type_to_variable<'a>(
|
|||
ambient_function,
|
||||
}) = stack.pop()
|
||||
{
|
||||
match typ {
|
||||
Variable(_) | EmptyRec | EmptyTagUnion => {
|
||||
use TypeTag::*;
|
||||
match types[typ] {
|
||||
Variable(_) | EmptyRecord | EmptyTagUnion => {
|
||||
unreachable!("This variant should never be deferred!")
|
||||
}
|
||||
RangedNumber(range) => {
|
||||
let content = Content::RangedNumber(*range);
|
||||
let content = Content::RangedNumber(range);
|
||||
|
||||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
Apply(symbol, arguments, _) => {
|
||||
Apply {
|
||||
symbol,
|
||||
type_argument_regions: _,
|
||||
region: _,
|
||||
} => {
|
||||
let arguments = types.get_type_arguments(typ);
|
||||
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
||||
for (target_index, var_index) in (new_arguments.indices()).zip(arguments) {
|
||||
let var = helper!(&var_index.value);
|
||||
for (target_index, var_index) in
|
||||
(new_arguments.indices()).zip(arguments.into_iter())
|
||||
{
|
||||
let var = helper!(var_index);
|
||||
subs.variables[target_index] = var;
|
||||
}
|
||||
|
||||
let flat_type = FlatType::Apply(*symbol, new_arguments);
|
||||
let flat_type = FlatType::Apply(symbol, new_arguments);
|
||||
let content = Content::Structure(flat_type);
|
||||
|
||||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
|
@ -2603,11 +2612,12 @@ fn type_to_variable<'a>(
|
|||
|
||||
ClosureTag {
|
||||
name,
|
||||
captures,
|
||||
ambient_function,
|
||||
} => {
|
||||
let union_lambdas =
|
||||
create_union_lambda(subs, rank, pools, arena, *name, captures, &mut stack);
|
||||
let captures = types.get_type_arguments(typ);
|
||||
let union_lambdas = create_union_lambda(
|
||||
subs, rank, pools, arena, types, name, captures, &mut stack,
|
||||
);
|
||||
|
||||
let content = Content::LambdaSet(subs::LambdaSet {
|
||||
solved: union_lambdas,
|
||||
|
@ -2615,7 +2625,7 @@ fn type_to_variable<'a>(
|
|||
// is to begin with.
|
||||
recursion_var: OptVariable::NONE,
|
||||
unspecialized: SubsSlice::default(),
|
||||
ambient_function: *ambient_function,
|
||||
ambient_function,
|
||||
});
|
||||
|
||||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
|
@ -2623,7 +2633,7 @@ fn type_to_variable<'a>(
|
|||
UnspecializedLambdaSet { unspecialized } => {
|
||||
let unspecialized_slice = SubsSlice::extend_new(
|
||||
&mut subs.unspecialized_lambda_sets,
|
||||
std::iter::once(*unspecialized),
|
||||
std::iter::once(unspecialized),
|
||||
);
|
||||
|
||||
// `ClosureTag` ambient functions are resolved during constraint generation.
|
||||
|
@ -2635,7 +2645,7 @@ fn type_to_variable<'a>(
|
|||
AmbientFunctionPolicy::NoFunction => {
|
||||
debug_assert!(is_alias_lambda_set_arg);
|
||||
// To be filled in during delayed type alias instantiation
|
||||
Variable::NULL
|
||||
roc_types::subs::Variable::NULL
|
||||
}
|
||||
AmbientFunctionPolicy::Function(var) => var,
|
||||
};
|
||||
|
@ -2650,9 +2660,12 @@ fn type_to_variable<'a>(
|
|||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
// This case is important for the rank of boolean variables
|
||||
Function(arguments, closure_type, ret_type) => {
|
||||
Function(closure_type, ret_type) => {
|
||||
let arguments = types.get_type_arguments(typ);
|
||||
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.into_iter())
|
||||
{
|
||||
let var = helper!(var_index);
|
||||
subs.variables[target_index] = var;
|
||||
}
|
||||
|
@ -2665,31 +2678,33 @@ fn type_to_variable<'a>(
|
|||
|
||||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
Record(fields, ext) => {
|
||||
Record(fields) => {
|
||||
let ext_slice = types.get_type_arguments(typ);
|
||||
|
||||
// An empty fields is inefficient (but would be correct)
|
||||
// If hit, try to turn the value into an EmptyRecord in canonicalization
|
||||
debug_assert!(!fields.is_empty() || !ext.is_closed());
|
||||
debug_assert!(!fields.is_empty() || !ext_slice.is_empty());
|
||||
|
||||
let mut field_vars = Vec::with_capacity_in(fields.len(), arena);
|
||||
|
||||
for (field, field_type) in fields {
|
||||
let (fields_names, field_kinds, field_tys) = types.record_fields_slices(fields);
|
||||
|
||||
for ((field, field_kind), field_type) in (fields_names.into_iter())
|
||||
.zip(field_kinds.into_iter())
|
||||
.zip(field_tys.into_iter())
|
||||
{
|
||||
let field_var = {
|
||||
use roc_types::types::RecordField::*;
|
||||
match &field_type {
|
||||
Optional(t) => Optional(helper!(t)),
|
||||
Required(t) => Required(helper!(t)),
|
||||
Demanded(t) => Demanded(helper!(t)),
|
||||
RigidRequired(t) => RigidRequired(helper!(t)),
|
||||
RigidOptional(t) => RigidOptional(helper!(t)),
|
||||
}
|
||||
let t = helper!(field_type);
|
||||
types[field_kind].replace(t)
|
||||
};
|
||||
|
||||
field_vars.push((field.clone(), field_var));
|
||||
field_vars.push((types[field].clone(), field_var));
|
||||
}
|
||||
|
||||
let temp_ext_var = match ext {
|
||||
TypeExtension::Open(ext) => helper!(ext),
|
||||
TypeExtension::Closed => Variable::EMPTY_RECORD,
|
||||
debug_assert!(ext_slice.len() <= 1);
|
||||
let temp_ext_var = match ext_slice.into_iter().next() {
|
||||
None => roc_types::subs::Variable::EMPTY_RECORD,
|
||||
Some(ext) => helper!(ext),
|
||||
};
|
||||
|
||||
let (it, new_ext_var) =
|
||||
|
@ -2710,21 +2725,28 @@ fn type_to_variable<'a>(
|
|||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
|
||||
TagUnion(tags, ext) => {
|
||||
TagUnion(tags) => {
|
||||
let ext_slice = types.get_type_arguments(typ);
|
||||
|
||||
// An empty tags is inefficient (but would be correct)
|
||||
// If hit, try to turn the value into an EmptyTagUnion in canonicalization
|
||||
debug_assert!(!tags.is_empty() || !ext.is_closed());
|
||||
debug_assert!(!tags.is_empty() || !ext_slice.is_empty());
|
||||
|
||||
let (union_tags, ext) =
|
||||
type_to_union_tags(subs, rank, pools, arena, tags, ext, &mut stack);
|
||||
let (union_tags, ext) = type_to_union_tags(
|
||||
subs, rank, pools, arena, types, tags, ext_slice, &mut stack,
|
||||
);
|
||||
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
|
||||
|
||||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
FunctionOrTagUnion(tag_name, symbol, ext) => {
|
||||
let temp_ext_var = match ext {
|
||||
TypeExtension::Open(ext) => helper!(ext),
|
||||
TypeExtension::Closed => Variable::EMPTY_TAG_UNION,
|
||||
FunctionOrTagUnion(symbol) => {
|
||||
let ext_slice = types.get_type_arguments(typ);
|
||||
let tag_name = types.get_tag_name(&typ).clone();
|
||||
|
||||
debug_assert!(ext_slice.len() <= 1);
|
||||
let temp_ext_var = match ext_slice.into_iter().next() {
|
||||
Some(ext) => helper!(ext),
|
||||
None => roc_types::subs::Variable::EMPTY_TAG_UNION,
|
||||
};
|
||||
|
||||
let (it, ext) = roc_types::types::gather_tags_unsorted_iter(
|
||||
|
@ -2738,30 +2760,33 @@ fn type_to_variable<'a>(
|
|||
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 subs.tag_names, [tag_name.clone()]);
|
||||
let symbols = SubsSlice::extend_new(&mut subs.symbol_names, [*symbol]);
|
||||
let tag_names = SubsSlice::extend_new(&mut subs.tag_names, [tag_name]);
|
||||
let symbols = SubsSlice::extend_new(&mut subs.symbol_names, [symbol]);
|
||||
|
||||
let content =
|
||||
Content::Structure(FlatType::FunctionOrTagUnion(tag_names, symbols, ext));
|
||||
|
||||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
RecursiveTagUnion(rec_var, tags) => {
|
||||
let ext_slice = types.get_type_arguments(typ);
|
||||
|
||||
// An empty tags is inefficient (but would be correct)
|
||||
// If hit, try to turn the value into an EmptyTagUnion in canonicalization
|
||||
debug_assert!(!tags.is_empty() || !ext.is_closed());
|
||||
debug_assert!(!tags.is_empty() || !ext_slice.is_empty());
|
||||
|
||||
let (union_tags, ext) =
|
||||
type_to_union_tags(subs, rank, pools, arena, tags, ext, &mut stack);
|
||||
let (union_tags, ext) = type_to_union_tags(
|
||||
subs, rank, pools, arena, types, tags, ext_slice, &mut stack,
|
||||
);
|
||||
let content =
|
||||
Content::Structure(FlatType::RecursiveTagUnion(*rec_var, union_tags, ext));
|
||||
Content::Structure(FlatType::RecursiveTagUnion(rec_var, union_tags, ext));
|
||||
|
||||
let tag_union_var = destination;
|
||||
register_with_known_var(subs, tag_union_var, rank, pools, content);
|
||||
|
||||
register_with_known_var(
|
||||
subs,
|
||||
*rec_var,
|
||||
rec_var,
|
||||
rank,
|
||||
pools,
|
||||
Content::RecursionVar {
|
||||
|
@ -2773,34 +2798,43 @@ fn type_to_variable<'a>(
|
|||
tag_union_var
|
||||
}
|
||||
|
||||
Type::DelayedAlias(AliasCommon {
|
||||
symbol,
|
||||
type_arguments,
|
||||
lambda_set_variables,
|
||||
infer_ext_in_output_types,
|
||||
}) => {
|
||||
DelayedAlias { shared } => {
|
||||
let AliasShared {
|
||||
symbol,
|
||||
type_argument_abilities,
|
||||
type_argument_regions,
|
||||
lambda_set_variables,
|
||||
infer_ext_in_output_variables,
|
||||
} = types[shared];
|
||||
|
||||
let type_arguments = types.get_type_arguments(typ);
|
||||
|
||||
let alias_variables = {
|
||||
let all_vars_length = type_arguments.len()
|
||||
+ lambda_set_variables.len()
|
||||
+ infer_ext_in_output_types.len();
|
||||
+ infer_ext_in_output_variables.len();
|
||||
let new_variables = VariableSubsSlice::reserve_into_subs(subs, all_vars_length);
|
||||
|
||||
let type_arguments_offset = 0;
|
||||
let lambda_set_vars_offset = type_arguments_offset + type_arguments.len();
|
||||
let infer_ext_vars_offset = lambda_set_vars_offset + lambda_set_variables.len();
|
||||
|
||||
for (target_index, arg_type) in
|
||||
(new_variables.indices().skip(type_arguments_offset)).zip(type_arguments)
|
||||
for (((target_index, arg_type), arg_region), abilities) in
|
||||
(new_variables.indices().skip(type_arguments_offset))
|
||||
.zip(type_arguments.into_iter())
|
||||
.zip(type_argument_regions.into_iter())
|
||||
.zip(type_argument_abilities.into_iter())
|
||||
{
|
||||
let copy_var = helper!(&arg_type.value.typ);
|
||||
let copy_var = helper!(arg_type);
|
||||
subs.variables[target_index] = copy_var;
|
||||
if let Some(abilities) = arg_type.value.opt_abilities.as_ref() {
|
||||
bind_to_abilities.push((Loc::at(arg_type.region, copy_var), abilities));
|
||||
if !types[abilities].is_empty() {
|
||||
let arg_region = types[arg_region];
|
||||
bind_to_abilities.push((Loc::at(arg_region, copy_var), abilities));
|
||||
}
|
||||
}
|
||||
|
||||
let it = (new_variables.indices().skip(lambda_set_vars_offset))
|
||||
.zip(lambda_set_variables);
|
||||
.zip(lambda_set_variables.into_iter());
|
||||
for (target_index, ls) in it {
|
||||
// We MUST do this now, otherwise when linking the ambient function during
|
||||
// instantiation of the real var, there will be nothing to link against.
|
||||
|
@ -2813,14 +2847,15 @@ fn type_to_variable<'a>(
|
|||
obligation_cache,
|
||||
arena,
|
||||
aliases,
|
||||
&ls.0,
|
||||
types,
|
||||
ls,
|
||||
true,
|
||||
);
|
||||
subs.variables[target_index] = copy_var;
|
||||
}
|
||||
|
||||
let it = (new_variables.indices().skip(infer_ext_vars_offset))
|
||||
.zip(infer_ext_in_output_types);
|
||||
.zip(infer_ext_in_output_variables.into_iter());
|
||||
for (target_index, ext_typ) in it {
|
||||
let copy_var = helper!(ext_typ);
|
||||
subs.variables[target_index] = copy_var;
|
||||
|
@ -2842,29 +2877,39 @@ fn type_to_variable<'a>(
|
|||
abilities_store,
|
||||
obligation_cache,
|
||||
arena,
|
||||
*symbol,
|
||||
types,
|
||||
symbol,
|
||||
alias_variables,
|
||||
);
|
||||
|
||||
let content = Content::Alias(*symbol, alias_variables, alias_variable, kind);
|
||||
let content = Content::Alias(symbol, alias_variables, alias_variable, kind);
|
||||
|
||||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
|
||||
Type::Alias {
|
||||
symbol,
|
||||
type_arguments,
|
||||
actual,
|
||||
lambda_set_variables,
|
||||
infer_ext_in_output_types,
|
||||
kind,
|
||||
} => {
|
||||
debug_assert!(Variable::get_reserved(*symbol).is_none());
|
||||
StructuralAlias { shared, actual } | OpaqueAlias { shared, actual } => {
|
||||
let kind = match types[typ] {
|
||||
StructuralAlias { .. } => AliasKind::Structural,
|
||||
OpaqueAlias { .. } => AliasKind::Opaque,
|
||||
_ => internal_error!(),
|
||||
};
|
||||
|
||||
let AliasShared {
|
||||
symbol,
|
||||
type_argument_abilities,
|
||||
type_argument_regions,
|
||||
lambda_set_variables,
|
||||
infer_ext_in_output_variables,
|
||||
} = types[shared];
|
||||
|
||||
debug_assert!(roc_types::subs::Variable::get_reserved(symbol).is_none());
|
||||
|
||||
let type_arguments = types.get_type_arguments(typ);
|
||||
|
||||
let alias_variables = {
|
||||
let all_vars_length = type_arguments.len()
|
||||
+ lambda_set_variables.len()
|
||||
+ infer_ext_in_output_types.len();
|
||||
+ infer_ext_in_output_variables.len();
|
||||
|
||||
let type_arguments_offset = 0;
|
||||
let lambda_set_vars_offset = type_arguments_offset + type_arguments.len();
|
||||
|
@ -2872,28 +2917,29 @@ fn type_to_variable<'a>(
|
|||
|
||||
let new_variables = VariableSubsSlice::reserve_into_subs(subs, all_vars_length);
|
||||
|
||||
for (target_index, OptAbleType { typ, opt_abilities }) in
|
||||
(new_variables.indices().skip(type_arguments_offset)).zip(type_arguments)
|
||||
for (((target_index, typ), region), abilities) in
|
||||
(new_variables.indices().skip(type_arguments_offset))
|
||||
.zip(type_arguments.into_iter())
|
||||
.zip(type_argument_regions.into_iter())
|
||||
.zip(type_argument_abilities.into_iter())
|
||||
{
|
||||
let copy_var = helper!(typ);
|
||||
subs.variables[target_index] = copy_var;
|
||||
if let Some(abilities) = opt_abilities.as_ref() {
|
||||
bind_to_abilities.push((
|
||||
Loc::at(roc_region::all::Region::zero(), copy_var),
|
||||
abilities,
|
||||
));
|
||||
if !types[abilities].is_empty() {
|
||||
let region = types[region];
|
||||
bind_to_abilities.push((Loc::at(region, copy_var), abilities));
|
||||
}
|
||||
}
|
||||
|
||||
let it = (new_variables.indices().skip(lambda_set_vars_offset))
|
||||
.zip(lambda_set_variables);
|
||||
.zip(lambda_set_variables.into_iter());
|
||||
for (target_index, ls) in it {
|
||||
let copy_var = helper!(&ls.0);
|
||||
let copy_var = helper!(ls);
|
||||
subs.variables[target_index] = copy_var;
|
||||
}
|
||||
|
||||
let it = (new_variables.indices().skip(infer_ext_vars_offset))
|
||||
.zip(infer_ext_in_output_types);
|
||||
.zip(infer_ext_in_output_variables.into_iter());
|
||||
for (target_index, ext_typ) in it {
|
||||
let copy_var = helper!(ext_typ);
|
||||
subs.variables[target_index] = copy_var;
|
||||
|
@ -2907,33 +2953,42 @@ fn type_to_variable<'a>(
|
|||
}
|
||||
};
|
||||
|
||||
let alias_variable = if let Symbol::RESULT_RESULT = *symbol {
|
||||
roc_result_to_var(subs, rank, pools, arena, actual, &mut stack)
|
||||
let alias_variable = if let Symbol::RESULT_RESULT = symbol {
|
||||
roc_result_to_var(subs, rank, pools, arena, types, actual, &mut stack)
|
||||
} else {
|
||||
helper!(actual)
|
||||
};
|
||||
let content = Content::Alias(*symbol, alias_variables, alias_variable, *kind);
|
||||
let content = Content::Alias(symbol, alias_variables, alias_variable, kind);
|
||||
|
||||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
HostExposedAlias {
|
||||
name: symbol,
|
||||
type_arguments,
|
||||
actual: alias_type,
|
||||
actual_var,
|
||||
lambda_set_variables,
|
||||
..
|
||||
shared,
|
||||
actual_type: alias_type,
|
||||
actual_variable: actual_var,
|
||||
} => {
|
||||
let AliasShared {
|
||||
symbol,
|
||||
type_argument_abilities: _,
|
||||
type_argument_regions: _,
|
||||
lambda_set_variables,
|
||||
infer_ext_in_output_variables: _, // TODO
|
||||
} = types[shared];
|
||||
|
||||
let type_arguments = types.get_type_arguments(typ);
|
||||
|
||||
let alias_variables = {
|
||||
let length = type_arguments.len() + lambda_set_variables.len();
|
||||
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.into_iter())
|
||||
{
|
||||
let copy_var = helper!(arg_type);
|
||||
subs.variables[target_index] = copy_var;
|
||||
}
|
||||
let it = (new_variables.indices().skip(type_arguments.len()))
|
||||
.zip(lambda_set_variables);
|
||||
.zip(lambda_set_variables.into_iter());
|
||||
for (target_index, ls) in it {
|
||||
// We MUST do this now, otherwise when linking the ambient function during
|
||||
// instantiation of the real var, there will be nothing to link against.
|
||||
|
@ -2946,7 +3001,8 @@ fn type_to_variable<'a>(
|
|||
obligation_cache,
|
||||
arena,
|
||||
aliases,
|
||||
&ls.0,
|
||||
types,
|
||||
ls,
|
||||
true,
|
||||
);
|
||||
subs.variables[target_index] = copy_var;
|
||||
|
@ -2970,32 +3026,35 @@ fn type_to_variable<'a>(
|
|||
obligation_cache,
|
||||
arena,
|
||||
aliases,
|
||||
types,
|
||||
alias_type,
|
||||
false,
|
||||
);
|
||||
// TODO(opaques): I think host-exposed aliases should always be structural
|
||||
// (when does it make sense to give a host an opaque type?)
|
||||
let content = Content::Alias(
|
||||
*symbol,
|
||||
symbol,
|
||||
alias_variables,
|
||||
alias_variable,
|
||||
AliasKind::Structural,
|
||||
);
|
||||
// let result = register(subs, rank, pools, content);
|
||||
let result = register_with_known_var(subs, destination, rank, pools, content);
|
||||
|
||||
// We only want to unify the actual_var with the alias once
|
||||
// if it's already redirected (and therefore, redundant)
|
||||
// don't do it again
|
||||
if !subs.redundant(*actual_var) {
|
||||
if !subs.redundant(actual_var) {
|
||||
let descriptor = subs.get(result);
|
||||
subs.union(result, *actual_var, descriptor);
|
||||
subs.union(result, actual_var, descriptor);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
Erroneous(problem) => {
|
||||
let problem_index = SubsIndex::push_new(&mut subs.problems, problem.clone());
|
||||
Erroneous => {
|
||||
// TODO: remove `Erroneous`, `Error` can always be used, and type problems known at
|
||||
// this point can be reported during canonicalization.
|
||||
let problem_index =
|
||||
SubsIndex::push_new(&mut subs.problems, types.get_problem(&typ).clone());
|
||||
let content = Content::Structure(FlatType::Erroneous(problem_index));
|
||||
|
||||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
|
@ -3004,6 +3063,7 @@ fn type_to_variable<'a>(
|
|||
}
|
||||
|
||||
for (Loc { value: var, region }, abilities) in bind_to_abilities {
|
||||
let abilities = &types[abilities];
|
||||
match *subs.get_content_unchecked(var) {
|
||||
Content::RigidVar(a) => {
|
||||
// TODO(multi-abilities): check run cache
|
||||
|
@ -3081,28 +3141,42 @@ fn type_to_variable<'a>(
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn roc_result_to_var<'a>(
|
||||
fn roc_result_to_var(
|
||||
subs: &mut Subs,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
arena: &'_ bumpalo::Bump,
|
||||
result_type: &'a Type,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>,
|
||||
types: &mut Types,
|
||||
result_type: Index<TypeTag>,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
) -> Variable {
|
||||
match result_type {
|
||||
Type::TagUnion(tags, ext) => {
|
||||
debug_assert!(ext.is_closed());
|
||||
match types[result_type] {
|
||||
TypeTag::TagUnion(tags) => {
|
||||
let ext_slice = types.get_type_arguments(result_type);
|
||||
|
||||
debug_assert!(ext_slice.is_empty());
|
||||
debug_assert!(tags.len() == 2);
|
||||
|
||||
if let [(err, err_args), (ok, ok_args)] = &tags[..] {
|
||||
let (tags_slice, payload_slices_slice) = types.union_tag_slices(tags);
|
||||
|
||||
if let ([err, ok], [err_args, ok_args]) =
|
||||
(&types[tags_slice], &types[payload_slices_slice])
|
||||
{
|
||||
debug_assert_eq!(err, &subs.tag_names[0]);
|
||||
debug_assert_eq!(ok, &subs.tag_names[1]);
|
||||
|
||||
if let ([err_type], [ok_type]) = (err_args.as_slice(), ok_args.as_slice()) {
|
||||
let err_var =
|
||||
RegisterVariable::with_stack(subs, rank, pools, arena, err_type, stack);
|
||||
let ok_var =
|
||||
RegisterVariable::with_stack(subs, rank, pools, arena, ok_type, stack);
|
||||
debug_assert_eq!(err_args.len(), 1);
|
||||
debug_assert_eq!(ok_args.len(), 1);
|
||||
|
||||
if let (Some(err_type), Some(ok_type)) =
|
||||
(err_args.into_iter().next(), ok_args.into_iter().next())
|
||||
{
|
||||
let err_var = RegisterVariable::with_stack(
|
||||
subs, rank, pools, arena, types, err_type, stack,
|
||||
);
|
||||
let ok_var = RegisterVariable::with_stack(
|
||||
subs, rank, pools, arena, types, ok_type, stack,
|
||||
);
|
||||
|
||||
let start = subs.variables.len() as u32;
|
||||
let err_slice = SubsSlice::new(start, 1);
|
||||
|
@ -3148,13 +3222,13 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn sorted_no_duplicates<T>(slice: &[(TagName, T)]) -> bool {
|
||||
match slice.split_first() {
|
||||
fn sorted_no_duplicate_tags(tag_slices: &[TagName]) -> bool {
|
||||
match tag_slices.split_first() {
|
||||
None => true,
|
||||
Some(((first, _), rest)) => {
|
||||
Some((first, rest)) => {
|
||||
let mut current = first;
|
||||
|
||||
for (next, _) in rest {
|
||||
for next in rest {
|
||||
if current >= next {
|
||||
return false;
|
||||
} else {
|
||||
|
@ -3190,10 +3264,10 @@ fn sort_and_deduplicate<T>(tag_vars: &mut bumpalo::collections::Vec<(TagName, T)
|
|||
/// Find whether the current run of tag names is in the subs.tag_names array already. If so,
|
||||
/// we take a SubsSlice to the existing tag names, so we don't have to add/clone those tag names
|
||||
/// and keep subs memory consumption low
|
||||
fn find_tag_name_run<T>(slice: &[(TagName, T)], subs: &mut Subs) -> Option<SubsSlice<TagName>> {
|
||||
fn find_tag_name_run(slice: &[TagName], subs: &mut Subs) -> Option<SubsSlice<TagName>> {
|
||||
use std::cmp::Ordering;
|
||||
|
||||
let tag_name = &slice.get(0)?.0;
|
||||
let tag_name = slice.get(0)?;
|
||||
|
||||
let mut result = None;
|
||||
|
||||
|
@ -3215,7 +3289,7 @@ fn find_tag_name_run<T>(slice: &[(TagName, T)], subs: &mut Subs) -> Option<SubsS
|
|||
// we might have a prefix
|
||||
let tag_names = &subs.tag_names[subs_slice.start as usize..];
|
||||
|
||||
for (from_subs, (from_slice, _)) in tag_names.iter().zip(slice.iter()) {
|
||||
for (from_subs, from_slice) in tag_names.iter().zip(slice.iter()) {
|
||||
if from_subs != from_slice {
|
||||
return None;
|
||||
}
|
||||
|
@ -3226,7 +3300,7 @@ fn find_tag_name_run<T>(slice: &[(TagName, T)], subs: &mut Subs) -> Option<SubsS
|
|||
Ordering::Equal => {
|
||||
let tag_names = &subs.tag_names[subs_slice.indices()];
|
||||
|
||||
for (from_subs, (from_slice, _)) in tag_names.iter().zip(slice.iter()) {
|
||||
for (from_subs, from_slice) in tag_names.iter().zip(slice.iter()) {
|
||||
if from_subs != from_slice {
|
||||
return None;
|
||||
}
|
||||
|
@ -3249,22 +3323,24 @@ fn find_tag_name_run<T>(slice: &[(TagName, T)], subs: &mut Subs) -> Option<SubsS
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn register_tag_arguments<'a>(
|
||||
fn register_tag_arguments(
|
||||
subs: &mut Subs,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
arena: &'_ bumpalo::Bump,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>,
|
||||
arguments: &'a [Type],
|
||||
types: &mut Types,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
arguments: Slice<TypeTag>,
|
||||
) -> VariableSubsSlice {
|
||||
if arguments.is_empty() {
|
||||
VariableSubsSlice::default()
|
||||
} else {
|
||||
let new_variables = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
||||
let it = new_variables.indices().zip(arguments);
|
||||
let it = new_variables.indices().zip(arguments.into_iter());
|
||||
|
||||
for (target_index, argument) in it {
|
||||
let var = RegisterVariable::with_stack(subs, rank, pools, arena, argument, stack);
|
||||
let var =
|
||||
RegisterVariable::with_stack(subs, rank, pools, arena, types, argument, stack);
|
||||
subs.variables[target_index] = var;
|
||||
}
|
||||
|
||||
|
@ -3273,17 +3349,25 @@ fn register_tag_arguments<'a>(
|
|||
}
|
||||
|
||||
/// Assumes that the tags are sorted and there are no duplicates!
|
||||
fn insert_tags_fast_path<'a>(
|
||||
fn insert_tags_fast_path(
|
||||
subs: &mut Subs,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
arena: &'_ bumpalo::Bump,
|
||||
tags: &'a [(TagName, Vec<Type>)],
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>,
|
||||
types: &mut Types,
|
||||
union_tags: UnionTags,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
) -> UnionTags {
|
||||
if let [(TagName(tag_name), arguments)] = tags {
|
||||
let (tags, payload_slices) = types.union_tag_slices(union_tags);
|
||||
|
||||
debug_assert_eq!(tags.len(), payload_slices.len());
|
||||
|
||||
if let [arguments_slice] = &types[payload_slices] {
|
||||
let arguments_slice = *arguments_slice;
|
||||
|
||||
let variable_slice =
|
||||
register_tag_arguments(subs, rank, pools, arena, stack, arguments.as_slice());
|
||||
register_tag_arguments(subs, rank, pools, arena, types, stack, arguments_slice);
|
||||
|
||||
let new_variable_slices =
|
||||
SubsSlice::extend_new(&mut subs.variable_slices, [variable_slice]);
|
||||
|
||||
|
@ -3293,7 +3377,7 @@ fn insert_tags_fast_path<'a>(
|
|||
};
|
||||
}
|
||||
|
||||
match tag_name.as_str() {
|
||||
match types[tags][0].0.as_str() {
|
||||
"Ok" => subs_tag_name!(Subs::TAG_NAME_OK.as_slice()),
|
||||
"Err" => subs_tag_name!(Subs::TAG_NAME_ERR.as_slice()),
|
||||
"InvalidNumStr" => subs_tag_name!(Subs::TAG_NAME_INVALID_NUM_STR.as_slice()),
|
||||
|
@ -3304,13 +3388,14 @@ fn insert_tags_fast_path<'a>(
|
|||
}
|
||||
|
||||
let new_variable_slices = SubsSlice::reserve_variable_slices(subs, tags.len());
|
||||
match find_tag_name_run(tags, subs) {
|
||||
match find_tag_name_run(&types[tags], subs) {
|
||||
Some(new_tag_names) => {
|
||||
let it = (new_variable_slices.indices()).zip(tags);
|
||||
let it = (new_variable_slices.indices()).zip(payload_slices.into_iter());
|
||||
|
||||
for (variable_slice_index, (_, arguments)) in it {
|
||||
for (variable_slice_index, arguments_index) in it {
|
||||
let arguments = types[arguments_index];
|
||||
subs.variable_slices[variable_slice_index] =
|
||||
register_tag_arguments(subs, rank, pools, arena, stack, arguments.as_slice());
|
||||
register_tag_arguments(subs, rank, pools, arena, types, stack, arguments);
|
||||
}
|
||||
|
||||
UnionTags::from_slices(new_tag_names, new_variable_slices)
|
||||
|
@ -3320,13 +3405,15 @@ fn insert_tags_fast_path<'a>(
|
|||
|
||||
let it = (new_variable_slices.indices())
|
||||
.zip(new_tag_names.indices())
|
||||
.zip(tags);
|
||||
.zip(tags.into_iter())
|
||||
.zip(payload_slices.into_iter());
|
||||
|
||||
for ((variable_slice_index, tag_name_index), (tag_name, arguments)) in it {
|
||||
for (((variable_slice_index, tag_name_index), tag_name), arguments_index) in it {
|
||||
let arguments = types[arguments_index];
|
||||
subs.variable_slices[variable_slice_index] =
|
||||
register_tag_arguments(subs, rank, pools, arena, stack, arguments.as_slice());
|
||||
register_tag_arguments(subs, rank, pools, arena, types, stack, arguments);
|
||||
|
||||
subs.tag_names[tag_name_index] = tag_name.clone();
|
||||
subs.tag_names[tag_name_index] = types[tag_name].clone();
|
||||
}
|
||||
|
||||
UnionTags::from_slices(new_tag_names, new_variable_slices)
|
||||
|
@ -3334,25 +3421,30 @@ fn insert_tags_fast_path<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn insert_tags_slow_path<'a>(
|
||||
fn insert_tags_slow_path(
|
||||
subs: &mut Subs,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
arena: &'_ bumpalo::Bump,
|
||||
tags: &'a [(TagName, Vec<Type>)],
|
||||
types: &mut Types,
|
||||
union_tags: UnionTags,
|
||||
mut tag_vars: bumpalo::collections::Vec<(TagName, VariableSubsSlice)>,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
) -> UnionTags {
|
||||
for (tag, tag_argument_types) in tags {
|
||||
let tag_argument_types: &[Type] = tag_argument_types.as_slice();
|
||||
let (tags, payload_slices) = types.union_tag_slices(union_tags);
|
||||
|
||||
for (tag_index, tag_argument_types_index) in (tags.into_iter()).zip(payload_slices.into_iter())
|
||||
{
|
||||
let tag_argument_types = &types[tag_argument_types_index];
|
||||
|
||||
let new_slice = VariableSubsSlice::reserve_into_subs(subs, tag_argument_types.len());
|
||||
|
||||
for (i, arg) in (new_slice.indices()).zip(tag_argument_types) {
|
||||
let var = RegisterVariable::with_stack(subs, rank, pools, arena, arg, stack);
|
||||
for (i, arg) in (new_slice.indices()).zip(tag_argument_types.into_iter()) {
|
||||
let var = RegisterVariable::with_stack(subs, rank, pools, arena, types, arg, stack);
|
||||
subs.variables[i] = var;
|
||||
}
|
||||
|
||||
tag_vars.push((tag.clone(), new_slice));
|
||||
tag_vars.push((types[tag_index].clone(), new_slice));
|
||||
}
|
||||
|
||||
sort_and_deduplicate(&mut tag_vars);
|
||||
|
@ -3360,36 +3452,42 @@ fn insert_tags_slow_path<'a>(
|
|||
UnionTags::insert_slices_into_subs(subs, tag_vars)
|
||||
}
|
||||
|
||||
fn type_to_union_tags<'a>(
|
||||
fn type_to_union_tags(
|
||||
subs: &mut Subs,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
arena: &'_ bumpalo::Bump,
|
||||
tags: &'a [(TagName, Vec<Type>)],
|
||||
ext: &'a TypeExtension,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>,
|
||||
types: &mut Types,
|
||||
union_tags: UnionTags,
|
||||
opt_ext_slice: Slice<TypeTag>,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
) -> (UnionTags, Variable) {
|
||||
use bumpalo::collections::Vec;
|
||||
|
||||
let sorted = tags.len() == 1 || sorted_no_duplicates(tags);
|
||||
let (tags, _) = types.union_tag_slices(union_tags);
|
||||
|
||||
match ext {
|
||||
TypeExtension::Closed => {
|
||||
let sorted = tags.len() == 1 || sorted_no_duplicate_tags(&types[tags]);
|
||||
|
||||
debug_assert!(opt_ext_slice.len() <= 1);
|
||||
|
||||
match opt_ext_slice.into_iter().next() {
|
||||
None => {
|
||||
let ext = Variable::EMPTY_TAG_UNION;
|
||||
|
||||
let union_tags = if sorted {
|
||||
insert_tags_fast_path(subs, rank, pools, arena, tags, stack)
|
||||
insert_tags_fast_path(subs, rank, pools, arena, types, union_tags, stack)
|
||||
} else {
|
||||
let tag_vars = Vec::with_capacity_in(tags.len(), arena);
|
||||
insert_tags_slow_path(subs, rank, pools, arena, tags, tag_vars, stack)
|
||||
insert_tags_slow_path(subs, rank, pools, arena, types, union_tags, tag_vars, stack)
|
||||
};
|
||||
|
||||
(union_tags, ext)
|
||||
}
|
||||
TypeExtension::Open(ext) => {
|
||||
Some(ext) => {
|
||||
let mut tag_vars = Vec::with_capacity_in(tags.len(), arena);
|
||||
|
||||
let temp_ext_var = RegisterVariable::with_stack(subs, rank, pools, arena, ext, stack);
|
||||
let temp_ext_var =
|
||||
RegisterVariable::with_stack(subs, rank, pools, arena, types, ext, stack);
|
||||
let (it, ext) = roc_types::types::gather_tags_unsorted_iter(
|
||||
subs,
|
||||
UnionTags::default(),
|
||||
|
@ -3400,9 +3498,9 @@ fn type_to_union_tags<'a>(
|
|||
tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));
|
||||
|
||||
let union_tags = if tag_vars.is_empty() && sorted {
|
||||
insert_tags_fast_path(subs, rank, pools, arena, tags, stack)
|
||||
insert_tags_fast_path(subs, rank, pools, arena, types, union_tags, stack)
|
||||
} else {
|
||||
insert_tags_slow_path(subs, rank, pools, arena, tags, tag_vars, stack)
|
||||
insert_tags_slow_path(subs, rank, pools, arena, types, union_tags, tag_vars, stack)
|
||||
};
|
||||
|
||||
(union_tags, ext)
|
||||
|
@ -3410,16 +3508,18 @@ fn type_to_union_tags<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn create_union_lambda<'a>(
|
||||
fn create_union_lambda(
|
||||
subs: &mut Subs,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
arena: &'_ bumpalo::Bump,
|
||||
types: &mut Types,
|
||||
closure: Symbol,
|
||||
capture_types: &'a [Type],
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>,
|
||||
capture_types: Slice<TypeTag>,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
) -> UnionLambdas {
|
||||
let variable_slice = register_tag_arguments(subs, rank, pools, arena, stack, capture_types);
|
||||
let variable_slice =
|
||||
register_tag_arguments(subs, rank, pools, arena, types, stack, capture_types);
|
||||
let new_variable_slices = SubsSlice::extend_new(&mut subs.variable_slices, [variable_slice]);
|
||||
|
||||
let lambda_name_slice = SubsSlice::extend_new(&mut subs.symbol_names, [closure]);
|
||||
|
|
|
@ -714,10 +714,11 @@ fn get_specialization_lambda_set_ambient_function<P: Phase>(
|
|||
let opaque_home = opaque.module_id();
|
||||
let external_specialized_lset =
|
||||
phase.with_module_abilities_store(opaque_home, |abilities_store| {
|
||||
let impl_key = roc_can::abilities::ImplKey {
|
||||
opaque,
|
||||
ability_member,
|
||||
};
|
||||
let impl_key = roc_can::abilities::ImplKey {
|
||||
opaque,
|
||||
ability_member,
|
||||
};
|
||||
|
||||
let opt_specialization =
|
||||
abilities_store.get_implementation(impl_key);
|
||||
match opt_specialization {
|
||||
|
|
|
@ -2657,10 +2657,10 @@ impl Label for Symbol {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UnionLabels<L> {
|
||||
length: u16,
|
||||
labels_start: u32,
|
||||
variables_start: u32,
|
||||
_marker: std::marker::PhantomData<L>,
|
||||
pub(crate) length: u16,
|
||||
pub(crate) labels_start: u32,
|
||||
pub(crate) values_start: u32,
|
||||
pub(crate) _marker: std::marker::PhantomData<L>,
|
||||
}
|
||||
|
||||
impl<L> Default for UnionLabels<L> {
|
||||
|
@ -2668,7 +2668,7 @@ impl<L> Default for UnionLabels<L> {
|
|||
Self {
|
||||
length: Default::default(),
|
||||
labels_start: Default::default(),
|
||||
variables_start: Default::default(),
|
||||
values_start: Default::default(),
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -2685,7 +2685,7 @@ where
|
|||
return false;
|
||||
}
|
||||
|
||||
let slice = subs.variable_slices[self.variables_start as usize];
|
||||
let slice = subs.variable_slices[self.values_start as usize];
|
||||
slice.length == 1
|
||||
}
|
||||
|
||||
|
@ -2708,7 +2708,7 @@ where
|
|||
Self {
|
||||
length: labels.len() as u16,
|
||||
labels_start: labels.start,
|
||||
variables_start: variables.start,
|
||||
values_start: variables.start,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -2718,7 +2718,7 @@ where
|
|||
}
|
||||
|
||||
pub fn variables(&self) -> SubsSlice<VariableSubsSlice> {
|
||||
SubsSlice::new(self.variables_start, self.length)
|
||||
SubsSlice::new(self.values_start, self.length)
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
|
@ -2764,7 +2764,7 @@ where
|
|||
Self {
|
||||
length: 1,
|
||||
labels_start: idx.index,
|
||||
variables_start: 0,
|
||||
values_start: 0,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -2792,7 +2792,7 @@ where
|
|||
Self {
|
||||
length,
|
||||
labels_start,
|
||||
variables_start,
|
||||
values_start: variables_start,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -3531,7 +3531,7 @@ fn explicit_substitute_union<L: Label>(
|
|||
|
||||
let mut union_tags = tags;
|
||||
debug_assert_eq!(length, union_tags.len());
|
||||
union_tags.variables_start = start;
|
||||
union_tags.values_start = start;
|
||||
union_tags
|
||||
}
|
||||
|
||||
|
@ -4382,7 +4382,7 @@ impl StorageSubs {
|
|||
|
||||
fn offset_tag_union(offsets: &StorageSubsOffsets, mut union_tags: UnionTags) -> UnionTags {
|
||||
union_tags.labels_start += offsets.tag_names;
|
||||
union_tags.variables_start += offsets.variable_slices;
|
||||
union_tags.values_start += offsets.variable_slices;
|
||||
|
||||
union_tags
|
||||
}
|
||||
|
@ -4392,7 +4392,7 @@ impl StorageSubs {
|
|||
mut union_lambdas: UnionLambdas,
|
||||
) -> UnionLambdas {
|
||||
union_lambdas.labels_start += offsets.symbol_names;
|
||||
union_lambdas.variables_start += offsets.variable_slices;
|
||||
union_lambdas.values_start += offsets.variable_slices;
|
||||
|
||||
union_lambdas
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ use crate::subs::{
|
|||
GetSubsSlice, RecordFields, Subs, UnionTags, VarStore, Variable, VariableSubsSlice,
|
||||
};
|
||||
use roc_collections::all::{HumanIndex, ImMap, ImSet, MutMap, MutSet, SendMap};
|
||||
use roc_collections::soa::{Index, Slice};
|
||||
use roc_collections::VecMap;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::called_via::CalledVia;
|
||||
use roc_module::ident::{ForeignSymbol, Ident, Lowercase, TagName};
|
||||
|
@ -295,6 +297,10 @@ impl AbilitySet {
|
|||
pub fn into_sorted_iter(self) -> impl ExactSizeIterator<Item = Symbol> {
|
||||
self.0.into_iter()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<Symbol> for AbilitySet {
|
||||
|
@ -359,6 +365,587 @@ impl std::ops::Neg for Polarity {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct AliasShared {
|
||||
pub symbol: Symbol,
|
||||
pub type_argument_abilities: Slice<AbilitySet>,
|
||||
pub type_argument_regions: Slice<Region>,
|
||||
pub lambda_set_variables: Slice<TypeTag>,
|
||||
pub infer_ext_in_output_variables: Slice<TypeTag>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TypeTag {
|
||||
EmptyRecord,
|
||||
EmptyTagUnion,
|
||||
/// The arguments are implicit
|
||||
Function(
|
||||
/// lambda set
|
||||
Index<TypeTag>,
|
||||
/// return type
|
||||
Index<TypeTag>,
|
||||
),
|
||||
/// Closure arguments are implicit
|
||||
ClosureTag {
|
||||
name: Symbol,
|
||||
ambient_function: Variable,
|
||||
},
|
||||
// type extension is implicit
|
||||
// tag name is in the `single_tag_union_tag_names` map
|
||||
FunctionOrTagUnion(Symbol),
|
||||
UnspecializedLambdaSet {
|
||||
unspecialized: Uls,
|
||||
},
|
||||
DelayedAlias {
|
||||
shared: Index<AliasShared>,
|
||||
},
|
||||
StructuralAlias {
|
||||
shared: Index<AliasShared>,
|
||||
actual: Index<TypeTag>,
|
||||
},
|
||||
OpaqueAlias {
|
||||
shared: Index<AliasShared>,
|
||||
actual: Index<TypeTag>,
|
||||
},
|
||||
HostExposedAlias {
|
||||
shared: Index<AliasShared>,
|
||||
actual_type: Index<TypeTag>,
|
||||
actual_variable: Variable,
|
||||
},
|
||||
|
||||
Apply {
|
||||
symbol: Symbol,
|
||||
// type_argument_types: Slice<TypeTag>, implicit
|
||||
type_argument_regions: Slice<Region>,
|
||||
region: Region, // IDEA: make implicit, final element of `type_argument_regions`
|
||||
},
|
||||
Variable(Variable),
|
||||
RangedNumber(NumericRange),
|
||||
/// A type error, which will code gen to a runtime error
|
||||
/// The problem is at the index of the type tag
|
||||
Erroneous,
|
||||
|
||||
// TypeExtension is implicit in the type slice
|
||||
// it is length zero for closed, length 1 for open
|
||||
TagUnion(UnionTags),
|
||||
RecursiveTagUnion(Variable, UnionTags),
|
||||
Record(RecordFields),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct AsideTypeSlice(Slice<TypeTag>);
|
||||
|
||||
impl AsideTypeSlice {
|
||||
pub fn into_iter(&self) -> impl Iterator<Item = Index<TypeTag>> {
|
||||
self.0.into_iter()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Types {
|
||||
// main storage. Each type is represented by a tag, which is identified by its index.
|
||||
// `tags_slices` is a parallel array (so these two vectors always have the same size), that
|
||||
// allows storing a slice of types. This is used for storing the function argument types, or
|
||||
// the extension parameter of tag unions/records.
|
||||
tags: Vec<TypeTag>,
|
||||
tags_slices: Vec<Slice<TypeTag>>,
|
||||
|
||||
// used to store other slices of types that are not the "main" arguments of a type stored in
|
||||
// `tags_slices`.
|
||||
aside_types_slices: Vec<Slice<TypeTag>>,
|
||||
|
||||
// region info where appropriate (retained for generating error messages)
|
||||
regions: Vec<Region>,
|
||||
|
||||
// tag unions
|
||||
tag_names: Vec<TagName>,
|
||||
|
||||
// records
|
||||
field_types: Vec<RecordField<()>>,
|
||||
field_names: Vec<Lowercase>,
|
||||
|
||||
// aliases
|
||||
type_arg_abilities: Vec<AbilitySet>, // TODO: structural sharing for `AbilitySet`s themselves
|
||||
aliases: Vec<AliasShared>,
|
||||
|
||||
// these tag types are relatively rare, and so we store them in a way that reduces space, at
|
||||
// the cost of slightly higher lookup time
|
||||
problems: VecMap<Index<TypeTag>, Problem>,
|
||||
single_tag_union_tag_names: VecMap<Index<TypeTag>, TagName>,
|
||||
}
|
||||
|
||||
impl Default for Types {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Types {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
// tags.len() == tags_slices.len()
|
||||
tags: vec![TypeTag::EmptyRecord, TypeTag::EmptyTagUnion],
|
||||
tags_slices: vec![Default::default(), Default::default()],
|
||||
|
||||
aside_types_slices: Default::default(),
|
||||
|
||||
regions: Default::default(),
|
||||
tag_names: Default::default(),
|
||||
field_types: Default::default(),
|
||||
field_names: Default::default(),
|
||||
type_arg_abilities: Default::default(),
|
||||
aliases: Default::default(),
|
||||
problems: Default::default(),
|
||||
single_tag_union_tag_names: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type_arguments(&self, tag: Index<TypeTag>) -> Slice<TypeTag> {
|
||||
self.tags_slices[tag.index()]
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn get_tag_name(&self, typ: &Index<TypeTag>) -> &TagName {
|
||||
self.single_tag_union_tag_names
|
||||
.get(typ)
|
||||
.expect("typ is not a single tag union")
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn get_problem(&self, typ: &Index<TypeTag>) -> &Problem {
|
||||
self.problems.get(typ).expect("typ is not an error")
|
||||
}
|
||||
|
||||
pub fn record_fields_slices(
|
||||
&self,
|
||||
fields: RecordFields,
|
||||
) -> (Slice<Lowercase>, Slice<RecordField<()>>, Slice<TypeTag>) {
|
||||
let RecordFields {
|
||||
length,
|
||||
field_names_start,
|
||||
variables_start,
|
||||
field_types_start,
|
||||
} = fields;
|
||||
|
||||
let names = Slice::new(field_names_start, length);
|
||||
let fields = Slice::new(field_types_start, length);
|
||||
let tys = Slice::new(variables_start, length);
|
||||
|
||||
(names, fields, tys)
|
||||
}
|
||||
|
||||
pub fn union_tag_slices(&self, union: UnionTags) -> (Slice<TagName>, Slice<AsideTypeSlice>) {
|
||||
let UnionTags {
|
||||
length,
|
||||
labels_start,
|
||||
values_start,
|
||||
_marker,
|
||||
} = union;
|
||||
|
||||
let tags = Slice::new(labels_start, length);
|
||||
let payload_slices = Slice::new(values_start, length);
|
||||
|
||||
(tags, payload_slices)
|
||||
}
|
||||
|
||||
fn reserve_type_tags(&mut self, length: usize) -> Slice<TypeTag> {
|
||||
use std::iter::repeat;
|
||||
|
||||
debug_assert_eq!(self.tags.len(), self.tags_slices.len());
|
||||
|
||||
self.tags_slices
|
||||
.extend(repeat(Slice::default()).take(length));
|
||||
|
||||
Slice::extend_new(&mut self.tags, repeat(TypeTag::EmptyRecord).take(length))
|
||||
}
|
||||
|
||||
fn reserve_type_tag(&mut self) -> Index<TypeTag> {
|
||||
debug_assert_eq!(self.tags.len(), self.tags_slices.len());
|
||||
|
||||
self.tags_slices.push(Slice::default());
|
||||
|
||||
Index::push_new(&mut self.tags, TypeTag::EmptyRecord)
|
||||
}
|
||||
|
||||
fn set_type_tag(&mut self, index: Index<TypeTag>, tag: TypeTag, type_slice: Slice<TypeTag>) {
|
||||
debug_assert_eq!(self.tags.len(), self.tags_slices.len());
|
||||
|
||||
self.tags[index.index()] = tag;
|
||||
self.tags_slices[index.index()] = type_slice;
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn from_old_type_slice(&mut self, old: &[Type]) -> Slice<TypeTag> {
|
||||
let slice = self.reserve_type_tags(old.len());
|
||||
|
||||
for (index, argument) in slice.into_iter().zip(old) {
|
||||
self.from_old_type_at(index, argument);
|
||||
}
|
||||
|
||||
slice
|
||||
}
|
||||
|
||||
fn tag_union_help(
|
||||
&mut self,
|
||||
tags: &[(TagName, Vec<Type>)],
|
||||
extension: &TypeExtension,
|
||||
) -> (UnionTags, Slice<TypeTag>) {
|
||||
let tag_names_slice =
|
||||
Slice::extend_new(&mut self.tag_names, tags.iter().map(|(n, _)| n.clone()));
|
||||
|
||||
// Store the payload slices in the aside buffer
|
||||
let type_slices = Slice::extend_new(
|
||||
&mut self.aside_types_slices,
|
||||
std::iter::repeat(Slice::default()).take(tags.len()),
|
||||
);
|
||||
|
||||
for (slice_index, (_, types)) in type_slices.indices().zip(tags) {
|
||||
self.aside_types_slices[slice_index] = self.from_old_type_slice(types);
|
||||
}
|
||||
|
||||
let union_tags = UnionTags {
|
||||
length: tags.len() as u16,
|
||||
labels_start: tag_names_slice.start() as u32,
|
||||
values_start: type_slices.start() as u32,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
let type_slice = match extension {
|
||||
TypeExtension::Open(ext) => self.from_old_type(ext).as_slice(),
|
||||
TypeExtension::Closed => Slice::default(),
|
||||
};
|
||||
|
||||
(union_tags, type_slice)
|
||||
}
|
||||
|
||||
fn alias_shared_help(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
type_arguments: &[OptAbleType],
|
||||
lambda_set_variables: &[LambdaSet],
|
||||
infer_ext_in_output_types: &[Type],
|
||||
) -> AliasShared {
|
||||
let lambda_set_slice = {
|
||||
let slice = self.reserve_type_tags(lambda_set_variables.len());
|
||||
|
||||
for (index, argument) in slice.into_iter().zip(lambda_set_variables) {
|
||||
self.from_old_type_at(index, &argument.0);
|
||||
}
|
||||
|
||||
Slice::new(slice.start() as _, slice.len() as _)
|
||||
};
|
||||
|
||||
let infer_ext_in_output_slice = {
|
||||
let slice = self.reserve_type_tags(infer_ext_in_output_types.len());
|
||||
|
||||
for (index, ty) in slice.into_iter().zip(infer_ext_in_output_types) {
|
||||
self.from_old_type_at(index, ty);
|
||||
}
|
||||
|
||||
Slice::new(slice.start() as _, slice.len() as _)
|
||||
};
|
||||
|
||||
let type_argument_abilities = Slice::extend_new(
|
||||
&mut self.type_arg_abilities,
|
||||
type_arguments
|
||||
.iter()
|
||||
.map(|a| a.opt_abilities.as_ref().cloned().unwrap_or_default()),
|
||||
);
|
||||
|
||||
// TODO: populate correctly
|
||||
let type_argument_regions = Slice::extend_new(
|
||||
&mut self.regions,
|
||||
std::iter::repeat(Region::zero()).take(type_arguments.len()),
|
||||
);
|
||||
|
||||
AliasShared {
|
||||
symbol,
|
||||
type_argument_abilities,
|
||||
type_argument_regions,
|
||||
lambda_set_variables: lambda_set_slice,
|
||||
infer_ext_in_output_variables: infer_ext_in_output_slice,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_old_type(&mut self, old: &Type) -> Index<TypeTag> {
|
||||
let index = self.reserve_type_tag();
|
||||
self.from_old_type_at(index, old);
|
||||
index
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn from_old_type_at(&mut self, index: Index<TypeTag>, old: &Type) {
|
||||
match old {
|
||||
Type::EmptyRec => self.set_type_tag(index, TypeTag::EmptyRecord, Slice::default()),
|
||||
Type::EmptyTagUnion => {
|
||||
self.set_type_tag(index, TypeTag::EmptyTagUnion, Slice::default())
|
||||
}
|
||||
Type::Function(arguments, lambda_set, return_type) => {
|
||||
let argument_slice = self.from_old_type_slice(arguments);
|
||||
|
||||
let tag = TypeTag::Function(
|
||||
self.from_old_type(lambda_set),
|
||||
self.from_old_type(return_type),
|
||||
);
|
||||
|
||||
self.set_type_tag(index, tag, argument_slice)
|
||||
}
|
||||
Type::Apply(symbol, arguments, region) => {
|
||||
let type_argument_regions =
|
||||
Slice::extend_new(&mut self.regions, arguments.iter().map(|t| t.region));
|
||||
|
||||
let type_slice = {
|
||||
let slice = self.reserve_type_tags(arguments.len());
|
||||
|
||||
for (index, argument) in slice.into_iter().zip(arguments) {
|
||||
self.from_old_type_at(index, &argument.value);
|
||||
}
|
||||
|
||||
slice
|
||||
};
|
||||
|
||||
self.set_type_tag(
|
||||
index,
|
||||
TypeTag::Apply {
|
||||
symbol: *symbol,
|
||||
type_argument_regions,
|
||||
region: *region,
|
||||
},
|
||||
type_slice,
|
||||
)
|
||||
}
|
||||
Type::TagUnion(tags, extension) => {
|
||||
let (union_tags, type_slice) = self.tag_union_help(tags, extension);
|
||||
|
||||
self.set_type_tag(index, TypeTag::TagUnion(union_tags), type_slice)
|
||||
}
|
||||
Type::RecursiveTagUnion(rec_var, tags, extension) => {
|
||||
let (union_tags, type_slice) = self.tag_union_help(tags, extension);
|
||||
let tag = TypeTag::RecursiveTagUnion(*rec_var, union_tags);
|
||||
|
||||
self.set_type_tag(index, tag, type_slice)
|
||||
}
|
||||
Type::FunctionOrTagUnion(tag_name, symbol, extension) => {
|
||||
let type_slice = match extension {
|
||||
TypeExtension::Open(ext) => self.from_old_type(ext).as_slice(),
|
||||
TypeExtension::Closed => Slice::default(),
|
||||
};
|
||||
|
||||
self.single_tag_union_tag_names
|
||||
.insert(index, tag_name.clone());
|
||||
|
||||
let tag = TypeTag::FunctionOrTagUnion(*symbol);
|
||||
self.set_type_tag(index, tag, type_slice)
|
||||
}
|
||||
Type::UnspecializedLambdaSet { unspecialized } => {
|
||||
let tag = TypeTag::UnspecializedLambdaSet {
|
||||
unspecialized: *unspecialized,
|
||||
};
|
||||
self.set_type_tag(index, tag, Slice::default())
|
||||
}
|
||||
Type::Record(fields, extension) => {
|
||||
let type_slice = match extension {
|
||||
TypeExtension::Open(ext) => self.from_old_type(ext).as_slice(),
|
||||
TypeExtension::Closed => Slice::default(),
|
||||
};
|
||||
|
||||
// should we sort at this point?
|
||||
let field_type_slice = {
|
||||
let slice = self.reserve_type_tags(fields.len());
|
||||
|
||||
for (index, argument) in slice.into_iter().zip(fields.values()) {
|
||||
self.from_old_type_at(index, argument.as_inner());
|
||||
}
|
||||
|
||||
slice
|
||||
};
|
||||
|
||||
let field_types = Slice::extend_new(
|
||||
&mut self.field_types,
|
||||
fields.values().map(|f| f.map(|_| ())),
|
||||
);
|
||||
|
||||
let field_names = Slice::extend_new(&mut self.field_names, fields.keys().cloned());
|
||||
|
||||
let record_fields = RecordFields {
|
||||
length: fields.len() as u16,
|
||||
field_names_start: field_names.start() as u32,
|
||||
variables_start: field_type_slice.start() as u32,
|
||||
field_types_start: field_types.start() as u32,
|
||||
};
|
||||
|
||||
let tag = TypeTag::Record(record_fields);
|
||||
self.set_type_tag(index, tag, type_slice)
|
||||
}
|
||||
Type::ClosureTag {
|
||||
name,
|
||||
captures,
|
||||
ambient_function,
|
||||
} => {
|
||||
let type_slice = self.from_old_type_slice(captures);
|
||||
|
||||
let tag = TypeTag::ClosureTag {
|
||||
name: *name,
|
||||
ambient_function: *ambient_function,
|
||||
};
|
||||
self.set_type_tag(index, tag, type_slice)
|
||||
}
|
||||
|
||||
Type::DelayedAlias(AliasCommon {
|
||||
symbol,
|
||||
type_arguments,
|
||||
lambda_set_variables,
|
||||
infer_ext_in_output_types,
|
||||
}) => {
|
||||
let type_argument_regions =
|
||||
Slice::extend_new(&mut self.regions, type_arguments.iter().map(|t| t.region));
|
||||
|
||||
let type_arguments_slice = {
|
||||
let slice = self.reserve_type_tags(type_arguments.len());
|
||||
|
||||
for (index, argument) in slice.into_iter().zip(type_arguments) {
|
||||
self.from_old_type_at(index, &argument.value.typ);
|
||||
}
|
||||
|
||||
slice
|
||||
};
|
||||
|
||||
let lambda_set_slice = {
|
||||
let slice = self.reserve_type_tags(lambda_set_variables.len());
|
||||
|
||||
let it = slice.into_iter().zip(lambda_set_variables);
|
||||
for (index, argument) in it {
|
||||
self.from_old_type_at(index, &argument.0);
|
||||
}
|
||||
|
||||
Slice::new(slice.start() as _, slice.len() as _)
|
||||
};
|
||||
|
||||
let infer_ext_in_output_slice = {
|
||||
let slice = self.reserve_type_tags(infer_ext_in_output_types.len());
|
||||
|
||||
let it = slice.into_iter().zip(infer_ext_in_output_types);
|
||||
for (index, argument) in it {
|
||||
self.from_old_type_at(index, argument);
|
||||
}
|
||||
|
||||
Slice::new(slice.start() as _, slice.len() as _)
|
||||
};
|
||||
|
||||
let type_argument_abilities = Slice::extend_new(
|
||||
&mut self.type_arg_abilities,
|
||||
type_arguments
|
||||
.iter()
|
||||
.map(|a| a.value.opt_abilities.as_ref().cloned().unwrap_or_default()),
|
||||
);
|
||||
|
||||
let alias_shared = AliasShared {
|
||||
symbol: *symbol,
|
||||
type_argument_abilities,
|
||||
type_argument_regions,
|
||||
lambda_set_variables: lambda_set_slice,
|
||||
infer_ext_in_output_variables: infer_ext_in_output_slice,
|
||||
};
|
||||
|
||||
let shared = Index::push_new(&mut self.aliases, alias_shared);
|
||||
|
||||
let tag = TypeTag::DelayedAlias { shared };
|
||||
|
||||
self.set_type_tag(index, tag, type_arguments_slice)
|
||||
}
|
||||
Type::Alias {
|
||||
symbol,
|
||||
type_arguments,
|
||||
lambda_set_variables,
|
||||
infer_ext_in_output_types,
|
||||
actual,
|
||||
kind,
|
||||
} => {
|
||||
let type_arguments_slice = {
|
||||
let slice = self.reserve_type_tags(type_arguments.len());
|
||||
|
||||
for (index, argument) in slice.into_iter().zip(type_arguments) {
|
||||
self.from_old_type_at(index, &argument.typ);
|
||||
}
|
||||
|
||||
slice
|
||||
};
|
||||
|
||||
let alias_shared = self.alias_shared_help(
|
||||
*symbol,
|
||||
type_arguments,
|
||||
lambda_set_variables,
|
||||
infer_ext_in_output_types,
|
||||
);
|
||||
|
||||
let shared = Index::push_new(&mut self.aliases, alias_shared);
|
||||
let actual = self.from_old_type(actual);
|
||||
|
||||
let tag = match kind {
|
||||
AliasKind::Structural => TypeTag::StructuralAlias { shared, actual },
|
||||
AliasKind::Opaque => TypeTag::OpaqueAlias { shared, actual },
|
||||
};
|
||||
|
||||
self.set_type_tag(index, tag, type_arguments_slice)
|
||||
}
|
||||
|
||||
Type::HostExposedAlias {
|
||||
name,
|
||||
type_arguments,
|
||||
lambda_set_variables,
|
||||
actual_var,
|
||||
actual,
|
||||
} => {
|
||||
let type_arguments_slice = self.from_old_type_slice(type_arguments);
|
||||
|
||||
let lambda_set_slice = {
|
||||
let slice = self.reserve_type_tags(lambda_set_variables.len());
|
||||
|
||||
for (index, argument) in slice.into_iter().zip(lambda_set_variables) {
|
||||
self.from_old_type_at(index, &argument.0);
|
||||
}
|
||||
|
||||
Slice::new(slice.start() as _, slice.len() as _)
|
||||
};
|
||||
|
||||
let alias_shared = AliasShared {
|
||||
symbol: *name,
|
||||
type_argument_abilities: Slice::default(),
|
||||
type_argument_regions: Slice::default(),
|
||||
lambda_set_variables: lambda_set_slice,
|
||||
infer_ext_in_output_variables: Slice::default(),
|
||||
};
|
||||
|
||||
let tag = TypeTag::HostExposedAlias {
|
||||
shared: Index::push_new(&mut self.aliases, alias_shared),
|
||||
actual_type: self.from_old_type(actual),
|
||||
actual_variable: *actual_var,
|
||||
};
|
||||
|
||||
self.set_type_tag(index, tag, type_arguments_slice)
|
||||
}
|
||||
Type::Variable(var) => {
|
||||
self.set_type_tag(index, TypeTag::Variable(*var), Slice::default())
|
||||
}
|
||||
Type::RangedNumber(range) => {
|
||||
self.set_type_tag(index, TypeTag::RangedNumber(*range), Slice::default())
|
||||
}
|
||||
Type::Erroneous(problem) => {
|
||||
self.problems.insert(index, problem.clone());
|
||||
self.set_type_tag(index, TypeTag::Erroneous, Slice::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Polarity {
|
||||
pub const OF_VALUE: Polarity = Polarity::Pos;
|
||||
|
||||
|
@ -373,6 +960,68 @@ impl Polarity {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_types_index {
|
||||
($($field:ident, $ty:ty)*) => {$(
|
||||
impl std::ops::Index<Index<$ty>> for Types {
|
||||
type Output = $ty;
|
||||
|
||||
fn index(&self, index: Index<$ty>) -> &Self::Output {
|
||||
// Validate that the types line up, so you can't accidentally
|
||||
// index into the wrong array.
|
||||
let _: &Vec<$ty> = &self.$field;
|
||||
|
||||
&self.$field[index.index()]
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
macro_rules! impl_types_index_slice {
|
||||
($($field:ident, $ty:ty)*) => {$(
|
||||
impl std::ops::Index<Slice<$ty>> for Types {
|
||||
type Output = [$ty];
|
||||
|
||||
fn index(&self, slice: Slice<$ty>) -> &Self::Output {
|
||||
// Validate that the types line up, so you can't accidentally
|
||||
// index into the wrong array.
|
||||
let _: &Vec<$ty> = &self.$field;
|
||||
|
||||
&self.$field[slice.indices()]
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
impl_types_index! {
|
||||
tags, TypeTag
|
||||
aliases, AliasShared
|
||||
type_arg_abilities, AbilitySet
|
||||
regions, Region
|
||||
tag_names, TagName
|
||||
field_types, RecordField<()>
|
||||
field_names, Lowercase
|
||||
}
|
||||
|
||||
impl_types_index_slice! {
|
||||
tag_names, TagName
|
||||
}
|
||||
|
||||
impl std::ops::Index<Index<AsideTypeSlice>> for Types {
|
||||
type Output = Slice<TypeTag>;
|
||||
|
||||
fn index(&self, slice: Index<AsideTypeSlice>) -> &Self::Output {
|
||||
&self.aside_types_slices[slice.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Index<Slice<AsideTypeSlice>> for Types {
|
||||
type Output = [Slice<TypeTag>];
|
||||
|
||||
fn index(&self, slice: Slice<AsideTypeSlice>) -> &Self::Output {
|
||||
&self.aside_types_slices[slice.indices()]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum Type {
|
||||
EmptyRec,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue