SoA Types get variable emplacement (!)

We're now reaching the steady state we want to be closert to - when a
type is translated to a variable, emplace the variable we created for it
in the type index, so that types are never converted again!
This commit is contained in:
Ayaz Hafiz 2022-11-09 14:56:34 -06:00
parent d93147dd25
commit 5564796927
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
5 changed files with 110 additions and 86 deletions

View file

@ -8,11 +8,11 @@ use roc_module::ident::TagName;
use roc_module::symbol::{ModuleId, Symbol};
use roc_region::all::{Loc, Region};
use roc_types::subs::{ExhaustiveMark, IllegalCycleMark, Variable};
use roc_types::types::{Category, PatternCategory, TypeTag, Types};
use roc_types::types::{Category, PatternCategory, TypeCell, TypeTag, Types};
pub struct Constraints {
pub constraints: Vec<Constraint>,
pub types: Vec<Cell<Index<TypeTag>>>,
pub types: Vec<Cell<Index<TypeCell>>>,
pub type_slices: Vec<TypeOrVar>,
pub variables: Vec<Variable>,
pub loc_symbols: Vec<(Symbol, Region)>,
@ -60,7 +60,7 @@ impl Default for Constraints {
pub type ExpectedTypeIndex = Index<Expected<TypeOrVar>>;
pub type PExpectedTypeIndex = Index<PExpected<TypeOrVar>>;
pub type TypeOrVar = EitherIndex<Cell<Index<TypeTag>>, Variable>;
pub type TypeOrVar = EitherIndex<Cell<Index<TypeCell>>, Variable>;
impl Constraints {
pub fn new() -> Self {
@ -138,9 +138,9 @@ impl Constraints {
}
}
pub const EMPTY_RECORD: Index<Cell<Index<TypeTag>>> = Index::new(0);
pub const EMPTY_TAG_UNION: Index<Cell<Index<TypeTag>>> = Index::new(1);
pub const STR: Index<Cell<Index<TypeTag>>> = Index::new(2);
pub const EMPTY_RECORD: Index<Cell<Index<TypeCell>>> = Index::new(0);
pub const EMPTY_TAG_UNION: Index<Cell<Index<TypeCell>>> = Index::new(1);
pub const STR: Index<Cell<Index<TypeCell>>> = Index::new(2);
pub const CATEGORY_RECORD: Index<Category> = Index::new(0);
pub const CATEGORY_FOREIGNCALL: Index<Category> = Index::new(1);
@ -173,9 +173,9 @@ impl Constraints {
pub fn push_type(
&mut self,
types: &Types,
typ: Index<TypeTag>,
) -> EitherIndex<Cell<Index<TypeTag>>, Variable> {
match types[typ] {
typ: Index<TypeCell>,
) -> EitherIndex<Cell<Index<TypeCell>>, Variable> {
match types[typ].get() {
TypeTag::EmptyRecord => EitherIndex::from_left(Self::EMPTY_RECORD),
TypeTag::EmptyTagUnion => EitherIndex::from_left(Self::EMPTY_TAG_UNION),
TypeTag::Apply {
@ -184,7 +184,7 @@ impl Constraints {
} => EitherIndex::from_left(Self::STR),
TypeTag::Variable(var) => Self::push_type_variable(var),
_ => {
let index: Index<Cell<Index<TypeTag>>> =
let index: Index<Cell<Index<TypeCell>>> =
Index::push_new(&mut self.types, Cell::new(typ));
EitherIndex::from_left(index)
}

View file

@ -30,7 +30,7 @@ use roc_region::all::{Loc, Region};
use roc_types::subs::{IllegalCycleMark, Variable};
use roc_types::types::Type::{self, *};
use roc_types::types::{
AliasKind, AnnotationSource, Category, OptAbleType, PReason, Reason, RecordField,
AliasKind, AnnotationSource, Category, OptAbleType, PReason, Reason, RecordField, TypeCell,
TypeExtension, TypeTag, Types,
};
@ -1608,7 +1608,7 @@ fn constrain_function_def(
let signature_index = constraints.push_type(types, signature);
let (arg_types, signature_closure_type, ret_type) = match types[signature] {
let (arg_types, signature_closure_type, ret_type) = match types[signature].get() {
TypeTag::Function(signature_closure_type, ret_type) => (
types.get_type_arguments(signature),
signature_closure_type,
@ -2503,7 +2503,7 @@ fn constrain_typed_def(
//
// This means we get errors like "the first argument of `f` is weird"
// instead of the more generic "something is wrong with the body of `f`"
match (&def.loc_expr.value, types[signature]) {
match (&def.loc_expr.value, types[signature].get()) {
(
Closure(ClosureData {
function_type: fn_var,
@ -2667,7 +2667,7 @@ fn constrain_typed_function_arguments(
def_pattern_state: &mut PatternState,
argument_pattern_state: &mut PatternState,
arguments: &[(Variable, AnnotatedMark, Loc<Pattern>)],
arg_types: Slice<TypeTag>,
arg_types: Slice<TypeCell>,
) {
// ensure type matches the one in the annotation
let opt_label = if let Pattern::Identifier(label) = def.loc_pattern.value {
@ -2805,7 +2805,7 @@ fn constrain_typed_function_arguments_simple(
def_pattern_state: &mut PatternState,
argument_pattern_state: &mut PatternState,
arguments: &[(Variable, AnnotatedMark, Loc<Pattern>)],
arg_types: Slice<TypeTag>,
arg_types: Slice<TypeCell>,
) {
let it = arguments.iter().zip(arg_types.into_iter()).enumerate();
for (index, ((pattern_var, annotated_mark, loc_pattern), ann)) in it {
@ -3094,7 +3094,7 @@ fn constrain_closure_size(
}
pub struct InstantiateRigids {
pub signature: Index<TypeTag>,
pub signature: Index<TypeCell>,
pub new_rigid_variables: Vec<Variable>,
pub new_infer_variables: Vec<Variable>,
}
@ -3321,7 +3321,7 @@ fn constraint_recursive_function(
signature_index,
));
let (arg_types, _signature_closure_type, ret_type) = match types[signature] {
let (arg_types, _signature_closure_type, ret_type) = match types[signature].get() {
TypeTag::Function(signature_closure_type, ret_type) => (
types.get_type_arguments(signature),
signature_closure_type,
@ -3764,7 +3764,7 @@ fn rec_defs_help(
//
// This means we get errors like "the first argument of `f` is weird"
// instead of the more generic "something is wrong with the body of `f`"
match (&def.loc_expr.value, types[signature]) {
match (&def.loc_expr.value, types[signature].get()) {
(
Closure(ClosureData {
function_type: fn_var,

View file

@ -771,7 +771,7 @@ fn could_be_a_tag_union(types: &Types, constraints: &mut Constraints, typ: TypeO
Ok(typ_index) => {
let typ_cell = &mut constraints.types[typ_index.index()];
!matches!(
types[*typ_cell.get_mut()],
types[*typ_cell.get_mut()].get(),
TypeTag::Apply { .. } | TypeTag::Function(..) | TypeTag::Record(..)
)
}

View file

@ -34,7 +34,7 @@ use roc_types::subs::{
};
use roc_types::types::{
gather_fields_unsorted_iter, AliasKind, AliasShared, Category, OptAbleVar, Polarity, Reason,
RecordField, Type, TypeExtension, TypeTag, Types, Uls,
RecordField, Type, TypeCell, TypeExtension, TypeTag, Types, Uls,
};
use roc_unify::unify::{
unify, unify_introduced_ability_specialization, Env as UEnv, Mode, Obligated,
@ -138,7 +138,7 @@ impl DelayedAliasVariables {
#[derive(Debug, Default)]
pub struct Aliases {
aliases: Vec<(Symbol, Index<TypeTag>, DelayedAliasVariables, AliasKind)>,
aliases: Vec<(Symbol, Index<TypeCell>, DelayedAliasVariables, AliasKind)>,
variables: Vec<OptAbleVar>,
}
@ -195,7 +195,7 @@ impl Aliases {
}
};
// TODO: can we construct Aliases from TypeTag directly?
// TODO: can we construct Aliases from TypeCell directly?
let alias_typ = types.from_old_type(&alias.typ);
self.aliases
@ -2263,7 +2263,7 @@ fn type_cell_to_var(
pools: &mut Pools,
types: &mut Types,
aliases: &mut Aliases,
typ_cell: &Cell<Index<TypeTag>>,
typ_cell: &Cell<Index<TypeCell>>,
) -> Variable {
let typ = typ_cell.get();
let var = type_to_var(
@ -2278,7 +2278,7 @@ fn type_cell_to_var(
typ,
);
unsafe {
types.set_variable(typ, var);
types.emplace_variable(typ, var);
}
var
@ -2293,9 +2293,9 @@ pub(crate) fn type_to_var(
pools: &mut Pools,
types: &mut Types,
aliases: &mut Aliases,
typ: Index<TypeTag>,
typ: Index<TypeCell>,
) -> Variable {
if let TypeTag::Variable(var) = types[typ] {
if let TypeTag::Variable(var) = types[typ].get() {
var
} else {
let mut arena = take_scratchpad();
@ -2336,11 +2336,11 @@ impl RegisterVariable {
pools: &mut Pools,
arena: &'_ bumpalo::Bump,
types: &mut Types,
typ: Index<TypeTag>,
typ: Index<TypeCell>,
) -> Self {
use RegisterVariable::*;
match types[typ] {
match types[typ].get() {
TypeTag::Variable(var) => Direct(var),
TypeTag::EmptyRecord => Direct(Variable::EMPTY_RECORD),
TypeTag::EmptyTagUnion => Direct(Variable::EMPTY_TAG_UNION),
@ -2373,7 +2373,7 @@ impl RegisterVariable {
pools: &mut Pools,
arena: &'_ bumpalo::Bump,
types: &mut Types,
typ: Index<TypeTag>,
typ: Index<TypeCell>,
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
) -> Variable {
match Self::from_type(subs, rank, pools, arena, types, typ) {
@ -2444,7 +2444,7 @@ impl AmbientFunctionPolicy {
#[derive(Debug)]
enum TypeToVar {
Defer {
typ: Index<TypeTag>,
typ: Index<TypeCell>,
destination: Variable,
ambient_function: AmbientFunctionPolicy,
},
@ -2461,7 +2461,7 @@ fn type_to_variable<'a>(
arena: &'a bumpalo::Bump,
aliases: &mut Aliases,
types: &mut Types,
typ: Index<TypeTag>,
typ: Index<TypeCell>,
// Helpers for instantiating ambient functions of lambda set variables from type aliases.
is_alias_lambda_set_arg: bool,
) -> Variable {
@ -2505,7 +2505,7 @@ fn type_to_variable<'a>(
}) = stack.pop()
{
use TypeTag::*;
match types[typ] {
match types[typ].get() {
Variable(_) | EmptyRecord | EmptyTagUnion => {
unreachable!("This variant should never be deferred!")
}
@ -2812,7 +2812,7 @@ fn type_to_variable<'a>(
}
StructuralAlias { shared, actual } | OpaqueAlias { shared, actual } => {
let kind = match types[typ] {
let kind = match types[typ].get() {
StructuralAlias { .. } => AliasKind::Structural,
OpaqueAlias { .. } => AliasKind::Opaque,
_ => internal_error!(),
@ -3062,10 +3062,10 @@ fn roc_result_to_var(
pools: &mut Pools,
arena: &'_ bumpalo::Bump,
types: &mut Types,
result_type: Index<TypeTag>,
result_type: Index<TypeCell>,
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
) -> Variable {
match types[result_type] {
match types[result_type].get() {
TypeTag::TagUnion(tags) => {
let ext_slice = types.get_type_arguments(result_type);
@ -3245,7 +3245,7 @@ fn register_tag_arguments(
arena: &'_ bumpalo::Bump,
types: &mut Types,
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
arguments: Slice<TypeTag>,
arguments: Slice<TypeCell>,
) -> VariableSubsSlice {
if arguments.is_empty() {
VariableSubsSlice::default()
@ -3374,7 +3374,7 @@ fn type_to_union_tags(
arena: &'_ bumpalo::Bump,
types: &mut Types,
union_tags: UnionTags,
opt_ext_slice: Slice<TypeTag>,
opt_ext_slice: Slice<TypeCell>,
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
) -> (UnionTags, Variable) {
use bumpalo::collections::Vec;
@ -3430,7 +3430,7 @@ fn create_union_lambda(
arena: &'_ bumpalo::Bump,
types: &mut Types,
closure: Symbol,
capture_types: Slice<TypeTag>,
capture_types: Slice<TypeCell>,
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
) -> UnionLambdas {
let variable_slice =

View file

@ -12,6 +12,7 @@ use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
use roc_module::low_level::LowLevel;
use roc_module::symbol::{Interns, Symbol};
use roc_region::all::{Loc, Region};
use std::cell::Cell;
use std::fmt;
use std::fmt::Write;
@ -370,8 +371,28 @@ 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>,
pub lambda_set_variables: Slice<TypeCell>,
pub infer_ext_in_output_variables: Slice<TypeCell>,
}
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct TypeCell(Cell<TypeTag>);
static_assertions::assert_eq_size!(TypeCell, TypeTag);
impl TypeCell {
const fn new(tag: TypeTag) -> Self {
Self(Cell::new(tag))
}
fn set(&self, tag: TypeTag) {
self.0.set(tag)
}
pub fn get(&self) -> TypeTag {
self.0.get()
}
}
/// The tag (head constructor) of a canonical type stored in [Types].
@ -382,9 +403,9 @@ pub enum TypeTag {
/// The arguments are implicit
Function(
/// lambda set
Index<TypeTag>,
Index<TypeCell>,
/// return type
Index<TypeTag>,
Index<TypeCell>,
),
/// Closure arguments are implicit
ClosureTag {
@ -402,21 +423,21 @@ pub enum TypeTag {
},
StructuralAlias {
shared: Index<AliasShared>,
actual: Index<TypeTag>,
actual: Index<TypeCell>,
},
OpaqueAlias {
shared: Index<AliasShared>,
actual: Index<TypeTag>,
actual: Index<TypeCell>,
},
HostExposedAlias {
shared: Index<AliasShared>,
actual_type: Index<TypeTag>,
actual_type: Index<TypeCell>,
actual_variable: Variable,
},
Apply {
symbol: Symbol,
// type_argument_types: Slice<TypeTag>, implicit
// type_argument_types: Slice<TypeCell>, implicit
type_argument_regions: Slice<Region>,
region: Region, // IDEA: make implicit, final element of `type_argument_regions`
},
@ -437,10 +458,10 @@ pub enum TypeTag {
/// type arguments of a [TypeTag].
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct AsideTypeSlice(Slice<TypeTag>);
pub struct AsideTypeSlice(Slice<TypeCell>);
impl AsideTypeSlice {
pub fn into_iter(&self) -> impl Iterator<Item = Index<TypeTag>> {
pub fn into_iter(&self) -> impl Iterator<Item = Index<TypeCell>> {
self.0.into_iter()
}
@ -463,12 +484,12 @@ pub struct Types {
// `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>>,
tags: Vec<TypeCell>,
tags_slices: Vec<Slice<TypeCell>>,
// 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>>,
aside_types_slices: Vec<Slice<TypeCell>>,
// region info where appropriate (retained for generating error messages)
regions: Vec<Region>,
@ -486,7 +507,7 @@ pub struct Types {
// 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
single_tag_union_tag_names: VecMap<Index<TypeTag>, TagName>,
single_tag_union_tag_names: VecMap<Index<TypeCell>, TagName>,
}
impl Default for Types {
@ -496,21 +517,21 @@ impl Default for Types {
}
impl Types {
pub const EMPTY_RECORD: Index<TypeTag> = Index::new(0);
const EMPTY_RECORD_TAG: TypeTag = TypeTag::EmptyRecord;
const EMPTY_RECORD_ARGS: Slice<TypeTag> = Slice::empty();
pub const EMPTY_RECORD: Index<TypeCell> = Index::new(0);
const EMPTY_RECORD_TAG: TypeCell = TypeCell::new(TypeTag::EmptyRecord);
const EMPTY_RECORD_ARGS: Slice<TypeCell> = Slice::empty();
pub const EMPTY_TAG_UNION: Index<TypeTag> = Index::new(1);
const EMPTY_TAG_UNION_TAG: TypeTag = TypeTag::EmptyTagUnion;
const EMPTY_TAG_UNION_ARGS: Slice<TypeTag> = Slice::empty();
pub const EMPTY_TAG_UNION: Index<TypeCell> = Index::new(1);
const EMPTY_TAG_UNION_TAG: TypeCell = TypeCell::new(TypeTag::EmptyTagUnion);
const EMPTY_TAG_UNION_ARGS: Slice<TypeCell> = Slice::empty();
pub const STR: Index<TypeTag> = Index::new(2);
const STR_TAG: TypeTag = TypeTag::Apply {
pub const STR: Index<TypeCell> = Index::new(2);
const STR_TAG: TypeCell = TypeCell::new(TypeTag::Apply {
symbol: Symbol::STR_STR,
type_argument_regions: Slice::empty(),
region: Region::zero(),
};
const STR_ARGS: Slice<TypeTag> = Slice::empty();
});
const STR_ARGS: Slice<TypeCell> = Slice::empty();
pub fn new() -> Self {
Self {
@ -548,7 +569,7 @@ impl Types {
}
#[track_caller]
pub fn get_tag_name(&self, typ: &Index<TypeTag>) -> &TagName {
pub fn get_tag_name(&self, typ: &Index<TypeCell>) -> &TagName {
self.single_tag_union_tag_names
.get(typ)
.expect("typ is not a single tag union")
@ -557,7 +578,7 @@ impl Types {
pub fn record_fields_slices(
&self,
fields: RecordFields,
) -> (Slice<Lowercase>, Slice<RecordField<()>>, Slice<TypeTag>) {
) -> (Slice<Lowercase>, Slice<RecordField<()>>, Slice<TypeCell>) {
let RecordFields {
length,
field_names_start,
@ -589,11 +610,11 @@ impl Types {
/// # Safety
///
/// May only be called if `var` is known to represent the type at `index`.
pub unsafe fn set_variable(&mut self, index: Index<TypeTag>, var: Variable) {
self.tags[index.index()] = TypeTag::Variable(var);
pub unsafe fn emplace_variable(&self, index: Index<TypeCell>, var: Variable) {
self.tags[index.index()].0.replace(TypeTag::Variable(var));
}
fn reserve_type_tags(&mut self, length: usize) -> Slice<TypeTag> {
fn reserve_type_tags(&mut self, length: usize) -> Slice<TypeCell> {
use std::iter::repeat;
debug_assert_eq!(self.tags.len(), self.tags_slices.len());
@ -601,21 +622,24 @@ impl Types {
self.tags_slices
.extend(repeat(Slice::default()).take(length));
Slice::extend_new(&mut self.tags, repeat(TypeTag::EmptyRecord).take(length))
Slice::extend_new(
&mut self.tags,
repeat(TypeCell::new(TypeTag::EmptyRecord)).take(length),
)
}
fn reserve_type_tag(&mut self) -> Index<TypeTag> {
fn reserve_type_tag(&mut self) -> Index<TypeCell> {
debug_assert_eq!(self.tags.len(), self.tags_slices.len());
self.tags_slices.push(Slice::default());
Index::push_new(&mut self.tags, TypeTag::EmptyRecord)
Index::push_new(&mut self.tags, TypeCell::new(TypeTag::EmptyRecord))
}
fn set_type_tag(&mut self, index: Index<TypeTag>, tag: TypeTag, type_slice: Slice<TypeTag>) {
fn set_type_tag(&mut self, index: Index<TypeCell>, tag: TypeTag, type_slice: Slice<TypeCell>) {
debug_assert_eq!(self.tags.len(), self.tags_slices.len());
self.tags[index.index()] = tag;
self.tags[index.index()].set(tag);
self.tags_slices[index.index()] = type_slice;
}
@ -624,7 +648,7 @@ impl Types {
&mut self,
// evil, but allows us to emulate reference-polymorphism
old: impl ExactSizeIterator<Item = B>,
) -> Slice<TypeTag>
) -> Slice<TypeCell>
where
B: std::borrow::Borrow<Type>,
{
@ -641,7 +665,7 @@ impl Types {
&mut self,
tags: &[(TagName, Vec<Type>)],
extension: &TypeExtension,
) -> (UnionTags, Slice<TypeTag>) {
) -> (UnionTags, Slice<TypeCell>) {
let tag_names_slice =
Slice::extend_new(&mut self.tag_names, tags.iter().map(|(n, _)| n.clone()));
@ -720,7 +744,7 @@ impl Types {
}
#[allow(clippy::wrong_self_convention)]
pub fn from_old_type(&mut self, old: &Type) -> Index<TypeTag> {
pub fn from_old_type(&mut self, old: &Type) -> Index<TypeCell> {
let index = self.reserve_type_tag();
self.from_old_type_at(index, old);
index
@ -728,10 +752,10 @@ impl Types {
pub fn function(
&mut self,
arguments: Slice<TypeTag>,
lambda_set: Index<TypeTag>,
ret: Index<TypeTag>,
) -> Index<TypeTag> {
arguments: Slice<TypeCell>,
lambda_set: Index<TypeCell>,
ret: Index<TypeCell>,
) -> Index<TypeCell> {
let index = self.reserve_type_tag();
let tag = TypeTag::Function(lambda_set, ret);
@ -740,7 +764,7 @@ impl Types {
}
#[allow(clippy::wrong_self_convention)]
fn from_old_type_at(&mut self, index: Index<TypeTag>, old: &Type) {
fn from_old_type_at(&mut self, index: Index<TypeCell>, old: &Type) {
match old {
Type::EmptyRec => self.set_type_tag(index, TypeTag::EmptyRecord, Slice::default()),
Type::EmptyTagUnion => {
@ -1003,9 +1027,9 @@ impl Types {
/// Creates a deep clone of a type with substituted variables.
pub fn clone_with_variable_substitutions(
&mut self,
typ: Index<TypeTag>,
typ: Index<TypeCell>,
subs: &MutMap<Variable, Variable>,
) -> Index<TypeTag> {
) -> Index<TypeCell> {
let cloned = self.reserve_type_tag();
let mut stack = vec![(cloned, typ)];
@ -1085,7 +1109,7 @@ impl Types {
while let Some((dest_index, typ)) = stack.pop() {
use TypeTag::*;
let (tag, args) = match self[typ] {
let (tag, args) = match self[typ].get() {
Variable(v) => (Variable(subst!(v)), Default::default()),
EmptyRecord => (EmptyRecord, Default::default()),
EmptyTagUnion => (EmptyTagUnion, Default::default()),
@ -1599,7 +1623,7 @@ macro_rules! impl_types_index_slice {
}
impl_types_index! {
tags, TypeTag
tags, TypeCell
aliases, AliasShared
type_arg_abilities, AbilitySet
regions, Region
@ -1613,7 +1637,7 @@ impl_types_index_slice! {
}
impl std::ops::Index<Index<AsideTypeSlice>> for Types {
type Output = Slice<TypeTag>;
type Output = Slice<TypeCell>;
fn index(&self, slice: Index<AsideTypeSlice>) -> &Self::Output {
&self.aside_types_slices[slice.index()]
@ -1621,7 +1645,7 @@ impl std::ops::Index<Index<AsideTypeSlice>> for Types {
}
impl std::ops::Index<Slice<AsideTypeSlice>> for Types {
type Output = [Slice<TypeTag>];
type Output = [Slice<TypeCell>];
fn index(&self, slice: Slice<AsideTypeSlice>) -> &Self::Output {
&self.aside_types_slices[slice.indices()]