From 93b9130edf5534260b5a127fe425c95e6399b2ab Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 21 Oct 2022 13:11:47 +0200 Subject: [PATCH 01/11] Type soa and conversion from existing data structure --- crates/compiler/collections/src/soa.rs | 15 +- crates/compiler/types/src/subs.rs | 26 +- crates/compiler/types/src/types.rs | 485 +++++++++++++++++++++++++ 3 files changed, 512 insertions(+), 14 deletions(-) diff --git a/crates/compiler/collections/src/soa.rs b/crates/compiler/collections/src/soa.rs index 8549ea62b5..4b2f94b44b 100644 --- a/crates/compiler/collections/src/soa.rs +++ b/crates/compiler/collections/src/soa.rs @@ -1,11 +1,24 @@ use std::usize; -#[derive(PartialEq, Eq)] pub struct Index { index: u32, _marker: std::marker::PhantomData, } +impl Eq for Index {} + +impl PartialEq for Index { + fn eq(&self, other: &Self) -> bool { + self.index == other.index + } +} + +impl std::hash::Hash for Index { + fn hash(&self, state: &mut H) { + self.index.hash(state); + } +} + impl Clone for Index { fn clone(&self) -> Self { Self { diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 1db59353dc..709cf3e643 100644 --- a/crates/compiler/types/src/subs.rs +++ b/crates/compiler/types/src/subs.rs @@ -2657,10 +2657,10 @@ impl Label for Symbol { #[derive(Clone, Debug)] pub struct UnionLabels { - length: u16, - labels_start: u32, - variables_start: u32, - _marker: std::marker::PhantomData, + pub(crate) length: u16, + pub(crate) labels_start: u32, + pub(crate) values_start: u32, + pub(crate) _marker: std::marker::PhantomData, } impl Default for UnionLabels { @@ -2668,7 +2668,7 @@ impl Default for UnionLabels { 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 { - 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( 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 } diff --git a/crates/compiler/types/src/types.rs b/crates/compiler/types/src/types.rs index 943ca81a98..d8c8d44724 100644 --- a/crates/compiler/types/src/types.rs +++ b/crates/compiler/types/src/types.rs @@ -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}; @@ -359,6 +361,489 @@ impl std::ops::Neg for Polarity { } } +#[allow(dead_code)] +struct AliasShared { + symbol: Symbol, + type_argument_abilities: Slice>, + type_argument_regions: Slice, + lambda_set_variables: Slice, + infer_ext_in_output_variables: Slice, +} + +#[derive(Debug, Clone)] +#[allow(dead_code)] +enum TypeTag { + EmptyRecord, + EmptyTagUnion, + Function(Index, Index), + 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, + }, + StructuralAlias { + shared: Index, + actual: Index, + }, + OpaqueAlias { + shared: Index, + actual: Index, + }, + HostExposedAlias { + shared: Index, + actual_type: Index, + actual_variable: Variable, + }, + + Apply { + symbol: Symbol, + // type_argument_types: Slice, implicit + type_argument_regions: Slice, + 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 + 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), +} + +#[allow(dead_code)] +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, + tags_slices: Vec>, + + // region info where appropriate (retained for generating error messages) + regions: Vec, + + // tag unions + tag_names: Vec, + + // records + field_types: Vec>, + field_names: Vec, + + // aliases + type_arg_abilities: Vec>, // TODO: structural sharing for `AbilitySet`s themselves + aliases: Vec, + + // 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, Problem>, + single_tag_union_tag_names: VecMap, TagName>, +} + +#[allow(dead_code)] +impl Types { + const EMPTY_RECORD: Index = Index::new(0); + const EMPTY_TAG_UNION: Index = Index::new(1); + + fn reserve_type_tags(&mut self, length: usize) -> Slice { + 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 { + 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 push_type_tag(&mut self, tag: TypeTag, type_slice: Slice) -> Index { + debug_assert_eq!(self.tags.len(), self.tags_slices.len()); + + self.tags_slices.push(type_slice); + + Index::push_new(&mut self.tags, tag) + } + + fn set_type_tag(&mut self, index: Index, tag: TypeTag, type_slice: Slice) { + debug_assert_eq!(self.tags.len(), self.tags_slices.len()); + + self.tags[index.index()] = tag; + self.tags_slices[index.index()] = type_slice; + } + + fn from_old_type_slice(&mut self, old: &[Type]) -> Slice { + 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)], + extension: &TypeExtension, + ) -> (UnionTags, Slice) { + let tag_names_slice = + Slice::extend_new(&mut self.tag_names, tags.iter().map(|(n, _)| n.clone())); + + let type_slices = Slice::extend_new( + &mut self.tags_slices, + std::iter::repeat(Slice::default()).take(tags.len()), + ); + + for (slice_index, (_, types)) in type_slices.indices().zip(tags) { + self.tags_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.clone()), + ); + + AliasShared { + symbol, + type_argument_abilities, + type_argument_regions: Slice::default(), + lambda_set_variables: lambda_set_slice, + infer_ext_in_output_variables: infer_ext_in_output_slice, + } + } + + pub fn from_old_type(&mut self, old: &Type) -> Index { + let index = self.reserve_type_tag(); + self.from_old_type_at(index, old); + index + } + + fn from_old_type_at(&mut self, index: Index, 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, + }) => { + // pub symbol: Symbol, + // pub type_arguments: Vec>, + // pub lambda_set_variables: Vec, + + 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.clone()), + ); + + 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::StructuralAlias { 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; From dad9a8e537a7e51dacf4ee992328c107531e6d47 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Wed, 2 Nov 2022 17:08:55 -0500 Subject: [PATCH 02/11] Pass Types SoA repr in types to Variable translation --- crates/compiler/solve/src/solve.rs | 12 +++++++++- crates/compiler/types/src/types.rs | 36 +++++++++++++++++------------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index d66181fc08..990549ac6a 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -34,7 +34,7 @@ use roc_types::subs::{ use roc_types::types::Type::{self, *}; use roc_types::types::{ gather_fields_unsorted_iter, AliasCommon, AliasKind, Category, OptAbleType, OptAbleVar, - Polarity, Reason, RecordField, TypeExtension, Uls, + Polarity, Reason, RecordField, TypeExtension, 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: &Types, symbol: Symbol, alias_variables: AliasVariables, ) -> (Variable, AliasKind) { @@ -425,6 +426,7 @@ impl Aliases { obligation_cache, arena, self, + types, &typ, false, ); @@ -450,6 +452,7 @@ impl Aliases { obligation_cache, arena, self, + types, &t, false, ); @@ -2368,6 +2371,7 @@ pub(crate) fn type_to_var( *var } else { let mut arena = take_scratchpad(); + let types = Types::new(); let var = type_to_variable( subs, @@ -2378,6 +2382,7 @@ pub(crate) fn type_to_var( obligation_cache, &arena, aliases, + &types, typ, false, ); @@ -2536,6 +2541,7 @@ fn type_to_variable<'a>( obligation_cache: &mut ObligationCache, arena: &'a bumpalo::Bump, aliases: &mut Aliases, + types: &Types, typ: &Type, // Helpers for instantiating ambient functions of lambda set variables from type aliases. is_alias_lambda_set_arg: bool, @@ -2813,6 +2819,7 @@ fn type_to_variable<'a>( obligation_cache, arena, aliases, + types, &ls.0, true, ); @@ -2842,6 +2849,7 @@ fn type_to_variable<'a>( abilities_store, obligation_cache, arena, + types, *symbol, alias_variables, ); @@ -2946,6 +2954,7 @@ fn type_to_variable<'a>( obligation_cache, arena, aliases, + types, &ls.0, true, ); @@ -2970,6 +2979,7 @@ fn type_to_variable<'a>( obligation_cache, arena, aliases, + types, alias_type, false, ); diff --git a/crates/compiler/types/src/types.rs b/crates/compiler/types/src/types.rs index d8c8d44724..ac817df803 100644 --- a/crates/compiler/types/src/types.rs +++ b/crates/compiler/types/src/types.rs @@ -362,7 +362,7 @@ impl std::ops::Neg for Polarity { } #[allow(dead_code)] -struct AliasShared { +pub struct AliasShared { symbol: Symbol, type_argument_abilities: Slice>, type_argument_regions: Slice, @@ -371,8 +371,7 @@ struct AliasShared { } #[derive(Debug, Clone)] -#[allow(dead_code)] -enum TypeTag { +pub enum TypeTag { EmptyRecord, EmptyTagUnion, Function(Index, Index), @@ -421,8 +420,7 @@ enum TypeTag { Record(RecordFields), } -#[allow(dead_code)] -struct Types { +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 @@ -450,10 +448,24 @@ struct Types { single_tag_union_tag_names: VecMap, TagName>, } -#[allow(dead_code)] impl Types { - const EMPTY_RECORD: Index = Index::new(0); - const EMPTY_TAG_UNION: Index = Index::new(1); + pub const EMPTY_RECORD: Index = Index::new(0); + pub const EMPTY_TAG_UNION: Index = Index::new(1); + + pub fn new() -> Self { + Self { + tags: vec![TypeTag::EmptyRecord, TypeTag::EmptyTagUnion], + tags_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(), + } + } fn reserve_type_tags(&mut self, length: usize) -> Slice { use std::iter::repeat; @@ -474,14 +486,6 @@ impl Types { Index::push_new(&mut self.tags, TypeTag::EmptyRecord) } - fn push_type_tag(&mut self, tag: TypeTag, type_slice: Slice) -> Index { - debug_assert_eq!(self.tags.len(), self.tags_slices.len()); - - self.tags_slices.push(type_slice); - - Index::push_new(&mut self.tags, tag) - } - fn set_type_tag(&mut self, index: Index, tag: TypeTag, type_slice: Slice) { debug_assert_eq!(self.tags.len(), self.tags_slices.len()); From 5da11d7fddb2c8dcd102ed713af466e4b5c7835d Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Wed, 2 Nov 2022 17:17:39 -0500 Subject: [PATCH 03/11] Index into Types --- crates/compiler/types/src/types.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/compiler/types/src/types.rs b/crates/compiler/types/src/types.rs index ac817df803..beb3d8d3cc 100644 --- a/crates/compiler/types/src/types.rs +++ b/crates/compiler/types/src/types.rs @@ -862,6 +862,14 @@ impl Polarity { } } +impl std::ops::Index> for Types { + type Output = TypeTag; + + fn index(&self, index: Index) -> &Self::Output { + &self.tags[index.index()] + } +} + #[derive(PartialEq, Eq)] pub enum Type { EmptyRec, From 58020a55d63df4473587148e9552215232438e1e Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 7 Nov 2022 15:11:53 -0600 Subject: [PATCH 04/11] Type to variable through Types SoA --- crates/compiler/solve/src/solve.rs | 481 +++++++++++++++++------------ crates/compiler/types/src/types.rs | 175 +++++++++-- 2 files changed, 439 insertions(+), 217 deletions(-) diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index 990549ac6a..d6f5855dfa 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -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; @@ -33,8 +34,8 @@ use roc_types::subs::{ }; use roc_types::types::Type::{self, *}; use roc_types::types::{ - gather_fields_unsorted_iter, AliasCommon, AliasKind, Category, OptAbleType, OptAbleVar, - Polarity, Reason, RecordField, TypeExtension, Types, Uls, + gather_fields_unsorted_iter, AliasCommon, AliasKind, AliasShared, Category, OptAbleType, + OptAbleVar, Polarity, Reason, RecordField, TypeExtension, TypeTag, Types, Uls, }; use roc_unify::unify::{ unify, unify_introduced_ability_specialization, Env as UEnv, Mode, Obligated, @@ -300,7 +301,7 @@ impl Aliases { abilities_store: &AbilitiesStore, obligation_cache: &mut ObligationCache, arena: &bumpalo::Bump, - types: &Types, + types: &mut Types, symbol: Symbol, alias_variables: AliasVariables, ) -> (Variable, AliasKind) { @@ -417,6 +418,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, @@ -427,7 +429,7 @@ impl Aliases { arena, self, types, - &typ, + typ, false, ); (alias_variable, kind) @@ -443,6 +445,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, @@ -453,7 +456,7 @@ impl Aliases { arena, self, types, - &t, + t_index, false, ); @@ -2371,7 +2374,8 @@ pub(crate) fn type_to_var( *var } else { let mut arena = take_scratchpad(); - let types = Types::new(); + let mut types = Types::new(); + let typ = types.from_old_type(typ); let var = type_to_variable( subs, @@ -2382,7 +2386,7 @@ pub(crate) fn type_to_var( obligation_cache, &arena, aliases, - &types, + &mut types, typ, false, ); @@ -2408,30 +2412,21 @@ impl RegisterVariable { rank: Rank, pools: &mut Pools, arena: &'_ bumpalo::Bump, - typ: &Type, + types: &mut Types, + typ: Index, ) -> 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); @@ -2454,10 +2449,11 @@ impl RegisterVariable { rank: Rank, pools: &mut Pools, arena: &'_ bumpalo::Bump, - typ: &'a Type, - stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>, + types: &mut Types, + typ: Index, + 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(); @@ -2523,9 +2519,9 @@ impl AmbientFunctionPolicy { } #[derive(Debug)] -enum TypeToVar<'a> { +enum TypeToVar { Defer { - typ: &'a Type, + typ: Index, destination: Variable, ambient_function: AmbientFunctionPolicy, }, @@ -2541,8 +2537,8 @@ fn type_to_variable<'a>( obligation_cache: &mut ObligationCache, arena: &'a bumpalo::Bump, aliases: &mut Aliases, - types: &Types, - typ: &Type, + types: &mut Types, + typ: Index, // Helpers for instantiating ambient functions of lambda set variables from type aliases. is_alias_lambda_set_arg: bool, ) -> Variable { @@ -2553,7 +2549,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. @@ -2585,23 +2581,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) @@ -2609,11 +2613,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, @@ -2621,7 +2626,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) @@ -2629,7 +2634,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. @@ -2641,7 +2646,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, }; @@ -2656,9 +2661,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; } @@ -2671,31 +2679,34 @@ 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) = @@ -2716,21 +2727,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( @@ -2744,30 +2762,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 { @@ -2779,34 +2800,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), opt_ability) 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 let Some(abilities) = &types[opt_ability] { + let arg_region = types[arg_region]; + bind_to_abilities.push((Loc::at(arg_region, copy_var), opt_ability)); } } 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. @@ -2820,14 +2850,14 @@ fn type_to_variable<'a>( arena, aliases, types, - &ls.0, + 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; @@ -2850,29 +2880,38 @@ fn type_to_variable<'a>( obligation_cache, arena, types, - *symbol, + 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(); @@ -2880,28 +2919,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), opt_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 let Some(abilities) = &types[opt_abilities] { + let region = types[region]; + bind_to_abilities.push((Loc::at(region, copy_var), opt_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; @@ -2915,33 +2955,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, + } = 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. @@ -2955,7 +3004,7 @@ fn type_to_variable<'a>( arena, aliases, types, - &ls.0, + ls, true, ); subs.variables[target_index] = copy_var; @@ -2986,7 +3035,7 @@ fn type_to_variable<'a>( // 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, @@ -2997,16 +3046,15 @@ fn type_to_variable<'a>( // 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()); - let content = Content::Structure(FlatType::Erroneous(problem_index)); + Erroneous => { + let content = Content::Error; register_with_known_var(subs, destination, rank, pools, content) } @@ -3014,6 +3062,11 @@ fn type_to_variable<'a>( } for (Loc { value: var, region }, abilities) in bind_to_abilities { + // TODO: SoA represent as Some>, not the other way + let abilities = types[abilities] + .as_ref() + .expect("should only have been added if it was Some"); + match *subs.get_content_unchecked(var) { Content::RigidVar(a) => { // TODO(multi-abilities): check run cache @@ -3096,23 +3149,37 @@ fn roc_result_to_var<'a>( 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, + 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); @@ -3158,13 +3225,13 @@ where } } -fn sorted_no_duplicates(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 { @@ -3200,10 +3267,10 @@ fn sort_and_deduplicate(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(slice: &[(TagName, T)], subs: &mut Subs) -> Option> { +fn find_tag_name_run(slice: &[TagName], subs: &mut Subs) -> Option> { use std::cmp::Ordering; - let tag_name = &slice.get(0)?.0; + let tag_name = slice.get(0)?; let mut result = None; @@ -3225,7 +3292,7 @@ fn find_tag_name_run(slice: &[(TagName, T)], subs: &mut Subs) -> Option(slice: &[(TagName, T)], subs: &mut Subs) -> Option { 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; } @@ -3264,17 +3331,19 @@ fn register_tag_arguments<'a>( 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, ) -> 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; } @@ -3288,12 +3357,20 @@ fn insert_tags_fast_path<'a>( rank: Rank, pools: &mut Pools, arena: &'_ bumpalo::Bump, - tags: &'a [(TagName, Vec)], - 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]); @@ -3303,7 +3380,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()), @@ -3314,13 +3391,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) @@ -3330,13 +3408,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) @@ -3349,20 +3429,25 @@ fn insert_tags_slow_path<'a>( rank: Rank, pools: &mut Pools, arena: &'_ bumpalo::Bump, - tags: &'a [(TagName, Vec)], + 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); @@ -3375,31 +3460,37 @@ fn type_to_union_tags<'a>( rank: Rank, pools: &mut Pools, arena: &'_ bumpalo::Bump, - tags: &'a [(TagName, Vec)], - ext: &'a TypeExtension, - stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>, + types: &mut Types, + union_tags: UnionTags, + opt_ext_slice: Slice, + 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(), @@ -3410,9 +3501,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) @@ -3425,11 +3516,13 @@ fn create_union_lambda<'a>( 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, + 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]); diff --git a/crates/compiler/types/src/types.rs b/crates/compiler/types/src/types.rs index beb3d8d3cc..510116c15e 100644 --- a/crates/compiler/types/src/types.rs +++ b/crates/compiler/types/src/types.rs @@ -361,20 +361,26 @@ impl std::ops::Neg for Polarity { } } -#[allow(dead_code)] pub struct AliasShared { - symbol: Symbol, - type_argument_abilities: Slice>, - type_argument_regions: Slice, - lambda_set_variables: Slice, - infer_ext_in_output_variables: Slice, + pub symbol: Symbol, + pub type_argument_abilities: Slice>, + pub type_argument_regions: Slice, + pub lambda_set_variables: Slice, + pub infer_ext_in_output_variables: Slice, } #[derive(Debug, Clone)] pub enum TypeTag { EmptyRecord, EmptyTagUnion, - Function(Index, Index), + /// The arugments are implicit + Function( + /// lambda set + Index, + /// return type + Index, + ), + /// Closure arguments are implicit ClosureTag { name: Symbol, ambient_function: Variable, @@ -420,6 +426,24 @@ pub enum TypeTag { Record(RecordFields), } +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct AsideTypeSlice(Slice); + +impl AsideTypeSlice { + pub fn into_iter(&self) -> impl Iterator> { + 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 @@ -428,6 +452,10 @@ pub struct Types { tags: Vec, tags_slices: Vec>, + // used to store other slices of types that are not the "main" arguments of a type stored in + // `tags_slices`. + aside_types_slices: Vec>, + // region info where appropriate (retained for generating error messages) regions: Vec, @@ -449,13 +477,14 @@ pub struct Types { } impl Types { - pub const EMPTY_RECORD: Index = Index::new(0); - pub const EMPTY_TAG_UNION: Index = Index::new(1); - pub fn new() -> Self { Self { + // tags.len() == tags_slices.len() tags: vec![TypeTag::EmptyRecord, TypeTag::EmptyTagUnion], - tags_slices: Default::default(), + tags_slices: vec![Default::default(), Default::default()], + + aside_types_slices: Default::default(), + regions: Default::default(), tag_names: Default::default(), field_types: Default::default(), @@ -467,6 +496,49 @@ impl Types { } } + pub fn get_type_arguments(&self, tag: Index) -> Slice { + self.tags_slices[tag.index()] + } + + #[track_caller] + pub fn get_tag_name(&self, typ: &Index) -> &TagName { + self.single_tag_union_tag_names + .get(typ) + .expect("typ is not a single tag union") + } + + pub fn record_fields_slices( + &self, + fields: RecordFields, + ) -> (Slice, Slice>, Slice) { + 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, Slice) { + 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 { use std::iter::repeat; @@ -511,13 +583,14 @@ impl Types { 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.tags_slices, + &mut self.aside_types_slices, std::iter::repeat(Slice::default()).take(tags.len()), ); for (slice_index, (_, types)) in type_slices.indices().zip(tags) { - self.tags_slices[slice_index] = self.from_old_type_slice(types); + self.aside_types_slices[slice_index] = self.from_old_type_slice(types); } let union_tags = UnionTags { @@ -567,10 +640,16 @@ impl Types { type_arguments.iter().map(|a| a.opt_abilities.clone()), ); + // 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: Slice::default(), + type_argument_regions, lambda_set_variables: lambda_set_slice, infer_ext_in_output_variables: infer_ext_in_output_slice, } @@ -705,10 +784,6 @@ impl Types { lambda_set_variables, infer_ext_in_output_types, }) => { - // pub symbol: Symbol, - // pub type_arguments: Vec>, - // pub lambda_set_variables: Vec, - let type_argument_regions = Slice::extend_new(&mut self.regions, type_arguments.iter().map(|t| t.region)); @@ -793,7 +868,7 @@ impl Types { let tag = match kind { AliasKind::Structural => TypeTag::StructuralAlias { shared, actual }, - AliasKind::Opaque => TypeTag::StructuralAlias { shared, actual }, + AliasKind::Opaque => TypeTag::OpaqueAlias { shared, actual }, }; self.set_type_tag(index, tag, type_arguments_slice) @@ -862,11 +937,65 @@ impl Polarity { } } -impl std::ops::Index> for Types { - type Output = TypeTag; +macro_rules! impl_types_index { + ($($field:ident, $ty:ty)*) => {$( + impl std::ops::Index> for Types { + type Output = $ty; - fn index(&self, index: Index) -> &Self::Output { - &self.tags[index.index()] + 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> 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, Option + regions, Region + tag_names, TagName + field_types, RecordField<()> + field_names, Lowercase +} + +impl_types_index_slice! { + tag_names, TagName +} + +impl std::ops::Index> for Types { + type Output = Slice; + + fn index(&self, slice: Index) -> &Self::Output { + &self.aside_types_slices[slice.index()] + } +} + +impl std::ops::Index> for Types { + type Output = [Slice]; + + fn index(&self, slice: Slice) -> &Self::Output { + &self.aside_types_slices[slice.indices()] } } From e240b18b275cde176aaceab5e2aec777eb9110e1 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 7 Nov 2022 15:15:47 -0600 Subject: [PATCH 05/11] Recover Erroneous in type --- crates/compiler/solve/src/solve.rs | 7 +++++-- crates/compiler/types/src/types.rs | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index d6f5855dfa..8850b98b31 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -3040,7 +3040,6 @@ fn type_to_variable<'a>( 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 @@ -3054,7 +3053,11 @@ fn type_to_variable<'a>( result } Erroneous => { - let content = Content::Error; + // 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) } diff --git a/crates/compiler/types/src/types.rs b/crates/compiler/types/src/types.rs index 510116c15e..fa8ffd3db4 100644 --- a/crates/compiler/types/src/types.rs +++ b/crates/compiler/types/src/types.rs @@ -417,6 +417,7 @@ pub enum TypeTag { 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 @@ -507,6 +508,11 @@ impl Types { .expect("typ is not a single tag union") } + #[track_caller] + pub fn get_problem(&self, typ: &Index) -> &Problem { + self.problems.get(typ).expect("typ is not an error") + } + pub fn record_fields_slices( &self, fields: RecordFields, From 09ec5459958e033dd2b339602aa80ba0d6d4f256 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 7 Nov 2022 15:16:27 -0600 Subject: [PATCH 06/11] Fix indent --- crates/compiler/solve/src/specialize.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/compiler/solve/src/specialize.rs b/crates/compiler/solve/src/specialize.rs index a5d1887dda..49b39eb0d4 100644 --- a/crates/compiler/solve/src/specialize.rs +++ b/crates/compiler/solve/src/specialize.rs @@ -714,10 +714,11 @@ fn get_specialization_lambda_set_ambient_function( 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 { From b7af2415389bab9f05c92aa73b51b033869fb9fe Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 7 Nov 2022 15:21:08 -0600 Subject: [PATCH 07/11] Address clippy for Types --- crates/compiler/types/src/types.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/compiler/types/src/types.rs b/crates/compiler/types/src/types.rs index fa8ffd3db4..dea2a0e16c 100644 --- a/crates/compiler/types/src/types.rs +++ b/crates/compiler/types/src/types.rs @@ -477,6 +477,12 @@ pub struct Types { single_tag_union_tag_names: VecMap, TagName>, } +impl Default for Types { + fn default() -> Self { + Self::new() + } +} + impl Types { pub fn new() -> Self { Self { @@ -571,6 +577,7 @@ impl Types { self.tags_slices[index.index()] = type_slice; } + #[allow(clippy::wrong_self_convention)] fn from_old_type_slice(&mut self, old: &[Type]) -> Slice { let slice = self.reserve_type_tags(old.len()); @@ -661,12 +668,14 @@ impl Types { } } + #[allow(clippy::wrong_self_convention)] pub fn from_old_type(&mut self, old: &Type) -> Index { 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, old: &Type) { match old { Type::EmptyRec => self.set_type_tag(index, TypeTag::EmptyRecord, Slice::default()), From b7351885422843c475547ea586fe45f0e3d4a9b8 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 7 Nov 2022 15:22:14 -0600 Subject: [PATCH 08/11] Life is short, no need to spell it out --- crates/compiler/solve/src/solve.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index 8850b98b31..16ea48fec2 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -2444,7 +2444,7 @@ impl RegisterVariable { } #[inline(always)] - fn with_stack<'a>( + fn with_stack( subs: &mut Subs, rank: Rank, pools: &mut Pools, @@ -3147,7 +3147,7 @@ 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, @@ -3329,7 +3329,7 @@ fn find_tag_name_run(slice: &[TagName], subs: &mut Subs) -> Option( +fn register_tag_arguments( subs: &mut Subs, rank: Rank, pools: &mut Pools, @@ -3355,7 +3355,7 @@ 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, @@ -3427,7 +3427,7 @@ 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, @@ -3458,7 +3458,7 @@ 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, @@ -3514,7 +3514,7 @@ fn type_to_union_tags<'a>( } } -fn create_union_lambda<'a>( +fn create_union_lambda( subs: &mut Subs, rank: Rank, pools: &mut Pools, From 191798cfd6598e8048f1a32e11529ecad5af6d6e Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 7 Nov 2022 15:24:11 -0600 Subject: [PATCH 09/11] Address clippy --- crates/compiler/solve/src/solve.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index 16ea48fec2..6dfb56239f 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -32,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, AliasShared, Category, OptAbleType, - OptAbleVar, Polarity, Reason, RecordField, TypeExtension, TypeTag, Types, 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, @@ -2695,7 +2694,6 @@ fn type_to_variable<'a>( .zip(field_tys.into_iter()) { let field_var = { - use roc_types::types::RecordField::*; let t = helper!(field_type); types[field_kind].replace(t) }; @@ -2829,7 +2827,7 @@ fn type_to_variable<'a>( { let copy_var = helper!(arg_type); subs.variables[target_index] = copy_var; - if let Some(abilities) = &types[opt_ability] { + if types[opt_ability].is_some() { let arg_region = types[arg_region]; bind_to_abilities.push((Loc::at(arg_region, copy_var), opt_ability)); } @@ -2927,7 +2925,7 @@ fn type_to_variable<'a>( { let copy_var = helper!(typ); subs.variables[target_index] = copy_var; - if let Some(abilities) = &types[opt_abilities] { + if types[opt_abilities].is_some() { let region = types[region]; bind_to_abilities.push((Loc::at(region, copy_var), opt_abilities)); } @@ -2971,10 +2969,10 @@ fn type_to_variable<'a>( } => { let AliasShared { symbol, - type_argument_abilities, + type_argument_abilities: _, type_argument_regions: _, lambda_set_variables, - infer_ext_in_output_variables, + infer_ext_in_output_variables: _, // TODO } = types[shared]; let type_arguments = types.get_type_arguments(typ); From db8e135a055c0f71fd80e2533430a4c9304ffd56 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 7 Nov 2022 15:31:00 -0600 Subject: [PATCH 10/11] Simplify AbilitySet storage --- crates/compiler/solve/src/solve.rs | 18 +++++++----------- crates/compiler/types/src/types.rs | 18 +++++++++++++----- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index 6dfb56239f..b42ee50e38 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -2819,7 +2819,7 @@ fn type_to_variable<'a>( 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), arg_region), opt_ability) in + 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()) @@ -2827,9 +2827,9 @@ fn type_to_variable<'a>( { let copy_var = helper!(arg_type); subs.variables[target_index] = copy_var; - if types[opt_ability].is_some() { + if !types[abilities].is_empty() { let arg_region = types[arg_region]; - bind_to_abilities.push((Loc::at(arg_region, copy_var), opt_ability)); + bind_to_abilities.push((Loc::at(arg_region, copy_var), abilities)); } } @@ -2917,7 +2917,7 @@ fn type_to_variable<'a>( let new_variables = VariableSubsSlice::reserve_into_subs(subs, all_vars_length); - for (((target_index, typ), region), opt_abilities) in + 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()) @@ -2925,9 +2925,9 @@ fn type_to_variable<'a>( { let copy_var = helper!(typ); subs.variables[target_index] = copy_var; - if types[opt_abilities].is_some() { + if !types[abilities].is_empty() { let region = types[region]; - bind_to_abilities.push((Loc::at(region, copy_var), opt_abilities)); + bind_to_abilities.push((Loc::at(region, copy_var), abilities)); } } @@ -3063,11 +3063,7 @@ fn type_to_variable<'a>( } for (Loc { value: var, region }, abilities) in bind_to_abilities { - // TODO: SoA represent as Some>, not the other way - let abilities = types[abilities] - .as_ref() - .expect("should only have been added if it was Some"); - + let abilities = &types[abilities]; match *subs.get_content_unchecked(var) { Content::RigidVar(a) => { // TODO(multi-abilities): check run cache diff --git a/crates/compiler/types/src/types.rs b/crates/compiler/types/src/types.rs index dea2a0e16c..feff4e9c23 100644 --- a/crates/compiler/types/src/types.rs +++ b/crates/compiler/types/src/types.rs @@ -297,6 +297,10 @@ impl AbilitySet { pub fn into_sorted_iter(self) -> impl ExactSizeIterator { self.0.into_iter() } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } } impl FromIterator for AbilitySet { @@ -363,7 +367,7 @@ impl std::ops::Neg for Polarity { pub struct AliasShared { pub symbol: Symbol, - pub type_argument_abilities: Slice>, + pub type_argument_abilities: Slice, pub type_argument_regions: Slice, pub lambda_set_variables: Slice, pub infer_ext_in_output_variables: Slice, @@ -468,7 +472,7 @@ pub struct Types { field_names: Vec, // aliases - type_arg_abilities: Vec>, // TODO: structural sharing for `AbilitySet`s themselves + type_arg_abilities: Vec, // TODO: structural sharing for `AbilitySet`s themselves aliases: Vec, // these tag types are relatively rare, and so we store them in a way that reduces space, at @@ -650,7 +654,9 @@ impl Types { let type_argument_abilities = Slice::extend_new( &mut self.type_arg_abilities, - type_arguments.iter().map(|a| a.opt_abilities.clone()), + type_arguments + .iter() + .map(|a| a.opt_abilities.as_ref().cloned().unwrap_or_default()), ); // TODO: populate correctly @@ -836,7 +842,9 @@ impl Types { let type_argument_abilities = Slice::extend_new( &mut self.type_arg_abilities, - type_arguments.iter().map(|a| a.value.opt_abilities.clone()), + type_arguments + .iter() + .map(|a| a.value.opt_abilities.as_ref().cloned().unwrap_or_default()), ); let alias_shared = AliasShared { @@ -987,7 +995,7 @@ macro_rules! impl_types_index_slice { impl_types_index! { tags, TypeTag aliases, AliasShared - type_arg_abilities, Option + type_arg_abilities, AbilitySet regions, Region tag_names, TagName field_types, RecordField<()> From b0bcda4117073550b305c435b65fefafdf76fec5 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 7 Nov 2022 15:34:06 -0600 Subject: [PATCH 11/11] typo --- crates/compiler/types/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/compiler/types/src/types.rs b/crates/compiler/types/src/types.rs index feff4e9c23..f728b638c9 100644 --- a/crates/compiler/types/src/types.rs +++ b/crates/compiler/types/src/types.rs @@ -377,7 +377,7 @@ pub struct AliasShared { pub enum TypeTag { EmptyRecord, EmptyTagUnion, - /// The arugments are implicit + /// The arguments are implicit Function( /// lambda set Index,