mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 07:49:17 +03:00
First pass at supporting multimorphic lambdas in lambda sets
This commit is contained in:
parent
1c40ad6127
commit
51978e08ed
@ -23,7 +23,11 @@ pub const STATIC_LIST_NAME: ConstName = ConstName(b"THIS IS A STATIC LIST");
|
||||
const ENTRY_POINT_NAME: &[u8] = b"mainForHost";
|
||||
|
||||
pub fn func_name_bytes(proc: &Proc) -> [u8; SIZE] {
|
||||
func_name_bytes_help(proc.name, proc.args.iter().map(|x| x.0), &proc.ret_layout)
|
||||
func_name_bytes_help(
|
||||
proc.name.call_name(),
|
||||
proc.args.iter().map(|x| x.0),
|
||||
&proc.ret_layout,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -106,8 +106,8 @@ trait Backend<'a> {
|
||||
proc: Proc<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
) -> (Vec<u8>, Vec<Relocation>, Vec<'a, (Symbol, String)>) {
|
||||
let layout_id = layout_ids.get(proc.name, &proc.ret_layout);
|
||||
let proc_name = self.symbol_to_string(proc.name, layout_id);
|
||||
let layout_id = layout_ids.get(proc.name.call_name(), &proc.ret_layout);
|
||||
let proc_name = self.symbol_to_string(proc.name.call_name(), layout_id);
|
||||
self.reset(proc_name, proc.is_self_recursive);
|
||||
self.load_args(proc.args, &proc.ret_layout);
|
||||
for (layout, sym) in proc.args {
|
||||
|
@ -4185,7 +4185,7 @@ fn build_procedures_help<'a, 'ctx, 'env>(
|
||||
|
||||
// only have top-level thunks for this proc's module in scope
|
||||
// this retain is not needed for correctness, but will cause less confusion when debugging
|
||||
let home = proc.name.module_id();
|
||||
let home = proc.name.call_name().module_id();
|
||||
current_scope.retain_top_level_thunks_for_module(home);
|
||||
|
||||
build_proc(
|
||||
@ -4559,7 +4559,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||
}
|
||||
};
|
||||
|
||||
let ident_string = proc.name.as_str(&env.interns);
|
||||
let ident_string = proc.name.call_name().as_str(&env.interns);
|
||||
let fn_name: String = format!("{}_1", ident_string);
|
||||
|
||||
build_closure_caller(
|
||||
|
@ -380,7 +380,7 @@ impl<'a> WasmBackend<'a> {
|
||||
println!("\ngenerating procedure {:?}\n", proc.name);
|
||||
}
|
||||
|
||||
self.append_proc_debug_name(proc.name);
|
||||
self.append_proc_debug_name(proc.name.call_name());
|
||||
|
||||
self.start_proc(proc);
|
||||
|
||||
|
@ -29,11 +29,12 @@ use roc_module::symbol::{
|
||||
IdentIds, IdentIdsByModule, Interns, ModuleId, ModuleIds, PQModuleName, PackageModuleIds,
|
||||
PackageQualified, Symbol,
|
||||
};
|
||||
use roc_mono::fresh_multimorphic_symbol;
|
||||
use roc_mono::ir::{
|
||||
CapturedSymbols, EntryPoint, ExternalSpecializations, PartialProc, Proc, ProcLayout, Procs,
|
||||
ProcsBase, UpdateModeIds,
|
||||
};
|
||||
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
||||
use roc_mono::layout::{LambdaName, Layout, LayoutCache, LayoutProblem};
|
||||
use roc_parse::ast::{self, Defs, ExtractSpaces, Spaced, StrLiteral, TypeAnnotation};
|
||||
use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
|
||||
use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
|
||||
@ -4545,8 +4546,12 @@ fn build_pending_specializations<'a>(
|
||||
// never gets called by Roc code, it will never
|
||||
// get specialized!
|
||||
if is_host_exposed {
|
||||
let layout_result =
|
||||
layout_cache.raw_from_var(mono_env.arena, expr_var, mono_env.subs);
|
||||
let layout_result = layout_cache.raw_from_var(
|
||||
mono_env.arena,
|
||||
expr_var,
|
||||
mono_env.subs,
|
||||
fresh_multimorphic_symbol!(mono_env),
|
||||
);
|
||||
|
||||
// cannot specialize when e.g. main's type contains type variables
|
||||
if let Err(e) = layout_result {
|
||||
@ -4571,7 +4576,7 @@ fn build_pending_specializations<'a>(
|
||||
|
||||
procs_base.host_specializations.insert_host_exposed(
|
||||
mono_env.subs,
|
||||
symbol,
|
||||
LambdaName::only_receiver(symbol),
|
||||
annotation,
|
||||
expr_var,
|
||||
);
|
||||
@ -4605,8 +4610,12 @@ fn build_pending_specializations<'a>(
|
||||
// never gets called by Roc code, it will never
|
||||
// get specialized!
|
||||
if is_host_exposed {
|
||||
let layout_result =
|
||||
layout_cache.raw_from_var(mono_env.arena, expr_var, mono_env.subs);
|
||||
let layout_result = layout_cache.raw_from_var(
|
||||
mono_env.arena,
|
||||
expr_var,
|
||||
mono_env.subs,
|
||||
fresh_multimorphic_symbol!(mono_env),
|
||||
);
|
||||
|
||||
// cannot specialize when e.g. main's type contains type variables
|
||||
if let Err(e) = layout_result {
|
||||
@ -4631,7 +4640,7 @@ fn build_pending_specializations<'a>(
|
||||
|
||||
procs_base.host_specializations.insert_host_exposed(
|
||||
mono_env.subs,
|
||||
symbol,
|
||||
LambdaName::only_receiver(symbol),
|
||||
annotation,
|
||||
expr_var,
|
||||
);
|
||||
@ -4683,8 +4692,12 @@ fn build_pending_specializations<'a>(
|
||||
// never gets called by Roc code, it will never
|
||||
// get specialized!
|
||||
if is_host_exposed {
|
||||
let layout_result =
|
||||
layout_cache.raw_from_var(mono_env.arena, expr_var, mono_env.subs);
|
||||
let layout_result = layout_cache.raw_from_var(
|
||||
mono_env.arena,
|
||||
expr_var,
|
||||
mono_env.subs,
|
||||
fresh_multimorphic_symbol!(mono_env),
|
||||
);
|
||||
|
||||
// cannot specialize when e.g. main's type contains type variables
|
||||
if let Err(e) = layout_result {
|
||||
@ -4709,7 +4722,7 @@ fn build_pending_specializations<'a>(
|
||||
|
||||
procs_base.host_specializations.insert_host_exposed(
|
||||
mono_env.subs,
|
||||
symbol,
|
||||
LambdaName::only_receiver(symbol),
|
||||
annotation,
|
||||
expr_var,
|
||||
);
|
||||
@ -4743,8 +4756,12 @@ fn build_pending_specializations<'a>(
|
||||
// never gets called by Roc code, it will never
|
||||
// get specialized!
|
||||
if is_host_exposed {
|
||||
let layout_result =
|
||||
layout_cache.raw_from_var(mono_env.arena, expr_var, mono_env.subs);
|
||||
let layout_result = layout_cache.raw_from_var(
|
||||
mono_env.arena,
|
||||
expr_var,
|
||||
mono_env.subs,
|
||||
fresh_multimorphic_symbol!(mono_env),
|
||||
);
|
||||
|
||||
// cannot specialize when e.g. main's type contains type variables
|
||||
if let Err(e) = layout_result {
|
||||
@ -4769,7 +4786,7 @@ fn build_pending_specializations<'a>(
|
||||
|
||||
procs_base.host_specializations.insert_host_exposed(
|
||||
mono_env.subs,
|
||||
symbol,
|
||||
LambdaName::only_receiver(symbol),
|
||||
annotation,
|
||||
expr_var,
|
||||
);
|
||||
|
@ -263,7 +263,7 @@ impl<'a> ParamMap<'a> {
|
||||
self.declarations[index + i] = param;
|
||||
}
|
||||
|
||||
self.visit_stmt(arena, proc.name, &proc.body);
|
||||
self.visit_stmt(arena, proc.name.call_name(), &proc.body);
|
||||
}
|
||||
|
||||
fn visit_proc_always_owned(
|
||||
@ -282,7 +282,7 @@ impl<'a> ParamMap<'a> {
|
||||
self.declarations[index + i] = param;
|
||||
}
|
||||
|
||||
self.visit_stmt(arena, proc.name, &proc.body);
|
||||
self.visit_stmt(arena, proc.name.call_name(), &proc.body);
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, arena: &'a Bump, _fnid: Symbol, stmt: &Stmt<'a>) {
|
||||
@ -852,10 +852,10 @@ impl<'a> BorrowInfState<'a> {
|
||||
|
||||
let ys = Vec::from_iter_in(proc.args.iter().map(|t| t.1), self.arena).into_bump_slice();
|
||||
self.update_param_set_symbols(ys);
|
||||
self.current_proc = proc.name;
|
||||
self.current_proc = proc.name.call_name();
|
||||
|
||||
// ensure that current_proc is in the owned map
|
||||
self.owned.entry(proc.name).or_default();
|
||||
self.owned.entry(proc.name.call_name()).or_default();
|
||||
|
||||
self.collect_stmt(param_map, &proc.body);
|
||||
self.update_param_map_declaration(param_map, param_offset, proc.args.len());
|
||||
|
@ -8,7 +8,7 @@ use crate::ir::{
|
||||
Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout,
|
||||
SelfRecursive, Stmt, UpdateModeId,
|
||||
};
|
||||
use crate::layout::{Builtin, Layout, UnionLayout};
|
||||
use crate::layout::{Builtin, LambdaName, Layout, UnionLayout};
|
||||
|
||||
mod equality;
|
||||
mod refcount;
|
||||
@ -343,7 +343,7 @@ impl<'a> CodeGenHelp<'a> {
|
||||
};
|
||||
|
||||
self.specializations[spec_index].proc = Some(Proc {
|
||||
name: proc_symbol,
|
||||
name: LambdaName::from_non_multimorphic(proc_symbol),
|
||||
args,
|
||||
body,
|
||||
closure_data_layout: None,
|
||||
|
@ -1406,7 +1406,7 @@ fn visit_proc<'a, 'i>(
|
||||
proc: &mut Proc<'a>,
|
||||
layout: ProcLayout<'a>,
|
||||
) {
|
||||
let params = match param_map.get_symbol(proc.name, layout) {
|
||||
let params = match param_map.get_symbol(proc.name.call_name(), layout) {
|
||||
Some(slice) => slice,
|
||||
None => Vec::from_iter_in(
|
||||
proc.args.iter().cloned().map(|(layout, symbol)| Param {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -67,8 +67,8 @@ impl<'a> RawFunctionLayout<'a> {
|
||||
matches!(self, RawFunctionLayout::ZeroArgumentThunk(_))
|
||||
}
|
||||
|
||||
fn new_help<'b>(
|
||||
env: &mut Env<'a, 'b>,
|
||||
fn new_help<'b, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, 'b, F>,
|
||||
var: Variable,
|
||||
content: Content,
|
||||
) -> Result<Self, LayoutProblem> {
|
||||
@ -153,8 +153,8 @@ impl<'a> RawFunctionLayout<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_from_lambda_set(
|
||||
_env: &mut Env<'a, '_>,
|
||||
fn layout_from_lambda_set<F: FreshMultimorphicSymbol>(
|
||||
_env: &mut Env<'a, '_, F>,
|
||||
_lset: subs::LambdaSet,
|
||||
) -> Result<Self, LayoutProblem> {
|
||||
unreachable!()
|
||||
@ -162,8 +162,8 @@ impl<'a> RawFunctionLayout<'a> {
|
||||
// Self::layout_from_flat_type(env, lset.as_tag_union())
|
||||
}
|
||||
|
||||
fn layout_from_flat_type(
|
||||
env: &mut Env<'a, '_>,
|
||||
fn layout_from_flat_type<F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
flat_type: FlatType,
|
||||
) -> Result<Self, LayoutProblem> {
|
||||
use roc_types::subs::FlatType::*;
|
||||
@ -184,8 +184,13 @@ impl<'a> RawFunctionLayout<'a> {
|
||||
let fn_args = fn_args.into_bump_slice();
|
||||
let ret = arena.alloc(ret);
|
||||
|
||||
let lambda_set =
|
||||
LambdaSet::from_var(env.arena, env.subs, closure_var, env.target_info)?;
|
||||
let lambda_set = LambdaSet::from_var(
|
||||
env.arena,
|
||||
env.subs,
|
||||
closure_var,
|
||||
env.target_info,
|
||||
env.fresh_multimorphic_symbol,
|
||||
)?;
|
||||
|
||||
Ok(Self::Function(fn_args, lambda_set, ret))
|
||||
}
|
||||
@ -216,7 +221,10 @@ impl<'a> RawFunctionLayout<'a> {
|
||||
/// Returns Err(()) if given an error, or Ok(Layout) if given a non-erroneous Structure.
|
||||
/// Panics if given a FlexVar or RigidVar, since those should have been
|
||||
/// monomorphized away already!
|
||||
fn from_var(env: &mut Env<'a, '_>, var: Variable) -> Result<Self, LayoutProblem> {
|
||||
fn from_var<F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
var: Variable,
|
||||
) -> Result<Self, LayoutProblem> {
|
||||
if env.is_seen(var) {
|
||||
unreachable!("The initial variable of a signature cannot be seen already")
|
||||
} else {
|
||||
@ -672,13 +680,16 @@ impl std::fmt::Debug for SetElement<'_> {
|
||||
impl std::fmt::Debug for LambdaSet<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
struct Helper<'a> {
|
||||
set: &'a [(Symbol, &'a [Layout<'a>])],
|
||||
set: &'a [(LambdaName, &'a [Layout<'a>])],
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Helper<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let entries = self.set.iter().map(|x| SetElement {
|
||||
symbol: x.0,
|
||||
symbol: match (x.0).0 {
|
||||
LambdaNameInner::Name(name) => name,
|
||||
LambdaNameInner::Multimorphic { alias, .. } => alias,
|
||||
},
|
||||
layout: x.1,
|
||||
});
|
||||
|
||||
@ -693,10 +704,79 @@ impl std::fmt::Debug for LambdaSet<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
enum LambdaNameInner {
|
||||
/// Standard lambda name assigned during canonicalize/constrain
|
||||
Name(Symbol),
|
||||
/// Sometimes we can end up with lambdas of the same name and different captures in the same
|
||||
/// lambda set, like [[Thunk U8, Thunk Str]]. See also https://github.com/rtfeldman/roc/issues/3336.
|
||||
/// We call such lambdas "multi-morphic".
|
||||
///
|
||||
/// The current compilation scheme in such cases is to assign an alias name for subsequent such
|
||||
/// lambda names, and then code-gen those lambda variants under a different `Proc`. In our
|
||||
/// example, the lambda set would be transformed to something like
|
||||
/// [[Thunk U8, Multimorphic(Thunk, ThunkAliasStr) Str]] which tells us to specialize the
|
||||
/// second variant using the proc `Thunk` but under the name `ThunkAliasStr`, with that
|
||||
/// particular closure layout.
|
||||
///
|
||||
/// Currently we do no de-duplication of alias names. This does make compilation faster, but
|
||||
/// also we should expect redundant multimorphic aliases to be somewhat rare, as that means a
|
||||
/// non-unitary lambda set is the same in multiple areas of a program.
|
||||
Multimorphic {
|
||||
/// The lambda we came from, e.g. `Thunk` in the example
|
||||
source: Symbol,
|
||||
/// The lambda we become, e.g. `ThunkAliasStr` in the example
|
||||
alias: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct LambdaName(LambdaNameInner);
|
||||
|
||||
impl LambdaName {
|
||||
#[inline(always)]
|
||||
pub fn source_name(&self) -> Symbol {
|
||||
match self.0 {
|
||||
LambdaNameInner::Name(name) => name,
|
||||
LambdaNameInner::Multimorphic { source, .. } => source,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn call_name(&self) -> Symbol {
|
||||
match self.0 {
|
||||
LambdaNameInner::Name(name) => name,
|
||||
LambdaNameInner::Multimorphic { alias, .. } => alias,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_multimorphic(&self) -> bool {
|
||||
matches!(self.0, LambdaNameInner::Multimorphic { .. })
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_non_multimorphic(name: Symbol) -> Self {
|
||||
Self(LambdaNameInner::Name(name))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn thunk(name: Symbol) -> Self {
|
||||
Self(LambdaNameInner::Name(name))
|
||||
}
|
||||
|
||||
// When the function name is known, so there can only be one possible receiver, in such cases
|
||||
// the lambda cannot be multimorphic.
|
||||
#[inline(always)]
|
||||
pub fn only_receiver(name: Symbol) -> Self {
|
||||
Self(LambdaNameInner::Name(name))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct LambdaSet<'a> {
|
||||
/// collection of function names and their closure arguments
|
||||
pub set: &'a [(Symbol, &'a [Layout<'a>])],
|
||||
pub set: &'a [(LambdaName, &'a [Layout<'a>])],
|
||||
/// how the closure will be represented at runtime
|
||||
representation: &'a Layout<'a>,
|
||||
}
|
||||
@ -726,8 +806,13 @@ impl<'a> LambdaSet<'a> {
|
||||
}
|
||||
|
||||
/// Does the lambda set contain the given symbol?
|
||||
/// NOTE: for multimorphic variants, this checks the alias name; the source name will always be
|
||||
/// the name of the first multimorphic variant.
|
||||
pub fn contains(&self, symbol: Symbol) -> bool {
|
||||
self.set.iter().any(|(s, _)| *s == symbol)
|
||||
self.set.iter().any(|(s, _)| match s.0 {
|
||||
LambdaNameInner::Name(name) => name == symbol,
|
||||
LambdaNameInner::Multimorphic { alias, .. } => alias == symbol,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_represented(&self) -> Option<Layout<'a>> {
|
||||
@ -741,12 +826,92 @@ impl<'a> LambdaSet<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn layout_for_member(&self, function_symbol: Symbol) -> ClosureRepresentation<'a> {
|
||||
pub fn layout_for_member_with_lambda_name(
|
||||
&self,
|
||||
lambda_name: LambdaName,
|
||||
) -> ClosureRepresentation<'a> {
|
||||
debug_assert!(
|
||||
self.set.iter().any(|(s, _)| *s == function_symbol),
|
||||
"function symbol not in set"
|
||||
self.set.iter().any(|(s, _)| *s == lambda_name),
|
||||
"lambda not in set"
|
||||
);
|
||||
|
||||
let comparator =
|
||||
|other_name: LambdaName, _other_captures_layouts: &[Layout]| other_name == lambda_name;
|
||||
|
||||
self.layout_for_member(comparator)
|
||||
}
|
||||
|
||||
pub fn find_lambda_name(
|
||||
&self,
|
||||
function_symbol: Symbol,
|
||||
captures_layouts: &[Layout],
|
||||
) -> LambdaName {
|
||||
debug_assert!(self.contains(function_symbol), "function symbol not in set");
|
||||
|
||||
let comparator = |other_name: LambdaName, other_captures_layouts: &[Layout]| {
|
||||
let other_name = match other_name.0 {
|
||||
LambdaNameInner::Name(name) => name,
|
||||
// Take the source, since we'll want to pick out the multimorphic name if it
|
||||
// matches
|
||||
LambdaNameInner::Multimorphic { source, .. } => source,
|
||||
};
|
||||
other_name == function_symbol
|
||||
&& captures_layouts.iter().eq(other_captures_layouts.iter())
|
||||
};
|
||||
|
||||
let (name, _) = self
|
||||
.set
|
||||
.iter()
|
||||
.find(|(name, layouts)| comparator(*name, layouts))
|
||||
.expect("no lambda set found");
|
||||
|
||||
*name
|
||||
}
|
||||
|
||||
// Layout for a single member of the lambda set, when you are constructing a proc, and already
|
||||
// know the multimorphic name (if any).
|
||||
// pub fn layout_for_member_constructing_proc(
|
||||
// &self,
|
||||
// lambda_name: LambdaName,
|
||||
// ) -> ClosureRepresentation<'a> {
|
||||
// debug_assert!(
|
||||
// self.set.iter().any(|(s, _)| *s == lambda_name),
|
||||
// "lambda not in set"
|
||||
// );
|
||||
|
||||
// let comparator =
|
||||
// |other_name: LambdaName, _other_captures_layouts: &[Layout]| other_name == lambda_name;
|
||||
|
||||
// self.layout_for_member(comparator)
|
||||
// }
|
||||
|
||||
// Layout for a single member of the lambda set, when you are constructing a closure
|
||||
// representation, and maybe need to pick out a multimorphic variant.
|
||||
// pub fn layout_for_member_constructing_closure_data(
|
||||
// &self,
|
||||
// function_symbol: Symbol,
|
||||
// captures_layouts: &[Layout],
|
||||
// ) -> ClosureRepresentation<'a> {
|
||||
// debug_assert!(self.contains(function_symbol), "function symbol not in set");
|
||||
|
||||
// let comparator = |other_name: LambdaName, other_captures_layouts: &[Layout]| {
|
||||
// let other_name = match other_name.0 {
|
||||
// LambdaNameInner::Name(name) => name,
|
||||
// // Take the source, since we'll want to pick out the multimorphic name if it
|
||||
// // matches
|
||||
// LambdaNameInner::Multimorphic { source, .. } => source,
|
||||
// };
|
||||
// other_name == function_symbol
|
||||
// && captures_layouts.iter().eq(other_captures_layouts.iter())
|
||||
// };
|
||||
|
||||
// self.layout_for_member(comparator)
|
||||
// }
|
||||
|
||||
fn layout_for_member<F>(&self, comparator: F) -> ClosureRepresentation<'a>
|
||||
where
|
||||
F: Fn(LambdaName, &[Layout]) -> bool,
|
||||
{
|
||||
match self.representation {
|
||||
Layout::Union(union) => {
|
||||
// here we rely on the fact that a union in a closure would be stored in a one-element record.
|
||||
@ -755,17 +920,22 @@ impl<'a> LambdaSet<'a> {
|
||||
UnionLayout::NonRecursive(_) => {
|
||||
// get the fields from the set, where they are sorted in alphabetic order
|
||||
// (and not yet sorted by their alignment)
|
||||
let (index, (_, fields)) = self
|
||||
let (index, (name, fields)) = self
|
||||
.set
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, (s, _))| *s == function_symbol)
|
||||
.find(|(_, (s, layouts))| comparator(*s, layouts))
|
||||
.unwrap();
|
||||
|
||||
let closure_name = match name.0 {
|
||||
LambdaNameInner::Name(name) => name,
|
||||
LambdaNameInner::Multimorphic { alias, .. } => alias,
|
||||
};
|
||||
|
||||
ClosureRepresentation::Union {
|
||||
tag_id: index as TagIdIntType,
|
||||
alphabetic_order_fields: fields,
|
||||
closure_name: function_symbol,
|
||||
closure_name,
|
||||
union_layout: *union,
|
||||
}
|
||||
}
|
||||
@ -782,12 +952,14 @@ impl<'a> LambdaSet<'a> {
|
||||
}
|
||||
}
|
||||
Layout::Struct { .. } => {
|
||||
debug_assert_eq!(self.set.len(), 1);
|
||||
|
||||
// get the fields from the set, where they are sorted in alphabetic order
|
||||
// (and not yet sorted by their alignment)
|
||||
let (_, fields) = self
|
||||
.set
|
||||
.iter()
|
||||
.find(|(s, _)| *s == function_symbol)
|
||||
.find(|(s, layouts)| comparator(*s, layouts))
|
||||
.unwrap();
|
||||
|
||||
ClosureRepresentation::AlphabeticOrderStruct(fields)
|
||||
@ -829,38 +1001,67 @@ impl<'a> LambdaSet<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_var(
|
||||
pub fn from_var<F>(
|
||||
arena: &'a Bump,
|
||||
subs: &Subs,
|
||||
closure_var: Variable,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<Self, LayoutProblem> {
|
||||
fresh_multimorphic_symbol: &mut F,
|
||||
) -> Result<Self, LayoutProblem>
|
||||
where
|
||||
F: FreshMultimorphicSymbol,
|
||||
{
|
||||
match roc_types::pretty_print::resolve_lambda_set(subs, closure_var) {
|
||||
ResolvedLambdaSet::Set(mut lambdas) => {
|
||||
// sort the tags; make sure ordering stays intact!
|
||||
lambdas.sort();
|
||||
lambdas.sort_by_key(|(sym, _)| *sym);
|
||||
|
||||
let mut set = Vec::with_capacity_in(lambdas.len(), arena);
|
||||
let mut set: Vec<(LambdaName, &[Layout])> =
|
||||
Vec::with_capacity_in(lambdas.len(), arena);
|
||||
|
||||
let mut last_function_symbol = None;
|
||||
for (function_symbol, variables) in lambdas.iter() {
|
||||
let mut arguments = Vec::with_capacity_in(variables.len(), arena);
|
||||
|
||||
let mut env = Env {
|
||||
arena,
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
target_info,
|
||||
fresh_multimorphic_symbol,
|
||||
};
|
||||
|
||||
for (function_symbol, variables) in lambdas.iter() {
|
||||
let mut arguments = Vec::with_capacity_in(variables.len(), arena);
|
||||
|
||||
for var in variables {
|
||||
arguments.push(Layout::from_var(&mut env, *var)?);
|
||||
}
|
||||
|
||||
set.push((*function_symbol, arguments.into_bump_slice()));
|
||||
let lambda_name = match last_function_symbol {
|
||||
None => LambdaNameInner::Name(*function_symbol),
|
||||
Some(last_function_symbol) => {
|
||||
if function_symbol != last_function_symbol {
|
||||
LambdaNameInner::Name(*function_symbol)
|
||||
} else {
|
||||
LambdaNameInner::Multimorphic {
|
||||
source: *function_symbol,
|
||||
alias: (*fresh_multimorphic_symbol)(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let lambda_name = LambdaName(lambda_name);
|
||||
|
||||
set.push((lambda_name, arguments.into_bump_slice()));
|
||||
|
||||
last_function_symbol = Some(function_symbol);
|
||||
}
|
||||
|
||||
let representation =
|
||||
arena.alloc(Self::make_representation(arena, subs, lambdas, target_info));
|
||||
let representation = arena.alloc(Self::make_representation(
|
||||
arena,
|
||||
subs,
|
||||
lambdas,
|
||||
target_info,
|
||||
fresh_multimorphic_symbol,
|
||||
));
|
||||
|
||||
Ok(LambdaSet {
|
||||
set: set.into_bump_slice(),
|
||||
@ -878,14 +1079,22 @@ impl<'a> LambdaSet<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_representation(
|
||||
fn make_representation<F: FreshMultimorphicSymbol>(
|
||||
arena: &'a Bump,
|
||||
subs: &Subs,
|
||||
tags: std::vec::Vec<(Symbol, std::vec::Vec<Variable>)>,
|
||||
target_info: TargetInfo,
|
||||
fresh_multimorphic_symbol: &mut F,
|
||||
) -> Layout<'a> {
|
||||
// otherwise, this is a closure with a payload
|
||||
let variant = union_sorted_tags_help(arena, tags, None, subs, target_info);
|
||||
let variant = union_sorted_tags_help(
|
||||
arena,
|
||||
tags,
|
||||
None,
|
||||
subs,
|
||||
target_info,
|
||||
fresh_multimorphic_symbol,
|
||||
);
|
||||
|
||||
use UnionVariant::*;
|
||||
match variant {
|
||||
@ -952,14 +1161,21 @@ pub enum Builtin<'a> {
|
||||
List(&'a Layout<'a>),
|
||||
}
|
||||
|
||||
pub struct Env<'a, 'b> {
|
||||
pub struct Env<'a, 'b, F>
|
||||
where
|
||||
F: FreshMultimorphicSymbol,
|
||||
{
|
||||
target_info: TargetInfo,
|
||||
arena: &'a Bump,
|
||||
seen: Vec<'a, Variable>,
|
||||
subs: &'b Subs,
|
||||
fresh_multimorphic_symbol: &'b mut F,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Env<'a, 'b> {
|
||||
impl<'a, 'b, F> Env<'a, 'b, F>
|
||||
where
|
||||
F: FreshMultimorphicSymbol,
|
||||
{
|
||||
fn is_seen(&self, var: Variable) -> bool {
|
||||
let var = self.subs.get_root_key_without_compacting(var);
|
||||
|
||||
@ -1009,8 +1225,8 @@ impl<'a> Layout<'a> {
|
||||
field_order_hash: FieldOrderHash::ZERO_FIELD_HASH,
|
||||
};
|
||||
|
||||
fn new_help<'b>(
|
||||
env: &mut Env<'a, 'b>,
|
||||
fn new_help<'b, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, 'b, F>,
|
||||
var: Variable,
|
||||
content: Content,
|
||||
) -> Result<Self, LayoutProblem> {
|
||||
@ -1068,7 +1284,10 @@ impl<'a> Layout<'a> {
|
||||
/// Returns Err(()) if given an error, or Ok(Layout) if given a non-erroneous Structure.
|
||||
/// Panics if given a FlexVar or RigidVar, since those should have been
|
||||
/// monomorphized away already!
|
||||
fn from_var(env: &mut Env<'a, '_>, var: Variable) -> Result<Self, LayoutProblem> {
|
||||
fn from_var<F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
var: Variable,
|
||||
) -> Result<Self, LayoutProblem> {
|
||||
if env.is_seen(var) {
|
||||
Ok(Layout::RecursivePointer)
|
||||
} else {
|
||||
@ -1392,12 +1611,16 @@ impl<'a> LayoutCache<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_var(
|
||||
pub fn from_var<F>(
|
||||
&mut self,
|
||||
arena: &'a Bump,
|
||||
var: Variable,
|
||||
subs: &Subs,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
fresh_multimorphic_symbol: &mut F,
|
||||
) -> Result<Layout<'a>, LayoutProblem>
|
||||
where
|
||||
F: FreshMultimorphicSymbol,
|
||||
{
|
||||
// Store things according to the root Variable, to avoid duplicate work.
|
||||
let var = subs.get_root_key_without_compacting(var);
|
||||
|
||||
@ -1406,16 +1629,18 @@ impl<'a> LayoutCache<'a> {
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
target_info: self.target_info,
|
||||
fresh_multimorphic_symbol,
|
||||
};
|
||||
|
||||
Layout::from_var(&mut env, var)
|
||||
}
|
||||
|
||||
pub fn raw_from_var(
|
||||
pub fn raw_from_var<F: FreshMultimorphicSymbol>(
|
||||
&mut self,
|
||||
arena: &'a Bump,
|
||||
var: Variable,
|
||||
subs: &Subs,
|
||||
fresh_multimorphic_symbol: &mut F,
|
||||
) -> Result<RawFunctionLayout<'a>, LayoutProblem> {
|
||||
// Store things according to the root Variable, to avoid duplicate work.
|
||||
let var = subs.get_root_key_without_compacting(var);
|
||||
@ -1425,6 +1650,7 @@ impl<'a> LayoutCache<'a> {
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
target_info: self.target_info,
|
||||
fresh_multimorphic_symbol,
|
||||
};
|
||||
RawFunctionLayout::from_var(&mut env, var)
|
||||
}
|
||||
@ -1679,8 +1905,8 @@ impl<'a> Builtin<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_from_lambda_set<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
fn layout_from_lambda_set<'a, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
lset: subs::LambdaSet,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
// Lambda set is just a tag union from the layout's perspective.
|
||||
@ -1709,8 +1935,8 @@ fn layout_from_lambda_set<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_from_flat_type<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
fn layout_from_flat_type<'a, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
flat_type: FlatType,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
use roc_types::subs::FlatType::*;
|
||||
@ -1818,8 +2044,13 @@ fn layout_from_flat_type<'a>(
|
||||
}
|
||||
}
|
||||
Func(_, closure_var, _) => {
|
||||
let lambda_set =
|
||||
LambdaSet::from_var(env.arena, env.subs, closure_var, env.target_info)?;
|
||||
let lambda_set = LambdaSet::from_var(
|
||||
env.arena,
|
||||
env.subs,
|
||||
closure_var,
|
||||
env.target_info,
|
||||
env.fresh_multimorphic_symbol,
|
||||
)?;
|
||||
|
||||
Ok(Layout::LambdaSet(lambda_set))
|
||||
}
|
||||
@ -1898,17 +2129,19 @@ fn layout_from_flat_type<'a>(
|
||||
|
||||
pub type SortedField<'a> = (Lowercase, Variable, Result<Layout<'a>, Layout<'a>>);
|
||||
|
||||
pub fn sort_record_fields<'a>(
|
||||
pub fn sort_record_fields<'a, F: FreshMultimorphicSymbol>(
|
||||
arena: &'a Bump,
|
||||
var: Variable,
|
||||
subs: &Subs,
|
||||
target_info: TargetInfo,
|
||||
fresh_multimorphic_symbol: &mut F,
|
||||
) -> Result<Vec<'a, SortedField<'a>>, LayoutProblem> {
|
||||
let mut env = Env {
|
||||
arena,
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
target_info,
|
||||
fresh_multimorphic_symbol,
|
||||
};
|
||||
|
||||
let (it, _) = match gather_fields_unsorted_iter(subs, RecordFields::empty(), var) {
|
||||
@ -1923,8 +2156,8 @@ pub fn sort_record_fields<'a>(
|
||||
sort_record_fields_help(&mut env, it)
|
||||
}
|
||||
|
||||
fn sort_record_fields_help<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
fn sort_record_fields_help<'a, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
fields_map: impl Iterator<Item = (Lowercase, RecordField<Variable>)>,
|
||||
) -> Result<Vec<'a, SortedField<'a>>, LayoutProblem> {
|
||||
let target_info = env.target_info;
|
||||
@ -2110,11 +2343,12 @@ impl<'a> WrappedVariant<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn union_sorted_tags<'a>(
|
||||
pub fn union_sorted_tags<'a, F: FreshMultimorphicSymbol>(
|
||||
arena: &'a Bump,
|
||||
var: Variable,
|
||||
subs: &Subs,
|
||||
target_info: TargetInfo,
|
||||
fresh_multimorphic_symbol: &mut F,
|
||||
) -> Result<UnionVariant<'a>, LayoutProblem> {
|
||||
let var =
|
||||
if let Content::RecursionVar { structure, .. } = subs.get_content_without_compacting(var) {
|
||||
@ -2135,7 +2369,7 @@ pub fn union_sorted_tags<'a>(
|
||||
| Err((_, Content::FlexVar(_) | Content::RigidVar(_)))
|
||||
| Err((_, Content::RecursionVar { .. })) => {
|
||||
let opt_rec_var = get_recursion_var(subs, var);
|
||||
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs, target_info)
|
||||
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs, target_info, fresh_multimorphic_symbol)
|
||||
}
|
||||
Err((_, Content::Error)) => return Err(LayoutProblem::Erroneous),
|
||||
Err(other) => panic!("invalid content in tag union variable: {:?}", other),
|
||||
@ -2164,8 +2398,8 @@ fn is_recursive_tag_union(layout: &Layout) -> bool {
|
||||
)
|
||||
}
|
||||
|
||||
fn union_sorted_tags_help_new<'a, L>(
|
||||
env: &mut Env<'a, '_>,
|
||||
fn union_sorted_tags_help_new<'a, L, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
tags_list: &[(&'_ L, &[Variable])],
|
||||
opt_rec_var: Option<Variable>,
|
||||
) -> UnionVariant<'a>
|
||||
@ -2355,12 +2589,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn union_sorted_tags_help<'a, L>(
|
||||
pub fn union_sorted_tags_help<'a, L, F: FreshMultimorphicSymbol>(
|
||||
arena: &'a Bump,
|
||||
mut tags_vec: std::vec::Vec<(L, std::vec::Vec<Variable>)>,
|
||||
opt_rec_var: Option<Variable>,
|
||||
subs: &Subs,
|
||||
target_info: TargetInfo,
|
||||
fresh_multimorphic_symbol: &mut F,
|
||||
) -> UnionVariant<'a>
|
||||
where
|
||||
L: Into<TagOrClosure> + Ord + Clone,
|
||||
@ -2373,6 +2608,7 @@ where
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
target_info,
|
||||
fresh_multimorphic_symbol,
|
||||
};
|
||||
|
||||
match tags_vec.len() {
|
||||
@ -2561,8 +2797,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_from_newtype<'a, L: Label>(
|
||||
env: &mut Env<'a, '_>,
|
||||
fn layout_from_newtype<'a, L: Label, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
tags: &UnsortedUnionLabels<L>,
|
||||
) -> Layout<'a> {
|
||||
debug_assert!(tags.is_newtype_wrapper(env.subs));
|
||||
@ -2585,7 +2821,10 @@ fn layout_from_newtype<'a, L: Label>(
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_from_union<'a, L>(env: &mut Env<'a, '_>, tags: &UnsortedUnionLabels<L>) -> Layout<'a>
|
||||
fn layout_from_union<'a, L, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
tags: &UnsortedUnionLabels<L>,
|
||||
) -> Layout<'a>
|
||||
where
|
||||
L: Label + Ord + Into<TagOrClosure>,
|
||||
{
|
||||
@ -2661,8 +2900,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_from_recursive_union<'a, L>(
|
||||
env: &mut Env<'a, '_>,
|
||||
fn layout_from_recursive_union<'a, L, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
rec_var: Variable,
|
||||
tags: &UnsortedUnionLabels<L>,
|
||||
) -> Result<Layout<'a>, LayoutProblem>
|
||||
@ -2843,8 +3082,8 @@ fn layout_from_num_content<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
fn dict_layout_from_key_value<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
fn dict_layout_from_key_value<'a, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
key_var: Variable,
|
||||
value_var: Variable,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
@ -2876,8 +3115,11 @@ fn dict_layout_from_key_value<'a>(
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn list_layout_from_elem<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
pub trait FreshMultimorphicSymbol: FnMut() -> Symbol {}
|
||||
impl<T> FreshMultimorphicSymbol for T where T: FnMut() -> Symbol {}
|
||||
|
||||
pub fn list_layout_from_elem<'a, F: FreshMultimorphicSymbol>(
|
||||
env: &mut Env<'a, '_, F>,
|
||||
element_var: Variable,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
let is_variable = |content| matches!(content, &Content::FlexVar(_) | &Content::RigidVar(_));
|
||||
@ -3032,7 +3274,7 @@ mod test {
|
||||
#[test]
|
||||
fn width_and_alignment_union_empty_struct() {
|
||||
let lambda_set = LambdaSet {
|
||||
set: &[(Symbol::LIST_MAP, &[])],
|
||||
set: &[(LambdaName::from_non_multimorphic(Symbol::LIST_MAP), &[])],
|
||||
representation: &Layout::UNIT,
|
||||
};
|
||||
|
||||
|
@ -1525,3 +1525,28 @@ fn tail_call_with_different_layout() {
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
#[ignore]
|
||||
fn lambda_sets_collide_with_captured_var() {
|
||||
indoc!(
|
||||
r#"
|
||||
capture : a -> ({} -> Str)
|
||||
capture = \val ->
|
||||
thunk =
|
||||
\{} ->
|
||||
when val is
|
||||
_ -> ""
|
||||
thunk
|
||||
|
||||
x : [True, False]
|
||||
|
||||
fun =
|
||||
when x is
|
||||
True -> capture 1u8
|
||||
False -> capture 1u64
|
||||
|
||||
fun {}
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
@ -130,9 +130,9 @@ impl<'a> ReplApp<'a> for CliApp {
|
||||
|
||||
/// Run user code that returns a type with a `Builtin` layout
|
||||
/// Size of the return value is statically determined from its Rust type
|
||||
fn call_function<Return, F>(&self, main_fn_name: &str, transform: F) -> Expr<'a>
|
||||
fn call_function<Return, F>(&self, main_fn_name: &str, mut transform: F) -> Expr<'a>
|
||||
where
|
||||
F: Fn(&'a Self::Memory, Return) -> Expr<'a>,
|
||||
F: FnMut(&'a Self::Memory, Return) -> Expr<'a>,
|
||||
Self::Memory: 'a,
|
||||
{
|
||||
run_jit_function!(self.lib, main_fn_name, Return, |v| transform(&CliMemory, v))
|
||||
@ -143,10 +143,10 @@ impl<'a> ReplApp<'a> for CliApp {
|
||||
&self,
|
||||
main_fn_name: &str,
|
||||
ret_bytes: usize,
|
||||
transform: F,
|
||||
mut transform: F,
|
||||
) -> T
|
||||
where
|
||||
F: Fn(&'a Self::Memory, usize) -> T,
|
||||
F: FnMut(&'a Self::Memory, usize) -> T,
|
||||
Self::Memory: 'a,
|
||||
{
|
||||
run_jit_function_dynamic_type!(self.lib, main_fn_name, ret_bytes, |v| transform(
|
||||
@ -305,6 +305,7 @@ fn gen_and_eval_llvm<'a>(
|
||||
|
||||
let app = CliApp { lib };
|
||||
|
||||
let mut env = env;
|
||||
let res_answer = jit_to_ast(
|
||||
&arena,
|
||||
&app,
|
||||
@ -312,6 +313,8 @@ fn gen_and_eval_llvm<'a>(
|
||||
main_fn_layout,
|
||||
content,
|
||||
&subs,
|
||||
home,
|
||||
env.interns.all_ident_ids.get_mut(&home).unwrap(),
|
||||
target_info,
|
||||
);
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_mono::fresh_multimorphic_symbol;
|
||||
use std::cmp::{max_by_key, min_by_key};
|
||||
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_module::called_via::CalledVia;
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use roc_mono::ir::ProcLayout;
|
||||
use roc_mono::layout::{
|
||||
union_sorted_tags_help, Builtin, Layout, LayoutCache, UnionLayout, UnionVariant, WrappedVariant,
|
||||
@ -19,10 +20,12 @@ use roc_types::subs::{Content, FlatType, GetSubsSlice, RecordFields, Subs, Union
|
||||
|
||||
use crate::{ReplApp, ReplAppMemory};
|
||||
|
||||
struct Env<'a, 'env> {
|
||||
struct Env<'a> {
|
||||
home: ModuleId,
|
||||
arena: &'a Bump,
|
||||
subs: &'env Subs,
|
||||
subs: &'a Subs,
|
||||
target_info: TargetInfo,
|
||||
ident_ids: &'a mut IdentIds,
|
||||
}
|
||||
|
||||
pub enum ToAstProblem {
|
||||
@ -45,12 +48,16 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>(
|
||||
layout: ProcLayout<'a>,
|
||||
content: &'a Content,
|
||||
subs: &'a Subs,
|
||||
module_id: ModuleId,
|
||||
ident_ids: &'a mut IdentIds,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<Expr<'a>, ToAstProblem> {
|
||||
let env = Env {
|
||||
let mut env = Env {
|
||||
arena,
|
||||
subs,
|
||||
target_info,
|
||||
home: module_id,
|
||||
ident_ids,
|
||||
};
|
||||
|
||||
match layout {
|
||||
@ -59,7 +66,7 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>(
|
||||
result,
|
||||
} => {
|
||||
// this is a thunk
|
||||
jit_to_ast_help(&env, app, main_fn_name, &result, content)
|
||||
jit_to_ast_help(&mut env, app, main_fn_name, &result, content)
|
||||
}
|
||||
_ => Err(ToAstProblem::FunctionLayout),
|
||||
}
|
||||
@ -86,7 +93,7 @@ enum NewtypeKind<'a> {
|
||||
///
|
||||
/// Returns (new type containers, optional alias content, real content).
|
||||
fn unroll_newtypes_and_aliases<'a>(
|
||||
env: &Env<'a, 'a>,
|
||||
env: &Env<'a>,
|
||||
mut content: &'a Content,
|
||||
) -> (Vec<'a, NewtypeKind<'a>>, Option<&'a Content>, &'a Content) {
|
||||
let mut newtype_containers = Vec::with_capacity_in(1, env.arena);
|
||||
@ -134,7 +141,7 @@ fn unroll_newtypes_and_aliases<'a>(
|
||||
}
|
||||
|
||||
fn apply_newtypes<'a>(
|
||||
env: &Env<'a, '_>,
|
||||
env: &Env<'a>,
|
||||
newtype_containers: Vec<'a, NewtypeKind<'a>>,
|
||||
mut expr: Expr<'a>,
|
||||
) -> Expr<'a> {
|
||||
@ -161,7 +168,7 @@ fn apply_newtypes<'a>(
|
||||
expr
|
||||
}
|
||||
|
||||
fn unroll_recursion_var<'a>(env: &Env<'a, 'a>, mut content: &'a Content) -> &'a Content {
|
||||
fn unroll_recursion_var<'a>(env: &Env<'a>, mut content: &'a Content) -> &'a Content {
|
||||
while let Content::RecursionVar { structure, .. } = content {
|
||||
content = env.subs.get_content_without_compacting(*structure);
|
||||
}
|
||||
@ -169,7 +176,7 @@ fn unroll_recursion_var<'a>(env: &Env<'a, 'a>, mut content: &'a Content) -> &'a
|
||||
}
|
||||
|
||||
fn get_tags_vars_and_variant<'a>(
|
||||
env: &Env<'a, '_>,
|
||||
env: &mut Env<'a>,
|
||||
tags: &UnionTags,
|
||||
opt_rec_var: Option<Variable>,
|
||||
) -> (MutMap<TagName, std::vec::Vec<Variable>>, UnionVariant<'a>) {
|
||||
@ -180,14 +187,20 @@ fn get_tags_vars_and_variant<'a>(
|
||||
|
||||
let vars_of_tag: MutMap<_, _> = tags_vec.iter().cloned().collect();
|
||||
|
||||
let union_variant =
|
||||
union_sorted_tags_help(env.arena, tags_vec, opt_rec_var, env.subs, env.target_info);
|
||||
let union_variant = union_sorted_tags_help(
|
||||
env.arena,
|
||||
tags_vec,
|
||||
opt_rec_var,
|
||||
env.subs,
|
||||
env.target_info,
|
||||
fresh_multimorphic_symbol!(env),
|
||||
);
|
||||
|
||||
(vars_of_tag, union_variant)
|
||||
}
|
||||
|
||||
fn expr_of_tag<'a, M: ReplAppMemory>(
|
||||
env: &Env<'a, 'a>,
|
||||
env: &mut Env<'a>,
|
||||
mem: &'a M,
|
||||
data_addr: usize,
|
||||
tag_name: &TagName,
|
||||
@ -211,7 +224,7 @@ fn expr_of_tag<'a, M: ReplAppMemory>(
|
||||
/// Gets the tag ID of a union variant, assuming that the tag ID is stored alongside (after) the
|
||||
/// tag data. The caller is expected to check that the tag ID is indeed stored this way.
|
||||
fn tag_id_from_data<'a, M: ReplAppMemory>(
|
||||
env: &Env<'a, 'a>,
|
||||
env: &Env<'a>,
|
||||
mem: &M,
|
||||
union_layout: UnionLayout,
|
||||
data_addr: usize,
|
||||
@ -239,7 +252,7 @@ fn tag_id_from_data<'a, M: ReplAppMemory>(
|
||||
/// - the tag ID
|
||||
/// - the address of the data of the union variant, unmasked if the pointer held the tag ID
|
||||
fn tag_id_from_recursive_ptr<'a, M: ReplAppMemory>(
|
||||
env: &Env<'a, 'a>,
|
||||
env: &Env<'a>,
|
||||
mem: &M,
|
||||
union_layout: UnionLayout,
|
||||
rec_addr: usize,
|
||||
@ -264,7 +277,7 @@ const OPAQUE_FUNCTION: Expr = Expr::Var {
|
||||
};
|
||||
|
||||
fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||
env: &Env<'a, 'a>,
|
||||
env: &mut Env<'a>,
|
||||
app: &'a A,
|
||||
main_fn_name: &str,
|
||||
layout: &Layout<'a>,
|
||||
@ -344,6 +357,11 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||
todo!("add support for rendering builtin {:?} to the REPL", other)
|
||||
}
|
||||
Layout::Struct { field_layouts, .. } => {
|
||||
let fields = [Layout::u64(), *layout];
|
||||
let layout = Layout::struct_no_name_order(&fields);
|
||||
|
||||
let result_stack_size = layout.stack_size(env.target_info);
|
||||
|
||||
let struct_addr_to_ast = |mem: &'a A::Memory, addr: usize| match raw_content {
|
||||
Content::Structure(FlatType::Record(fields, _)) => {
|
||||
Ok(struct_to_ast(env, mem, addr, *fields))
|
||||
@ -389,11 +407,6 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||
}
|
||||
};
|
||||
|
||||
let fields = [Layout::u64(), *layout];
|
||||
let layout = Layout::struct_no_name_order(&fields);
|
||||
|
||||
let result_stack_size = layout.stack_size(env.target_info);
|
||||
|
||||
app.call_function_dynamic_size(
|
||||
main_fn_name,
|
||||
result_stack_size as usize,
|
||||
@ -462,7 +475,7 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||
result.map(|e| apply_newtypes(env, newtype_containers, e))
|
||||
}
|
||||
|
||||
fn tag_name_to_expr<'a>(env: &Env<'a, '_>, tag_name: &TagName) -> Expr<'a> {
|
||||
fn tag_name_to_expr<'a>(env: &Env<'a>, tag_name: &TagName) -> Expr<'a> {
|
||||
Expr::Tag(env.arena.alloc_str(&tag_name.as_ident_str()))
|
||||
}
|
||||
|
||||
@ -475,7 +488,7 @@ enum WhenRecursive<'a> {
|
||||
}
|
||||
|
||||
fn addr_to_ast<'a, M: ReplAppMemory>(
|
||||
env: &Env<'a, 'a>,
|
||||
env: &mut Env<'a>,
|
||||
mem: &'a M,
|
||||
addr: usize,
|
||||
layout: &Layout<'a>,
|
||||
@ -770,7 +783,7 @@ fn addr_to_ast<'a, M: ReplAppMemory>(
|
||||
}
|
||||
|
||||
fn list_to_ast<'a, M: ReplAppMemory>(
|
||||
env: &Env<'a, 'a>,
|
||||
env: &mut Env<'a>,
|
||||
mem: &'a M,
|
||||
addr: usize,
|
||||
len: usize,
|
||||
@ -822,7 +835,7 @@ fn list_to_ast<'a, M: ReplAppMemory>(
|
||||
}
|
||||
|
||||
fn single_tag_union_to_ast<'a, M: ReplAppMemory>(
|
||||
env: &Env<'a, 'a>,
|
||||
env: &mut Env<'a>,
|
||||
mem: &'a M,
|
||||
addr: usize,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
@ -849,7 +862,7 @@ fn single_tag_union_to_ast<'a, M: ReplAppMemory>(
|
||||
}
|
||||
|
||||
fn sequence_of_expr<'a, I, M: ReplAppMemory>(
|
||||
env: &Env<'a, 'a>,
|
||||
env: &mut Env<'a>,
|
||||
mem: &'a M,
|
||||
addr: usize,
|
||||
sequence: I,
|
||||
@ -881,7 +894,7 @@ where
|
||||
}
|
||||
|
||||
fn struct_to_ast<'a, M: ReplAppMemory>(
|
||||
env: &Env<'a, 'a>,
|
||||
env: &mut Env<'a>,
|
||||
mem: &'a M,
|
||||
addr: usize,
|
||||
record_fields: RecordFields,
|
||||
@ -900,7 +913,12 @@ fn struct_to_ast<'a, M: ReplAppMemory>(
|
||||
|
||||
let inner_content = env.subs.get_content_without_compacting(field.into_inner());
|
||||
let field_layout = layout_cache
|
||||
.from_var(arena, field.into_inner(), env.subs)
|
||||
.from_var(
|
||||
arena,
|
||||
field.into_inner(),
|
||||
env.subs,
|
||||
fresh_multimorphic_symbol!(env),
|
||||
)
|
||||
.unwrap();
|
||||
let inner_layouts = arena.alloc([field_layout]);
|
||||
|
||||
@ -939,7 +957,12 @@ fn struct_to_ast<'a, M: ReplAppMemory>(
|
||||
for (label, field) in record_fields.sorted_iterator(subs, Variable::EMPTY_RECORD) {
|
||||
let content = subs.get_content_without_compacting(field.into_inner());
|
||||
let field_layout = layout_cache
|
||||
.from_var(arena, field.into_inner(), env.subs)
|
||||
.from_var(
|
||||
arena,
|
||||
field.into_inner(),
|
||||
env.subs,
|
||||
fresh_multimorphic_symbol!(env),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let loc_expr = &*arena.alloc(Loc {
|
||||
@ -1006,7 +1029,7 @@ fn unpack_two_element_tag_union(
|
||||
}
|
||||
|
||||
fn bool_to_ast<'a, M: ReplAppMemory>(
|
||||
env: &Env<'a, '_>,
|
||||
env: &Env<'a>,
|
||||
mem: &M,
|
||||
value: bool,
|
||||
content: &Content,
|
||||
@ -1081,7 +1104,7 @@ fn bool_to_ast<'a, M: ReplAppMemory>(
|
||||
}
|
||||
|
||||
fn byte_to_ast<'a, M: ReplAppMemory>(
|
||||
env: &Env<'a, '_>,
|
||||
env: &mut Env<'a>,
|
||||
mem: &M,
|
||||
value: u8,
|
||||
content: &Content,
|
||||
@ -1139,6 +1162,7 @@ fn byte_to_ast<'a, M: ReplAppMemory>(
|
||||
None,
|
||||
env.subs,
|
||||
env.target_info,
|
||||
fresh_multimorphic_symbol!(env),
|
||||
);
|
||||
|
||||
match union_variant {
|
||||
|
@ -12,7 +12,7 @@ pub trait ReplApp<'a> {
|
||||
/// The `transform` callback takes the app's memory and the returned value
|
||||
fn call_function<Return, F>(&self, main_fn_name: &str, transform: F) -> Expr<'a>
|
||||
where
|
||||
F: Fn(&'a Self::Memory, Return) -> Expr<'a>,
|
||||
F: FnMut(&'a Self::Memory, Return) -> Expr<'a>,
|
||||
Self::Memory: 'a;
|
||||
|
||||
/// Run user code that returns a struct or union, whose size is provided as an argument
|
||||
@ -24,7 +24,7 @@ pub trait ReplApp<'a> {
|
||||
transform: F,
|
||||
) -> T
|
||||
where
|
||||
F: Fn(&'a Self::Memory, usize) -> T,
|
||||
F: FnMut(&'a Self::Memory, usize) -> T,
|
||||
Self::Memory: 'a;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user