mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Merge branch 'trunk' into list-map-ownership
This commit is contained in:
commit
201d09d9bf
71 changed files with 2250 additions and 2560 deletions
|
@ -10,6 +10,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
|||
use roc_can::abilities::AbilitiesStore;
|
||||
use roc_can::expr::{AnnotatedMark, ClosureData, IntValue};
|
||||
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
|
||||
use roc_collections::VecMap;
|
||||
use roc_debug_flags::{
|
||||
dbg_do, ROC_PRINT_IR_AFTER_REFCOUNT, ROC_PRINT_IR_AFTER_RESET_REUSE,
|
||||
ROC_PRINT_IR_AFTER_SPECIALIZATION,
|
||||
|
@ -753,6 +754,157 @@ impl<'a> Specialized<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Uniquely determines the specialization of a polymorphic (non-proc) value symbol.
|
||||
/// Two specializations are equivalent if their [`SpecializationMark`]s are equal.
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
struct SpecializationMark<'a> {
|
||||
/// The layout of the symbol itself.
|
||||
layout: Layout<'a>,
|
||||
|
||||
/// If this symbol is a closure def, we must also keep track of what function it specializes,
|
||||
/// because the [`layout`] field will only keep track of its closure and lambda set - which can
|
||||
/// be the same for two different function specializations. For example,
|
||||
///
|
||||
/// id = if True then \x -> x else \y -> y
|
||||
/// { a: id "", b: id 1u8 }
|
||||
///
|
||||
/// The lambda set and captures of `id` is the same in both usages inside the record, but the
|
||||
/// reified specializations of `\x -> x` and `\y -> y` must be for Str and U8.
|
||||
///
|
||||
/// Note that this field is not relevant for anything that is not a function.
|
||||
function_mark: Option<RawFunctionLayout<'a>>,
|
||||
}
|
||||
|
||||
/// When walking a function body, we may encounter specialized usages of polymorphic symbols. For
|
||||
/// example
|
||||
///
|
||||
/// myTag = A
|
||||
/// use1 : [A, B]
|
||||
/// use1 = myTag
|
||||
/// use2 : [A, B, C]
|
||||
/// use2 = myTag
|
||||
///
|
||||
/// We keep track of the specializations of `myTag` and create fresh symbols when there is more
|
||||
/// than one, so that a unique def can be created for each.
|
||||
#[derive(Default, Debug, Clone)]
|
||||
struct SymbolSpecializations<'a>(
|
||||
// THEORY:
|
||||
// 1. the number of symbols in a def is very small
|
||||
// 2. the number of specializations of a symbol in a def is even smaller (almost always only one)
|
||||
// So, a linear VecMap is preferrable. Use a two-layered one to make (1) extraction of defs easy
|
||||
// and (2) reads of a certain symbol be determined by its first occurrence, not its last.
|
||||
VecMap<Symbol, VecMap<SpecializationMark<'a>, (Variable, Symbol)>>,
|
||||
);
|
||||
|
||||
impl<'a> SymbolSpecializations<'a> {
|
||||
/// Gets a specialization for a symbol, or creates a new one.
|
||||
#[inline(always)]
|
||||
fn get_or_insert(
|
||||
&mut self,
|
||||
env: &mut Env<'a, '_>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
symbol: Symbol,
|
||||
specialization_var: Variable,
|
||||
) -> Symbol {
|
||||
let arena = env.arena;
|
||||
let subs: &Subs = env.subs;
|
||||
|
||||
let layout = match layout_cache.from_var(arena, specialization_var, subs) {
|
||||
Ok(layout) => layout,
|
||||
// This can happen when the def symbol has a type error. In such cases just use the
|
||||
// def symbol, which is erroring.
|
||||
Err(_) => return symbol,
|
||||
};
|
||||
|
||||
let is_closure = matches!(
|
||||
subs.get_content_without_compacting(specialization_var),
|
||||
Content::Structure(FlatType::Func(..))
|
||||
);
|
||||
let function_mark = if is_closure {
|
||||
let fn_layout = match layout_cache.raw_from_var(arena, specialization_var, subs) {
|
||||
Ok(layout) => layout,
|
||||
// This can happen when the def symbol has a type error. In such cases just use the
|
||||
// def symbol, which is erroring.
|
||||
Err(_) => return symbol,
|
||||
};
|
||||
Some(fn_layout)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let specialization_mark = SpecializationMark {
|
||||
layout,
|
||||
function_mark,
|
||||
};
|
||||
|
||||
let symbol_specializations = self.0.get_or_insert(symbol, Default::default);
|
||||
|
||||
// For the first specialization, always reuse the current symbol. The vast majority of defs
|
||||
// only have one instance type, so this preserves readability of the IR.
|
||||
// TODO: turn me off and see what breaks.
|
||||
let needs_fresh_symbol = !symbol_specializations.is_empty();
|
||||
|
||||
let mut make_specialized_symbol = || {
|
||||
if needs_fresh_symbol {
|
||||
env.unique_symbol()
|
||||
} else {
|
||||
symbol
|
||||
}
|
||||
};
|
||||
|
||||
let (_var, specialized_symbol) = symbol_specializations
|
||||
.get_or_insert(specialization_mark, || {
|
||||
(specialization_var, make_specialized_symbol())
|
||||
});
|
||||
|
||||
*specialized_symbol
|
||||
}
|
||||
|
||||
/// Inserts a known specialization for a symbol. Returns the overwritten specialization, if any.
|
||||
pub fn get_or_insert_known(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
mark: SpecializationMark<'a>,
|
||||
specialization_var: Variable,
|
||||
specialization_symbol: Symbol,
|
||||
) -> Option<(Variable, Symbol)> {
|
||||
self.0
|
||||
.get_or_insert(symbol, Default::default)
|
||||
.insert(mark, (specialization_var, specialization_symbol))
|
||||
}
|
||||
|
||||
/// Removes all specializations for a symbol, returning the type and symbol of each specialization.
|
||||
pub fn remove(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
) -> impl ExactSizeIterator<Item = (SpecializationMark<'a>, (Variable, Symbol))> {
|
||||
self.0
|
||||
.remove(&symbol)
|
||||
.map(|(_, specializations)| specializations)
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
}
|
||||
|
||||
/// Expects and removes at most a single specialization symbol for the given requested symbol.
|
||||
/// A symbol may have no specializations if it is never referenced in a body, so it is possible
|
||||
/// for this to return None.
|
||||
pub fn remove_single(&mut self, symbol: Symbol) -> Option<Symbol> {
|
||||
let mut specializations = self.remove(symbol);
|
||||
|
||||
debug_assert!(
|
||||
specializations.len() < 2,
|
||||
"Symbol {:?} has multiple specializations",
|
||||
symbol
|
||||
);
|
||||
|
||||
specializations.next().map(|(_, (_, symbol))| symbol)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Procs<'a> {
|
||||
pub partial_procs: PartialProcs<'a>,
|
||||
|
@ -763,7 +915,7 @@ pub struct Procs<'a> {
|
|||
specialized: Specialized<'a>,
|
||||
pub runtime_errors: BumpMap<Symbol, &'a str>,
|
||||
pub externals_we_need: BumpMap<ModuleId, ExternalSpecializations>,
|
||||
pub needed_symbol_specializations: BumpMap<(Symbol, Layout<'a>), (Variable, Symbol)>,
|
||||
symbol_specializations: SymbolSpecializations<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Procs<'a> {
|
||||
|
@ -777,38 +929,9 @@ impl<'a> Procs<'a> {
|
|||
specialized: Specialized::default(),
|
||||
runtime_errors: BumpMap::new_in(arena),
|
||||
externals_we_need: BumpMap::new_in(arena),
|
||||
needed_symbol_specializations: BumpMap::new_in(arena),
|
||||
symbol_specializations: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Expects and removes a single specialization symbol for the given requested symbol.
|
||||
/// In debug builds, we assert that the layout of the specialization is the layout expected by
|
||||
/// the requested symbol.
|
||||
fn remove_single_symbol_specialization(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
layout: Layout,
|
||||
) -> Option<Symbol> {
|
||||
let mut specialized_symbols = self
|
||||
.needed_symbol_specializations
|
||||
.drain_filter(|(sym, _), _| sym == &symbol);
|
||||
|
||||
let specialization_symbol = specialized_symbols
|
||||
.next()
|
||||
.map(|((_, specialized_layout), (_, specialized_symbol))| {
|
||||
debug_assert_eq!(specialized_layout, layout, "Requested the single specialization of {:?}, but the specialization layout ({:?}) doesn't match the expected layout ({:?})", symbol, specialized_layout, layout);
|
||||
specialized_symbol
|
||||
});
|
||||
|
||||
debug_assert_eq!(
|
||||
specialized_symbols.count(),
|
||||
0,
|
||||
"Symbol {:?} has multiple specializations",
|
||||
symbol
|
||||
);
|
||||
|
||||
specialization_symbol
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -2206,9 +2329,9 @@ pub fn specialize_all<'a>(
|
|||
specialize_host_specializations(env, &mut procs, layout_cache, specializations_for_host);
|
||||
|
||||
debug_assert!(
|
||||
procs.needed_symbol_specializations.is_empty(),
|
||||
procs.symbol_specializations.is_empty(),
|
||||
"{:?}",
|
||||
&procs.needed_symbol_specializations
|
||||
&procs.symbol_specializations
|
||||
);
|
||||
|
||||
procs
|
||||
|
@ -2543,11 +2666,10 @@ fn specialize_external<'a>(
|
|||
// An argument from the closure list may have taken on a specialized symbol
|
||||
// name during the evaluation of the def body. If this is the case, load the
|
||||
// specialized name rather than the original captured name!
|
||||
let mut get_specialized_name = |symbol, layout| {
|
||||
let mut get_specialized_name = |symbol| {
|
||||
procs
|
||||
.needed_symbol_specializations
|
||||
.remove(&(symbol, layout))
|
||||
.map(|(_, specialized)| specialized)
|
||||
.symbol_specializations
|
||||
.remove_single(symbol)
|
||||
.unwrap_or(symbol)
|
||||
};
|
||||
|
||||
|
@ -2585,7 +2707,7 @@ fn specialize_external<'a>(
|
|||
union_layout,
|
||||
};
|
||||
|
||||
let symbol = get_specialized_name(**symbol, **layout);
|
||||
let symbol = get_specialized_name(**symbol);
|
||||
|
||||
specialized_body = Stmt::Let(
|
||||
symbol,
|
||||
|
@ -2628,7 +2750,7 @@ fn specialize_external<'a>(
|
|||
structure: Symbol::ARG_CLOSURE,
|
||||
};
|
||||
|
||||
let symbol = get_specialized_name(**symbol, **layout);
|
||||
let symbol = get_specialized_name(**symbol);
|
||||
|
||||
specialized_body = Stmt::Let(
|
||||
symbol,
|
||||
|
@ -2673,11 +2795,10 @@ fn specialize_external<'a>(
|
|||
let proc_args: Vec<_> = proc_args
|
||||
.iter()
|
||||
.map(|&(layout, symbol)| {
|
||||
// Grab the specialization symbol, if it exists.
|
||||
let symbol = procs
|
||||
.needed_symbol_specializations
|
||||
// We can remove the specialization since this is the definition site.
|
||||
.remove(&(symbol, layout))
|
||||
.map(|(_, specialized_symbol)| specialized_symbol)
|
||||
.symbol_specializations
|
||||
.remove_single(symbol)
|
||||
.unwrap_or(symbol);
|
||||
|
||||
(layout, symbol)
|
||||
|
@ -3391,18 +3512,7 @@ pub fn with_hole<'a>(
|
|||
);
|
||||
|
||||
let outer_symbol = env.unique_symbol();
|
||||
let pattern_layout = layout_cache
|
||||
.from_var(env.arena, def.expr_var, env.subs)
|
||||
.expect("Pattern has no layout");
|
||||
stmt = store_pattern(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
&mono_pattern,
|
||||
pattern_layout,
|
||||
outer_symbol,
|
||||
stmt,
|
||||
);
|
||||
stmt = store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt);
|
||||
|
||||
// convert the def body, store in outer_symbol
|
||||
with_hole(
|
||||
|
@ -3445,7 +3555,9 @@ pub fn with_hole<'a>(
|
|||
can_reuse_symbol(env, procs, &roc_can::expr::Expr::Var(symbol))
|
||||
{
|
||||
let real_symbol =
|
||||
reuse_symbol_or_specialize(env, procs, layout_cache, symbol, variable);
|
||||
procs
|
||||
.symbol_specializations
|
||||
.get_or_insert(env, layout_cache, symbol, variable);
|
||||
symbol = real_symbol;
|
||||
}
|
||||
|
||||
|
@ -3524,8 +3636,12 @@ pub fn with_hole<'a>(
|
|||
match can_reuse_symbol(env, procs, &loc_arg_expr.value) {
|
||||
// Opaques decay to their argument.
|
||||
ReuseSymbol::Value(symbol) => {
|
||||
let real_name =
|
||||
reuse_symbol_or_specialize(env, procs, layout_cache, symbol, arg_var);
|
||||
let real_name = procs.symbol_specializations.get_or_insert(
|
||||
env,
|
||||
layout_cache,
|
||||
symbol,
|
||||
arg_var,
|
||||
);
|
||||
let mut result = hole.clone();
|
||||
substitute_in_exprs(arena, &mut result, assigned, real_name);
|
||||
result
|
||||
|
@ -3578,9 +3694,8 @@ pub fn with_hole<'a>(
|
|||
can_fields.push(Field::Function(symbol, variable));
|
||||
}
|
||||
Value(symbol) => {
|
||||
let reusable = reuse_symbol_or_specialize(
|
||||
let reusable = procs.symbol_specializations.get_or_insert(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
symbol,
|
||||
field.var,
|
||||
|
@ -4393,25 +4508,38 @@ pub fn with_hole<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
Value(function_symbol) => match full_layout {
|
||||
RawFunctionLayout::Function(arg_layouts, lambda_set, ret_layout) => {
|
||||
let closure_data_symbol = function_symbol;
|
||||
Value(function_symbol) => {
|
||||
let function_symbol = procs.symbol_specializations.get_or_insert(
|
||||
env,
|
||||
layout_cache,
|
||||
function_symbol,
|
||||
fn_var,
|
||||
);
|
||||
|
||||
result = match_on_lambda_set(
|
||||
env,
|
||||
lambda_set,
|
||||
closure_data_symbol,
|
||||
arg_symbols,
|
||||
match full_layout {
|
||||
RawFunctionLayout::Function(
|
||||
arg_layouts,
|
||||
lambda_set,
|
||||
ret_layout,
|
||||
assigned,
|
||||
hole,
|
||||
);
|
||||
) => {
|
||||
let closure_data_symbol = function_symbol;
|
||||
|
||||
result = match_on_lambda_set(
|
||||
env,
|
||||
lambda_set,
|
||||
closure_data_symbol,
|
||||
arg_symbols,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
assigned,
|
||||
hole,
|
||||
);
|
||||
}
|
||||
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
||||
unreachable!("calling a non-closure layout")
|
||||
}
|
||||
}
|
||||
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
||||
unreachable!("calling a non-closure layout")
|
||||
}
|
||||
},
|
||||
}
|
||||
UnspecializedExpr(symbol) => {
|
||||
match procs.ability_member_aliases.get(symbol).unwrap() {
|
||||
&AbilityMember(member) => {
|
||||
|
@ -5561,7 +5689,6 @@ pub fn from_can<'a>(
|
|||
}
|
||||
LetNonRec(def, cont, outer_annotation) => {
|
||||
if let roc_can::pattern::Pattern::Identifier(symbol) = &def.loc_pattern.value {
|
||||
// dbg!(symbol, &def.loc_expr.value);
|
||||
match def.loc_expr.value {
|
||||
roc_can::expr::Expr::Closure(closure_data) => {
|
||||
register_capturing_closure(env, procs, layout_cache, *symbol, closure_data);
|
||||
|
@ -5693,12 +5820,14 @@ pub fn from_can<'a>(
|
|||
_ => {
|
||||
let rest = from_can(env, variable, cont.value, procs, layout_cache);
|
||||
|
||||
let needs_def_specializations = procs
|
||||
.needed_symbol_specializations
|
||||
.keys()
|
||||
.any(|(s, _)| s == symbol);
|
||||
// Remove all the requested symbol specializations now, since this is the
|
||||
// def site and hence we won't need them any higher up.
|
||||
let mut needed_specializations =
|
||||
procs.symbol_specializations.remove(*symbol);
|
||||
|
||||
if !needs_def_specializations {
|
||||
if needed_specializations.len() == 0 {
|
||||
// We don't need any specializations, that means this symbol is never
|
||||
// referenced.
|
||||
return with_hole(
|
||||
env,
|
||||
def.loc_expr.value,
|
||||
|
@ -5714,16 +5843,9 @@ pub fn from_can<'a>(
|
|||
|
||||
let mut stmt = rest;
|
||||
|
||||
// Remove all the requested symbol specializations now, since this is the
|
||||
// def site and hence we won't need them any higher up.
|
||||
let mut needed_specializations = procs
|
||||
.needed_symbol_specializations
|
||||
.drain_filter(|(s, _), _| s == symbol)
|
||||
.collect::<std::vec::Vec<_>>();
|
||||
|
||||
if needed_specializations.len() == 1 {
|
||||
let ((_, _wanted_layout), (var, specialized_symbol)) =
|
||||
needed_specializations.pop().unwrap();
|
||||
let (_specialization_mark, (var, specialized_symbol)) =
|
||||
needed_specializations.next().unwrap();
|
||||
|
||||
// Unify the expr_var with the requested specialization once.
|
||||
let _res =
|
||||
|
@ -5740,7 +5862,7 @@ pub fn from_can<'a>(
|
|||
);
|
||||
} else {
|
||||
// Need to eat the cost and create a specialized version of the body for each specialization.
|
||||
for ((_original_symbol, _wanted_layout), (var, specialized_symbol)) in
|
||||
for (_specialization_mark, (var, specialized_symbol)) in
|
||||
needed_specializations
|
||||
{
|
||||
use crate::copy::deep_copy_type_vars_into_expr;
|
||||
|
@ -5810,11 +5932,9 @@ pub fn from_can<'a>(
|
|||
|
||||
// layer on any default record fields
|
||||
for (symbol, variable, expr) in assignments {
|
||||
let layout = layout_cache
|
||||
.from_var(env.arena, variable, env.subs)
|
||||
.expect("Default field has no layout");
|
||||
let specialization_symbol = procs
|
||||
.remove_single_symbol_specialization(symbol, layout)
|
||||
.symbol_specializations
|
||||
.remove_single(symbol)
|
||||
// Can happen when the symbol was never used under this body, and hence has no
|
||||
// requested specialization.
|
||||
.unwrap_or(symbol);
|
||||
|
@ -5831,30 +5951,12 @@ pub fn from_can<'a>(
|
|||
);
|
||||
}
|
||||
|
||||
let pattern_layout = layout_cache
|
||||
.from_var(env.arena, def.expr_var, env.subs)
|
||||
.expect("Pattern has no layout");
|
||||
if let roc_can::expr::Expr::Var(outer_symbol) = def.loc_expr.value {
|
||||
store_pattern(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
&mono_pattern,
|
||||
pattern_layout,
|
||||
outer_symbol,
|
||||
stmt,
|
||||
)
|
||||
store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt)
|
||||
} else {
|
||||
let outer_symbol = env.unique_symbol();
|
||||
stmt = store_pattern(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
&mono_pattern,
|
||||
pattern_layout,
|
||||
outer_symbol,
|
||||
stmt,
|
||||
);
|
||||
stmt =
|
||||
store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt);
|
||||
|
||||
// convert the def body, store in outer_symbol
|
||||
with_hole(
|
||||
|
@ -6420,19 +6522,10 @@ pub fn store_pattern<'a>(
|
|||
procs: &mut Procs<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
can_pat: &Pattern<'a>,
|
||||
pattern_layout: Layout,
|
||||
outer_symbol: Symbol,
|
||||
stmt: Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
match store_pattern_help(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
can_pat,
|
||||
pattern_layout,
|
||||
outer_symbol,
|
||||
stmt,
|
||||
) {
|
||||
match store_pattern_help(env, procs, layout_cache, can_pat, outer_symbol, stmt) {
|
||||
StorePattern::Productive(new) => new,
|
||||
StorePattern::NotProductive(new) => new,
|
||||
}
|
||||
|
@ -6452,7 +6545,6 @@ fn store_pattern_help<'a>(
|
|||
procs: &mut Procs<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
can_pat: &Pattern<'a>,
|
||||
pattern_layout: Layout,
|
||||
outer_symbol: Symbol,
|
||||
mut stmt: Stmt<'a>,
|
||||
) -> StorePattern<'a> {
|
||||
|
@ -6463,7 +6555,8 @@ fn store_pattern_help<'a>(
|
|||
// An identifier in a pattern can define at most one specialization!
|
||||
// Remove any requested specializations for this name now, since this is the definition site.
|
||||
let specialization_symbol = procs
|
||||
.remove_single_symbol_specialization(*symbol, pattern_layout)
|
||||
.symbol_specializations
|
||||
.remove_single(*symbol)
|
||||
// Can happen when the symbol was never used under this body, and hence has no
|
||||
// requested specialization.
|
||||
.unwrap_or(*symbol);
|
||||
|
@ -6484,16 +6577,8 @@ fn store_pattern_help<'a>(
|
|||
return StorePattern::NotProductive(stmt);
|
||||
}
|
||||
NewtypeDestructure { arguments, .. } => match arguments.as_slice() {
|
||||
[(pattern, layout)] => {
|
||||
return store_pattern_help(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
pattern,
|
||||
*layout,
|
||||
outer_symbol,
|
||||
stmt,
|
||||
);
|
||||
[(pattern, _layout)] => {
|
||||
return store_pattern_help(env, procs, layout_cache, pattern, outer_symbol, stmt);
|
||||
}
|
||||
_ => {
|
||||
let mut fields = Vec::with_capacity_in(arguments.len(), env.arena);
|
||||
|
@ -6530,16 +6615,8 @@ fn store_pattern_help<'a>(
|
|||
);
|
||||
}
|
||||
OpaqueUnwrap { argument, .. } => {
|
||||
let (pattern, layout) = &**argument;
|
||||
return store_pattern_help(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
pattern,
|
||||
*layout,
|
||||
outer_symbol,
|
||||
stmt,
|
||||
);
|
||||
let (pattern, _layout) = &**argument;
|
||||
return store_pattern_help(env, procs, layout_cache, pattern, outer_symbol, stmt);
|
||||
}
|
||||
|
||||
RecordDestructure(destructs, [_single_field]) => {
|
||||
|
@ -6547,7 +6624,8 @@ fn store_pattern_help<'a>(
|
|||
match &destruct.typ {
|
||||
DestructType::Required(symbol) => {
|
||||
let specialization_symbol = procs
|
||||
.remove_single_symbol_specialization(*symbol, destruct.layout)
|
||||
.symbol_specializations
|
||||
.remove_single(*symbol)
|
||||
// Can happen when the symbol was never used under this body, and hence has no
|
||||
// requested specialization.
|
||||
.unwrap_or(*symbol);
|
||||
|
@ -6565,7 +6643,6 @@ fn store_pattern_help<'a>(
|
|||
procs,
|
||||
layout_cache,
|
||||
guard_pattern,
|
||||
destruct.layout,
|
||||
outer_symbol,
|
||||
stmt,
|
||||
);
|
||||
|
@ -6638,7 +6715,8 @@ fn store_tag_pattern<'a>(
|
|||
Identifier(symbol) => {
|
||||
// Pattern can define only one specialization
|
||||
let symbol = procs
|
||||
.remove_single_symbol_specialization(*symbol, arg_layout)
|
||||
.symbol_specializations
|
||||
.remove_single(*symbol)
|
||||
.unwrap_or(*symbol);
|
||||
|
||||
// store immediately in the given symbol
|
||||
|
@ -6659,15 +6737,7 @@ fn store_tag_pattern<'a>(
|
|||
let symbol = env.unique_symbol();
|
||||
|
||||
// first recurse, continuing to unpack symbol
|
||||
match store_pattern_help(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
argument,
|
||||
arg_layout,
|
||||
symbol,
|
||||
stmt,
|
||||
) {
|
||||
match store_pattern_help(env, procs, layout_cache, argument, symbol, stmt) {
|
||||
StorePattern::Productive(new) => {
|
||||
is_productive = true;
|
||||
stmt = new;
|
||||
|
@ -6727,7 +6797,8 @@ fn store_newtype_pattern<'a>(
|
|||
Identifier(symbol) => {
|
||||
// store immediately in the given symbol, removing it specialization if it had any
|
||||
let specialization_symbol = procs
|
||||
.remove_single_symbol_specialization(*symbol, arg_layout)
|
||||
.symbol_specializations
|
||||
.remove_single(*symbol)
|
||||
// Can happen when the symbol was never used under this body, and hence has no
|
||||
// requested specialization.
|
||||
.unwrap_or(*symbol);
|
||||
|
@ -6754,15 +6825,7 @@ fn store_newtype_pattern<'a>(
|
|||
let symbol = env.unique_symbol();
|
||||
|
||||
// first recurse, continuing to unpack symbol
|
||||
match store_pattern_help(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
argument,
|
||||
arg_layout,
|
||||
symbol,
|
||||
stmt,
|
||||
) {
|
||||
match store_pattern_help(env, procs, layout_cache, argument, symbol, stmt) {
|
||||
StorePattern::Productive(new) => {
|
||||
is_productive = true;
|
||||
stmt = new;
|
||||
|
@ -6810,7 +6873,8 @@ fn store_record_destruct<'a>(
|
|||
// A destructure can define at most one specialization!
|
||||
// Remove any requested specializations for this name now, since this is the definition site.
|
||||
let specialization_symbol = procs
|
||||
.remove_single_symbol_specialization(*symbol, destruct.layout)
|
||||
.symbol_specializations
|
||||
.remove_single(*symbol)
|
||||
// Can happen when the symbol was never used under this body, and hence has no
|
||||
// requested specialization.
|
||||
.unwrap_or(*symbol);
|
||||
|
@ -6825,7 +6889,8 @@ fn store_record_destruct<'a>(
|
|||
DestructType::Guard(guard_pattern) => match &guard_pattern {
|
||||
Identifier(symbol) => {
|
||||
let specialization_symbol = procs
|
||||
.remove_single_symbol_specialization(*symbol, destruct.layout)
|
||||
.symbol_specializations
|
||||
.remove_single(*symbol)
|
||||
// Can happen when the symbol was never used under this body, and hence has no
|
||||
// requested specialization.
|
||||
.unwrap_or(*symbol);
|
||||
|
@ -6863,15 +6928,7 @@ fn store_record_destruct<'a>(
|
|||
_ => {
|
||||
let symbol = env.unique_symbol();
|
||||
|
||||
match store_pattern_help(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
guard_pattern,
|
||||
destruct.layout,
|
||||
symbol,
|
||||
stmt,
|
||||
) {
|
||||
match store_pattern_help(env, procs, layout_cache, guard_pattern, symbol, stmt) {
|
||||
StorePattern::Productive(new) => {
|
||||
stmt = new;
|
||||
stmt = Stmt::Let(symbol, load, destruct.layout, env.arena.alloc(stmt));
|
||||
|
@ -6934,45 +6991,6 @@ fn can_reuse_symbol<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Reuses the specialized symbol for a given symbol and instance type. If no specialization symbol
|
||||
/// yet exists, one is created.
|
||||
fn reuse_symbol_or_specialize<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
procs: &mut Procs<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
symbol: Symbol,
|
||||
var: Variable,
|
||||
) -> Symbol {
|
||||
let wanted_layout = match layout_cache.from_var(env.arena, var, env.subs) {
|
||||
Ok(layout) => layout,
|
||||
// This can happen when the def symbol has a type error. In such cases just use the
|
||||
// def symbol, which is erroring.
|
||||
Err(_) => return symbol,
|
||||
};
|
||||
|
||||
// For the first specialization, always reuse the current symbol. The vast majority of defs
|
||||
// only have one instance type, so this preserves readability of the IR.
|
||||
let needs_fresh_symbol = procs
|
||||
.needed_symbol_specializations
|
||||
.keys()
|
||||
.any(|(s, _)| *s == symbol);
|
||||
|
||||
let mut make_specialized_symbol = || {
|
||||
if needs_fresh_symbol {
|
||||
env.unique_symbol()
|
||||
} else {
|
||||
symbol
|
||||
}
|
||||
};
|
||||
|
||||
let (_, specialized_symbol) = procs
|
||||
.needed_symbol_specializations
|
||||
.entry((symbol, wanted_layout))
|
||||
.or_insert_with(|| (var, make_specialized_symbol()));
|
||||
|
||||
*specialized_symbol
|
||||
}
|
||||
|
||||
fn possible_reuse_symbol_or_specialize<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
procs: &mut Procs<'a>,
|
||||
|
@ -6982,7 +7000,9 @@ fn possible_reuse_symbol_or_specialize<'a>(
|
|||
) -> Symbol {
|
||||
match can_reuse_symbol(env, procs, expr) {
|
||||
ReuseSymbol::Value(symbol) => {
|
||||
reuse_symbol_or_specialize(env, procs, layout_cache, symbol, var)
|
||||
procs
|
||||
.symbol_specializations
|
||||
.get_or_insert(env, layout_cache, symbol, var)
|
||||
}
|
||||
_ => env.unique_symbol(),
|
||||
}
|
||||
|
@ -7027,16 +7047,13 @@ where
|
|||
let result = build_rest(env, procs, layout_cache);
|
||||
|
||||
// The specializations we wanted of the symbol on the LHS of this alias.
|
||||
let needed_specializations_of_left = procs
|
||||
.needed_symbol_specializations
|
||||
.drain_filter(|(s, _), _| s == &left)
|
||||
.collect::<std::vec::Vec<_>>();
|
||||
let needed_specializations_of_left = procs.symbol_specializations.remove(left);
|
||||
|
||||
if procs.is_imported_module_thunk(right) {
|
||||
// if this is an imported symbol, then we must make sure it is
|
||||
// specialized, and wrap the original in a function pointer.
|
||||
let mut result = result;
|
||||
for (_, (variable, left)) in needed_specializations_of_left.into_iter() {
|
||||
for (_, (variable, left)) in needed_specializations_of_left {
|
||||
add_needed_external(procs, env, variable, right);
|
||||
|
||||
let res_layout = layout_cache.from_var(env.arena, variable, env.subs);
|
||||
|
@ -7056,14 +7073,17 @@ where
|
|||
// We need to lift all specializations of "left" to be specializations of "right".
|
||||
let mut scratchpad_update_specializations = std::vec::Vec::new();
|
||||
|
||||
let left_had_specialization_symbols = !needed_specializations_of_left.is_empty();
|
||||
let left_had_specialization_symbols = needed_specializations_of_left.len() > 0;
|
||||
|
||||
for ((_, layout), (specialized_var, specialized_sym)) in
|
||||
needed_specializations_of_left.into_iter()
|
||||
for (specialization_mark, (specialized_var, specialized_sym)) in
|
||||
needed_specializations_of_left
|
||||
{
|
||||
let old_specialized_sym = procs
|
||||
.needed_symbol_specializations
|
||||
.insert((right, layout), (specialized_var, specialized_sym));
|
||||
let old_specialized_sym = procs.symbol_specializations.get_or_insert_known(
|
||||
right,
|
||||
specialization_mark,
|
||||
specialized_var,
|
||||
specialized_sym,
|
||||
);
|
||||
|
||||
if let Some((_, old_specialized_sym)) = old_specialized_sym {
|
||||
scratchpad_update_specializations.push((old_specialized_sym, specialized_sym));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue