mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
WIP
This commit is contained in:
parent
d753e64b94
commit
e63eea7389
14 changed files with 1455 additions and 1031 deletions
|
@ -7,7 +7,7 @@ use roc_can::builtins::builtin_defs_map;
|
||||||
use roc_collections::all::{MutMap, MutSet};
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
use roc_fmt::annotation::Formattable;
|
use roc_fmt::annotation::Formattable;
|
||||||
use roc_fmt::annotation::{Newlines, Parens};
|
use roc_fmt::annotation::{Newlines, Parens};
|
||||||
use roc_gen::llvm::build::{build_proc, build_proc_header, OptLevel};
|
use roc_gen::llvm::build::{build_proc, build_proc_header_new, OptLevel};
|
||||||
use roc_load::file::LoadingProblem;
|
use roc_load::file::LoadingProblem;
|
||||||
use roc_parse::parser::SyntaxError;
|
use roc_parse::parser::SyntaxError;
|
||||||
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
||||||
|
@ -190,12 +190,13 @@ pub fn gen_and_eval<'a>(
|
||||||
// because their bodies may reference each other.
|
// because their bodies may reference each other.
|
||||||
let mut scope = roc_gen::llvm::build::Scope::default();
|
let mut scope = roc_gen::llvm::build::Scope::default();
|
||||||
for ((symbol, layout), proc) in procedures.drain() {
|
for ((symbol, layout), proc) in procedures.drain() {
|
||||||
let fn_val = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
let fn_val = build_proc_header_new(&env, &mut layout_ids, symbol, layout, &proc);
|
||||||
|
|
||||||
if proc.args.is_empty() {
|
if proc.args.is_empty() {
|
||||||
// this is a 0-argument thunk, i.e. a top-level constant definition
|
// this is a 0-argument thunk, i.e. a top-level constant definition
|
||||||
// it must be in-scope everywhere in the module!
|
// it must be in-scope everywhere in the module!
|
||||||
scope.insert_top_level_thunk(symbol, layout, fn_val);
|
// scope.insert_top_level_thunk(symbol, layout, fn_val);
|
||||||
|
todo!("fix type error");
|
||||||
}
|
}
|
||||||
|
|
||||||
headers.push((proc, fn_val));
|
headers.push((proc, fn_val));
|
||||||
|
@ -240,7 +241,7 @@ pub fn gen_and_eval<'a>(
|
||||||
&env,
|
&env,
|
||||||
&mut layout_ids,
|
&mut layout_ids,
|
||||||
main_fn_symbol,
|
main_fn_symbol,
|
||||||
&main_fn_layout,
|
main_fn_layout,
|
||||||
);
|
);
|
||||||
|
|
||||||
env.dibuilder.finalize();
|
env.dibuilder.finalize();
|
||||||
|
@ -271,7 +272,7 @@ pub fn gen_and_eval<'a>(
|
||||||
&arena,
|
&arena,
|
||||||
lib,
|
lib,
|
||||||
main_fn_name,
|
main_fn_name,
|
||||||
&main_fn_layout,
|
&arena.alloc(main_fn_layout).full(),
|
||||||
&content,
|
&content,
|
||||||
&env.interns,
|
&env.interns,
|
||||||
home,
|
home,
|
||||||
|
|
|
@ -146,12 +146,12 @@ pub fn gen_from_mono_module(
|
||||||
|
|
||||||
let mut scope = Scope::default();
|
let mut scope = Scope::default();
|
||||||
for ((symbol, layout), proc) in loaded.procedures {
|
for ((symbol, layout), proc) in loaded.procedures {
|
||||||
let fn_val = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
let fn_val = todo!("fix type error"); // build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
||||||
|
|
||||||
if proc.args.is_empty() {
|
if proc.args.is_empty() {
|
||||||
// this is a 0-argument thunk, i.e. a top-level constant definition
|
// this is a 0-argument thunk, i.e. a top-level constant definition
|
||||||
// it must be in-scope everywhere in the module!
|
// it must be in-scope everywhere in the module!
|
||||||
scope.insert_top_level_thunk(symbol, layout, fn_val);
|
todo!("fix type error"); // scope.insert_top_level_thunk(symbol, layout, fn_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
headers.push((proc, fn_val));
|
headers.push((proc, fn_val));
|
||||||
|
|
|
@ -148,8 +148,8 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
add_type(
|
add_type(
|
||||||
Symbol::NUM_MUL,
|
Symbol::NUM_MUL,
|
||||||
top_level_function(
|
top_level_function(
|
||||||
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
|
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
|
||||||
Box::new(num_type(flex(TVAR1))),
|
Box::new(int_type(flex(TVAR1))),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,8 @@ use roc_collections::all::{ImMap, MutSet};
|
||||||
use roc_module::ident::TagName;
|
use roc_module::ident::TagName;
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
use roc_mono::ir::{BranchInfo, CallType, JoinPointId, ModifyRc, Wrapped};
|
use roc_mono::ir::{BranchInfo, CallType, JoinPointId, ModifyRc, TopLevelFunctionLayout, Wrapped};
|
||||||
use roc_mono::layout::{Builtin, ClosureLayout, Layout, LayoutIds, MemoryMode, UnionLayout};
|
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, MemoryMode, UnionLayout};
|
||||||
use target_lexicon::CallingConvention;
|
use target_lexicon::CallingConvention;
|
||||||
|
|
||||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||||
|
@ -123,6 +123,15 @@ impl<'a, 'ctx> Scope<'a, 'ctx> {
|
||||||
self.top_level_thunks
|
self.top_level_thunks
|
||||||
.insert(symbol, (layout, function_value));
|
.insert(symbol, (layout, function_value));
|
||||||
}
|
}
|
||||||
|
pub fn insert_top_level_thunk_new(
|
||||||
|
&mut self,
|
||||||
|
symbol: Symbol,
|
||||||
|
layout: &'a TopLevelFunctionLayout<'a>,
|
||||||
|
function_value: FunctionValue<'ctx>,
|
||||||
|
) {
|
||||||
|
self.top_level_thunks
|
||||||
|
.insert(symbol, (layout.full(), function_value));
|
||||||
|
}
|
||||||
fn remove(&mut self, symbol: &Symbol) {
|
fn remove(&mut self, symbol: &Symbol) {
|
||||||
self.symbols.remove(symbol);
|
self.symbols.remove(symbol);
|
||||||
}
|
}
|
||||||
|
@ -562,10 +571,10 @@ pub fn promote_to_main_function<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
layout: &Layout<'a>,
|
layout: TopLevelFunctionLayout<'a>,
|
||||||
) -> (&'static str, FunctionValue<'ctx>) {
|
) -> (&'static str, FunctionValue<'ctx>) {
|
||||||
let fn_name = layout_ids
|
let fn_name = layout_ids
|
||||||
.get(symbol, layout)
|
.get(symbol, &(env.arena.alloc(layout).full()))
|
||||||
.to_symbol_string(symbol, &env.interns);
|
.to_symbol_string(symbol, &env.interns);
|
||||||
|
|
||||||
let roc_main_fn = env.module.get_function(&fn_name).unwrap();
|
let roc_main_fn = env.module.get_function(&fn_name).unwrap();
|
||||||
|
@ -2496,11 +2505,13 @@ fn build_switch_ir<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let cond_symbol = &cond_symbol;
|
let cond_symbol = &cond_symbol;
|
||||||
let (cond_value, stored_layout) = load_symbol_and_layout(scope, cond_symbol);
|
let (cond_value, stored_layout) = load_symbol_and_layout(scope, cond_symbol);
|
||||||
|
/*
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
&cond_layout, stored_layout,
|
&cond_layout, stored_layout,
|
||||||
"\nThis switch wants to match on this layout:\n\n {:?}\n\nBut the symbol {:?} that is matched on has layout:\n\n {:?}\n\n {:?}",
|
"\nThis switch wants to match on this layout:\n\n {:?}\n\nBut the symbol {:?} that is matched on has layout:\n\n {:?}\n\n {:?}",
|
||||||
cond_layout, cond_symbol, stored_layout, cond_value
|
cond_layout, cond_symbol, stored_layout, cond_value
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
let cont_block = context.append_basic_block(parent, "cont");
|
let cont_block = context.append_basic_block(parent, "cont");
|
||||||
|
|
||||||
|
@ -3041,6 +3052,18 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>(
|
||||||
wrapper_function
|
wrapper_function
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn build_proc_header_new<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
|
symbol: Symbol,
|
||||||
|
layout: TopLevelFunctionLayout<'a>,
|
||||||
|
proc: &roc_mono::ir::Proc<'a>,
|
||||||
|
) -> FunctionValue<'ctx> {
|
||||||
|
let layout = env.arena.alloc(layout).full();
|
||||||
|
|
||||||
|
build_proc_header(env, layout_ids, symbol, &layout, proc)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_proc_header<'a, 'ctx, 'env>(
|
pub fn build_proc_header<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
|
@ -3118,7 +3141,7 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
|
||||||
def_name: &str,
|
def_name: &str,
|
||||||
alias_symbol: Symbol,
|
alias_symbol: Symbol,
|
||||||
arguments: &[Layout<'a>],
|
arguments: &[Layout<'a>],
|
||||||
closure: &ClosureLayout<'a>,
|
lambda_set: &LambdaSet<'a>,
|
||||||
result: &Layout<'a>,
|
result: &Layout<'a>,
|
||||||
) {
|
) {
|
||||||
use inkwell::types::BasicType;
|
use inkwell::types::BasicType;
|
||||||
|
@ -3146,8 +3169,7 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_pointer_type = {
|
let function_pointer_type = {
|
||||||
let function_layout =
|
let function_layout = lambda_set.extend_function_layout(arena, arguments, result);
|
||||||
ClosureLayout::extend_function_layout(arena, arguments, *closure, result);
|
|
||||||
|
|
||||||
// this is already a (function) pointer type
|
// this is already a (function) pointer type
|
||||||
basic_type_from_layout(env, &function_layout)
|
basic_type_from_layout(env, &function_layout)
|
||||||
|
@ -3155,7 +3177,7 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
|
||||||
argument_types.push(function_pointer_type);
|
argument_types.push(function_pointer_type);
|
||||||
|
|
||||||
let closure_argument_type = {
|
let closure_argument_type = {
|
||||||
let basic_type = basic_type_from_layout(env, &closure.as_block_of_memory_layout());
|
let basic_type = basic_type_from_layout(env, &lambda_set.runtime_representation());
|
||||||
|
|
||||||
basic_type.ptr_type(AddressSpace::Generic)
|
basic_type.ptr_type(AddressSpace::Generic)
|
||||||
};
|
};
|
||||||
|
@ -3217,7 +3239,7 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
|
|
||||||
// STEP 4: build a {} -> u64 function that gives the size of the closure
|
// STEP 4: build a {} -> u64 function that gives the size of the closure
|
||||||
let layout = Layout::Closure(arguments, *closure, result);
|
let layout = Layout::Closure(arguments, *lambda_set, result);
|
||||||
build_host_exposed_alias_size(env, def_name, alias_symbol, &layout);
|
build_host_exposed_alias_size(env, def_name, alias_symbol, &layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,15 +109,10 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||||
basic_type_from_function_layout(env, args, None, ret_layout)
|
basic_type_from_function_layout(env, args, None, ret_layout)
|
||||||
}
|
}
|
||||||
Closure(args, closure_layout, ret_layout) => {
|
Closure(args, closure_layout, ret_layout) => {
|
||||||
let closure_data_layout = closure_layout.as_block_of_memory_layout();
|
let closure_data_layout = closure_layout.runtime_representation();
|
||||||
let closure_data = basic_type_from_layout(env, &closure_data_layout);
|
let closure_data = basic_type_from_layout(env, &closure_data_layout);
|
||||||
|
|
||||||
let function_pointer =
|
closure_data
|
||||||
basic_type_from_function_layout(env, args, Some(closure_data), ret_layout);
|
|
||||||
|
|
||||||
env.context
|
|
||||||
.struct_type(&[function_pointer, closure_data], false)
|
|
||||||
.as_basic_type_enum()
|
|
||||||
}
|
}
|
||||||
Pointer(layout) => basic_type_from_layout(env, &layout)
|
Pointer(layout) => basic_type_from_layout(env, &layout)
|
||||||
.ptr_type(AddressSpace::Generic)
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
|
|
@ -544,8 +544,8 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Closure(_, closure_layout, _) => {
|
Closure(_, lambda_set, _) => {
|
||||||
if closure_layout.contains_refcounted() {
|
if lambda_set.contains_refcounted() {
|
||||||
let wrapper_struct = value.into_struct_value();
|
let wrapper_struct = value.into_struct_value();
|
||||||
|
|
||||||
let field_ptr = env
|
let field_ptr = env
|
||||||
|
@ -560,7 +560,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
||||||
mode,
|
mode,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
field_ptr,
|
field_ptr,
|
||||||
&closure_layout.as_block_of_memory_layout(),
|
&lambda_set.runtime_representation(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ use roc_module::symbol::{
|
||||||
};
|
};
|
||||||
use roc_mono::ir::{
|
use roc_mono::ir::{
|
||||||
CapturedSymbols, ExternalSpecializations, PartialProc, PendingSpecialization, Proc, Procs,
|
CapturedSymbols, ExternalSpecializations, PartialProc, PendingSpecialization, Proc, Procs,
|
||||||
|
TopLevelFunctionLayout,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
||||||
use roc_parse::ast::{self, StrLiteral, TypeAnnotation};
|
use roc_parse::ast::{self, StrLiteral, TypeAnnotation};
|
||||||
|
@ -704,7 +705,7 @@ pub struct MonomorphizedModule<'a> {
|
||||||
pub can_problems: MutMap<ModuleId, Vec<roc_problem::can::Problem>>,
|
pub can_problems: MutMap<ModuleId, Vec<roc_problem::can::Problem>>,
|
||||||
pub type_problems: MutMap<ModuleId, Vec<solve::TypeError>>,
|
pub type_problems: MutMap<ModuleId, Vec<solve::TypeError>>,
|
||||||
pub mono_problems: MutMap<ModuleId, Vec<roc_mono::ir::MonoProblem>>,
|
pub mono_problems: MutMap<ModuleId, Vec<roc_mono::ir::MonoProblem>>,
|
||||||
pub procedures: MutMap<(Symbol, Layout<'a>), Proc<'a>>,
|
pub procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>,
|
||||||
pub exposed_to_host: MutMap<Symbol, Variable>,
|
pub exposed_to_host: MutMap<Symbol, Variable>,
|
||||||
pub header_sources: MutMap<ModuleId, (PathBuf, Box<str>)>,
|
pub header_sources: MutMap<ModuleId, (PathBuf, Box<str>)>,
|
||||||
pub sources: MutMap<ModuleId, (PathBuf, Box<str>)>,
|
pub sources: MutMap<ModuleId, (PathBuf, Box<str>)>,
|
||||||
|
@ -775,7 +776,7 @@ enum Msg<'a> {
|
||||||
ident_ids: IdentIds,
|
ident_ids: IdentIds,
|
||||||
layout_cache: LayoutCache<'a>,
|
layout_cache: LayoutCache<'a>,
|
||||||
external_specializations_requested: BumpMap<ModuleId, ExternalSpecializations<'a>>,
|
external_specializations_requested: BumpMap<ModuleId, ExternalSpecializations<'a>>,
|
||||||
procedures: MutMap<(Symbol, Layout<'a>), Proc<'a>>,
|
procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>,
|
||||||
problems: Vec<roc_mono::ir::MonoProblem>,
|
problems: Vec<roc_mono::ir::MonoProblem>,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
subs: Subs,
|
subs: Subs,
|
||||||
|
@ -817,7 +818,7 @@ struct State<'a> {
|
||||||
|
|
||||||
pub module_cache: ModuleCache<'a>,
|
pub module_cache: ModuleCache<'a>,
|
||||||
pub dependencies: Dependencies<'a>,
|
pub dependencies: Dependencies<'a>,
|
||||||
pub procedures: MutMap<(Symbol, Layout<'a>), Proc<'a>>,
|
pub procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>,
|
||||||
pub exposed_to_host: MutMap<Symbol, Variable>,
|
pub exposed_to_host: MutMap<Symbol, Variable>,
|
||||||
|
|
||||||
/// This is the "final" list of IdentIds, after canonicalization and constraint gen
|
/// This is the "final" list of IdentIds, after canonicalization and constraint gen
|
||||||
|
@ -847,7 +848,8 @@ struct State<'a> {
|
||||||
/// pending specializations in the same thread.
|
/// pending specializations in the same thread.
|
||||||
pub needs_specialization: MutSet<ModuleId>,
|
pub needs_specialization: MutSet<ModuleId>,
|
||||||
|
|
||||||
pub all_pending_specializations: MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization<'a>>>,
|
pub all_pending_specializations:
|
||||||
|
MutMap<Symbol, MutMap<TopLevelFunctionLayout<'a>, PendingSpecialization<'a>>>,
|
||||||
|
|
||||||
pub specializations_in_flight: u32,
|
pub specializations_in_flight: u32,
|
||||||
|
|
||||||
|
@ -3977,7 +3979,7 @@ fn add_def_to_module<'a>(
|
||||||
|
|
||||||
procs.insert_exposed(
|
procs.insert_exposed(
|
||||||
symbol,
|
symbol,
|
||||||
layout,
|
TopLevelFunctionLayout::from_layout(mono_env.arena, layout),
|
||||||
mono_env.arena,
|
mono_env.arena,
|
||||||
mono_env.subs,
|
mono_env.subs,
|
||||||
def.annotation,
|
def.annotation,
|
||||||
|
@ -4030,7 +4032,7 @@ fn add_def_to_module<'a>(
|
||||||
|
|
||||||
procs.insert_exposed(
|
procs.insert_exposed(
|
||||||
symbol,
|
symbol,
|
||||||
layout,
|
TopLevelFunctionLayout::from_layout(mono_env.arena, layout),
|
||||||
mono_env.arena,
|
mono_env.arena,
|
||||||
mono_env.subs,
|
mono_env.subs,
|
||||||
def.annotation,
|
def.annotation,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::ir::{Expr, JoinPointId, Param, Proc, Stmt};
|
use crate::ir::{Expr, JoinPointId, Param, Proc, Stmt, TopLevelFunctionLayout};
|
||||||
use crate::layout::Layout;
|
use crate::layout::Layout;
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
@ -15,14 +15,15 @@ fn should_borrow_layout(layout: &Layout) -> bool {
|
||||||
|
|
||||||
pub fn infer_borrow<'a>(
|
pub fn infer_borrow<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
procs: &MutMap<(Symbol, Layout<'a>), Proc<'a>>,
|
procs: &MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>,
|
||||||
) -> ParamMap<'a> {
|
) -> ParamMap<'a> {
|
||||||
let mut param_map = ParamMap {
|
let mut param_map = ParamMap {
|
||||||
items: MutMap::default(),
|
items: MutMap::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (key, proc) in procs {
|
for ((s, top_level), proc) in procs {
|
||||||
param_map.visit_proc(arena, proc, *key);
|
let key = (*s, arena.alloc(*top_level).full());
|
||||||
|
param_map.visit_proc(arena, proc, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut env = BorrowInfState {
|
let mut env = BorrowInfState {
|
||||||
|
@ -47,7 +48,8 @@ pub fn infer_borrow<'a>(
|
||||||
// mutually recursive functions (or just make all their arguments owned)
|
// mutually recursive functions (or just make all their arguments owned)
|
||||||
|
|
||||||
for (key, proc) in procs {
|
for (key, proc) in procs {
|
||||||
env.collect_proc(proc, key.1);
|
let layout = arena.alloc(key.1).full();
|
||||||
|
env.collect_proc(proc, layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !env.modified {
|
if !env.modified {
|
||||||
|
|
|
@ -165,11 +165,10 @@ impl<'a, 'i> Env<'a, 'i> {
|
||||||
self.constructor_map.insert(symbol, 0);
|
self.constructor_map.insert(symbol, 0);
|
||||||
self.layout_map.insert(symbol, Layout::Struct(fields));
|
self.layout_map.insert(symbol, Layout::Struct(fields));
|
||||||
}
|
}
|
||||||
Closure(arguments, closure_layout, result) => {
|
Closure(arguments, lambda_set, result) => {
|
||||||
let fpointer = Layout::FunctionPointer(arguments, result);
|
|
||||||
let fields = self.arena.alloc([fpointer, *closure_layout.layout]);
|
|
||||||
self.constructor_map.insert(symbol, 0);
|
self.constructor_map.insert(symbol, 0);
|
||||||
self.layout_map.insert(symbol, Layout::Struct(fields));
|
self.layout_map
|
||||||
|
.insert(symbol, lambda_set.runtime_representation());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -245,10 +244,12 @@ fn layout_for_constructor<'a>(
|
||||||
debug_assert_eq!(constructor, 0);
|
debug_assert_eq!(constructor, 0);
|
||||||
HasFields(fields)
|
HasFields(fields)
|
||||||
}
|
}
|
||||||
Closure(arguments, closure_layout, result) => {
|
Closure(arguments, lambda_set, result) => {
|
||||||
let fpointer = Layout::FunctionPointer(arguments, result);
|
// TODO can this be improved again?
|
||||||
let fields = arena.alloc([fpointer, *closure_layout.layout]);
|
// let fpointer = Layout::FunctionPointer(arguments, result);
|
||||||
HasFields(fields)
|
// let fields = arena.alloc([fpointer, *lambda_set.layout]);
|
||||||
|
// HasFields(fields)
|
||||||
|
ConstructorLayout::Unknown
|
||||||
}
|
}
|
||||||
other => unreachable!("weird layout {:?}", other),
|
other => unreachable!("weird layout {:?}", other),
|
||||||
}
|
}
|
||||||
|
@ -373,11 +374,12 @@ pub fn expand_and_cancel_proc<'a>(
|
||||||
|
|
||||||
introduced.push(*symbol);
|
introduced.push(*symbol);
|
||||||
}
|
}
|
||||||
Layout::Closure(arguments, closure_layout, result) => {
|
Layout::Closure(_arguments, _lambda_set, _result) => {
|
||||||
let fpointer = Layout::FunctionPointer(arguments, result);
|
// TODO can this be improved again?
|
||||||
let fields = env.arena.alloc([fpointer, *closure_layout.layout]);
|
// let fpointer = Layout::FunctionPointer(arguments, result);
|
||||||
env.insert_struct_info(*symbol, fields);
|
// let fields = env.arena.alloc([fpointer, *closure_layout.layout]);
|
||||||
introduced.push(*symbol);
|
// env.insert_struct_info(*symbol, fields);
|
||||||
|
// introduced.push(*symbol);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -35,7 +35,7 @@ pub enum Layout<'a> {
|
||||||
RecursivePointer,
|
RecursivePointer,
|
||||||
/// A function. The types of its arguments, then the type of its return value.
|
/// A function. The types of its arguments, then the type of its return value.
|
||||||
FunctionPointer(&'a [Layout<'a>], &'a Layout<'a>),
|
FunctionPointer(&'a [Layout<'a>], &'a Layout<'a>),
|
||||||
Closure(&'a [Layout<'a>], ClosureLayout<'a>, &'a Layout<'a>),
|
Closure(&'a [Layout<'a>], LambdaSet<'a>, &'a Layout<'a>),
|
||||||
Pointer(&'a Layout<'a>),
|
Pointer(&'a Layout<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,213 @@ impl<'a> UnionLayout<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct LambdaSet<'a> {
|
||||||
|
/// collection of function names and their closure arguments
|
||||||
|
pub set: &'a [(Symbol, &'a [Layout<'a>])],
|
||||||
|
/// how the closure will be represented at runtime
|
||||||
|
representation: &'a Layout<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// representation of the closure *for a particular function*
|
||||||
|
pub enum ClosureRepresentation<'a> {
|
||||||
|
/// the closure is represented as a union. Includes the tag ID!
|
||||||
|
Union {
|
||||||
|
tag_layout: &'a [Layout<'a>],
|
||||||
|
tag_name: TagName,
|
||||||
|
tag_id: u8,
|
||||||
|
union_size: u8,
|
||||||
|
},
|
||||||
|
/// the representation is anything but a union
|
||||||
|
Other(Layout<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LambdaSet<'a> {
|
||||||
|
pub fn runtime_representation(&self) -> Layout<'a> {
|
||||||
|
*self.representation
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn layout_for_member(&self, function_symbol: Symbol) -> ClosureRepresentation<'a> {
|
||||||
|
debug_assert!(
|
||||||
|
self.set.iter().any(|(s, _)| *s == function_symbol),
|
||||||
|
"function symbol not in set"
|
||||||
|
);
|
||||||
|
|
||||||
|
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.
|
||||||
|
// a closure representation that is itself union must be a of the shape `Closure1 ... | Closure2 ...`
|
||||||
|
match union {
|
||||||
|
UnionLayout::NonRecursive(tags) => {
|
||||||
|
let index = self
|
||||||
|
.set
|
||||||
|
.iter()
|
||||||
|
.position(|(s, _)| *s == function_symbol)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ClosureRepresentation::Union {
|
||||||
|
union_size: self.set.len() as u8,
|
||||||
|
tag_id: index as u8,
|
||||||
|
tag_layout: tags[index],
|
||||||
|
tag_name: TagName::Closure(function_symbol),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UnionLayout::Recursive(_) => todo!("recursive closures"),
|
||||||
|
UnionLayout::NonNullableUnwrapped(_) => todo!("recursive closures"),
|
||||||
|
UnionLayout::NullableWrapped {
|
||||||
|
nullable_id: _,
|
||||||
|
other_tags: _,
|
||||||
|
} => todo!("recursive closures"),
|
||||||
|
UnionLayout::NullableUnwrapped {
|
||||||
|
nullable_id: _,
|
||||||
|
other_fields: _,
|
||||||
|
} => todo!("recursive closures"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => ClosureRepresentation::Other(*self.representation),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend_function_layout(
|
||||||
|
&self,
|
||||||
|
arena: &'a Bump,
|
||||||
|
argument_layouts: &'a [Layout<'a>],
|
||||||
|
ret_layout: &'a Layout<'a>,
|
||||||
|
) -> Layout<'a> {
|
||||||
|
if let [] = self.set {
|
||||||
|
// TERRIBLE HACK for builting functions
|
||||||
|
Layout::FunctionPointer(argument_layouts, ret_layout)
|
||||||
|
} else if let [(_, [])] = self.set {
|
||||||
|
// this function does not have anything in its closure, and the lambda set is a
|
||||||
|
// singleton, so we pass no extra argument
|
||||||
|
Layout::FunctionPointer(argument_layouts, ret_layout)
|
||||||
|
} else {
|
||||||
|
let mut arguments = Vec::with_capacity_in(argument_layouts.len() + 1, arena);
|
||||||
|
arguments.extend(argument_layouts);
|
||||||
|
arguments.push(self.runtime_representation());
|
||||||
|
|
||||||
|
Layout::FunctionPointer(arguments.into_bump_slice(), ret_layout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_var(
|
||||||
|
arena: &'a Bump,
|
||||||
|
subs: &Subs,
|
||||||
|
closure_var: Variable,
|
||||||
|
) -> Result<Self, LayoutProblem> {
|
||||||
|
let mut tags = std::vec::Vec::new();
|
||||||
|
match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) {
|
||||||
|
Ok(()) | Err((_, Content::FlexVar(_))) if !tags.is_empty() => {
|
||||||
|
// sort the tags; make sure ordering stays intact!
|
||||||
|
tags.sort();
|
||||||
|
|
||||||
|
let mut set = Vec::with_capacity_in(tags.len(), arena);
|
||||||
|
|
||||||
|
let mut env = Env {
|
||||||
|
arena,
|
||||||
|
subs,
|
||||||
|
seen: MutSet::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (tag_name, variables) in tags.iter() {
|
||||||
|
if let TagName::Closure(function_symbol) = tag_name {
|
||||||
|
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()));
|
||||||
|
} else {
|
||||||
|
unreachable!("non-closure tag name in lambda set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let representation = arena.alloc(Self::make_representation(arena, subs, tags));
|
||||||
|
|
||||||
|
Ok(LambdaSet {
|
||||||
|
set: set.into_bump_slice(),
|
||||||
|
representation,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(()) | Err((_, Content::FlexVar(_))) => {
|
||||||
|
// TODO hack for builting functions.
|
||||||
|
Ok(LambdaSet {
|
||||||
|
set: &[],
|
||||||
|
representation: arena.alloc(Layout::Struct(&[])),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => panic!("called LambdaSet.from_var on invalid input"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_representation(
|
||||||
|
arena: &'a Bump,
|
||||||
|
subs: &Subs,
|
||||||
|
tags: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
|
||||||
|
) -> Layout<'a> {
|
||||||
|
// otherwise, this is a closure with a payload
|
||||||
|
let variant = union_sorted_tags_help(arena, tags, None, subs);
|
||||||
|
|
||||||
|
use UnionVariant::*;
|
||||||
|
match variant {
|
||||||
|
Never | Unit | UnitWithArguments => Layout::Struct(&[]),
|
||||||
|
BoolUnion { .. } => Layout::Builtin(Builtin::Int1),
|
||||||
|
ByteUnion(_) => Layout::Builtin(Builtin::Int8),
|
||||||
|
Unwrapped(_tag_name, layouts) => Layout::Struct(layouts.into_bump_slice()),
|
||||||
|
Wrapped(variant) => {
|
||||||
|
use WrappedVariant::*;
|
||||||
|
|
||||||
|
match variant {
|
||||||
|
NonRecursive {
|
||||||
|
sorted_tag_layouts: tags,
|
||||||
|
} => {
|
||||||
|
debug_assert!(tags.len() > 1);
|
||||||
|
|
||||||
|
// if the closed-over value is actually a layout, it should be wrapped in a 1-element record
|
||||||
|
debug_assert!(matches!(tags[0].0, TagName::Closure(_)));
|
||||||
|
|
||||||
|
let mut tag_arguments = Vec::with_capacity_in(tags.len(), arena);
|
||||||
|
|
||||||
|
for (_, tag_args) in tags.iter() {
|
||||||
|
tag_arguments.push(&tag_args[0..]);
|
||||||
|
}
|
||||||
|
Layout::Union(UnionLayout::NonRecursive(tag_arguments.into_bump_slice()))
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => panic!("handle recursive layouts"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_wrapped(&self) -> crate::ir::Wrapped {
|
||||||
|
use crate::ir::Wrapped;
|
||||||
|
|
||||||
|
match self.representation {
|
||||||
|
Layout::Struct(fields) if fields.len() == 1 => Wrapped::SingleElementRecord,
|
||||||
|
Layout::Struct(_) => Wrapped::RecordOrSingleTagUnion,
|
||||||
|
Layout::Union(_) => Wrapped::MultiTagUnion,
|
||||||
|
_ => Wrapped::SingleElementRecord,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stack_size(&self, pointer_size: u32) -> u32 {
|
||||||
|
self.representation.stack_size(pointer_size)
|
||||||
|
}
|
||||||
|
pub fn contains_refcounted(&self) -> bool {
|
||||||
|
self.representation.contains_refcounted()
|
||||||
|
}
|
||||||
|
pub fn safe_to_memcpy(&self) -> bool {
|
||||||
|
self.representation.safe_to_memcpy()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alignment_bytes(&self, pointer_size: u32) -> u32 {
|
||||||
|
self.representation.alignment_bytes(pointer_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct ClosureLayout<'a> {
|
pub struct ClosureLayout<'a> {
|
||||||
/// the layout that this specific closure captures
|
/// the layout that this specific closure captures
|
||||||
|
@ -181,22 +388,12 @@ impl<'a> ClosureLayout<'a> {
|
||||||
let mut tags = std::vec::Vec::new();
|
let mut tags = std::vec::Vec::new();
|
||||||
match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) {
|
match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) {
|
||||||
Ok(()) | Err((_, Content::FlexVar(_))) if !tags.is_empty() => {
|
Ok(()) | Err((_, Content::FlexVar(_))) if !tags.is_empty() => {
|
||||||
// special-case the `[ Closure1, Closure2, Closure3 ]` case, where none of
|
|
||||||
// the tags have a payload
|
|
||||||
let all_no_payload = tags.iter().all(|(_, arguments)| arguments.is_empty());
|
|
||||||
|
|
||||||
if all_no_payload {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, this is a closure with a payload
|
// otherwise, this is a closure with a payload
|
||||||
let variant = union_sorted_tags_help(arena, tags, None, subs);
|
let variant = union_sorted_tags_help(arena, tags, None, subs);
|
||||||
|
|
||||||
use UnionVariant::*;
|
use UnionVariant::*;
|
||||||
match variant {
|
match variant {
|
||||||
Never => Ok(None),
|
Never | Unit | UnitWithArguments => {
|
||||||
Unit => Ok(None),
|
|
||||||
UnitWithArguments => {
|
|
||||||
// the closure layout is zero-sized, but there is something in it (e.g. `{}`)
|
// the closure layout is zero-sized, but there is something in it (e.g. `{}`)
|
||||||
|
|
||||||
let closure_layout = ClosureLayout::from_unit(arena);
|
let closure_layout = ClosureLayout::from_unit(arena);
|
||||||
|
@ -641,7 +838,7 @@ impl<'a> Layout<'a> {
|
||||||
Layout::FunctionPointer(_, _) => pointer_size,
|
Layout::FunctionPointer(_, _) => pointer_size,
|
||||||
Layout::Pointer(_) => pointer_size,
|
Layout::Pointer(_) => pointer_size,
|
||||||
Layout::Closure(_, captured, _) => {
|
Layout::Closure(_, captured, _) => {
|
||||||
pointer_size.max(captured.layout.alignment_bytes(pointer_size))
|
pointer_size.max(captured.alignment_bytes(pointer_size))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -731,7 +928,9 @@ impl<'a> Layout<'a> {
|
||||||
Closure(args, closure_layout, result) => {
|
Closure(args, closure_layout, result) => {
|
||||||
let args_doc = args.iter().map(|x| x.to_doc(alloc, Parens::InFunction));
|
let args_doc = args.iter().map(|x| x.to_doc(alloc, Parens::InFunction));
|
||||||
|
|
||||||
let bom = closure_layout.layout.to_doc(alloc, Parens::NotNeeded);
|
let bom = closure_layout
|
||||||
|
.representation
|
||||||
|
.to_doc(alloc, Parens::NotNeeded);
|
||||||
|
|
||||||
alloc
|
alloc
|
||||||
.intersperse(args_doc, ", ")
|
.intersperse(args_doc, ", ")
|
||||||
|
@ -1111,10 +1310,9 @@ fn layout_from_flat_type<'a>(
|
||||||
let fn_args = fn_args.into_bump_slice();
|
let fn_args = fn_args.into_bump_slice();
|
||||||
let ret = arena.alloc(ret);
|
let ret = arena.alloc(ret);
|
||||||
|
|
||||||
match ClosureLayout::from_var(env.arena, env.subs, closure_var)? {
|
let lambda_set = LambdaSet::from_var(env.arena, env.subs, closure_var)?;
|
||||||
Some(closure_layout) => Ok(Layout::Closure(fn_args, closure_layout, ret)),
|
|
||||||
None => Ok(Layout::FunctionPointer(fn_args, ret)),
|
Ok(Layout::Closure(fn_args, lambda_set, ret))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Record(fields, ext_var) => {
|
Record(fields, ext_var) => {
|
||||||
// extract any values from the ext_var
|
// extract any values from the ext_var
|
||||||
|
|
|
@ -16,7 +16,7 @@ mod test_mono {
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::ir::Proc;
|
use roc_mono::ir::Proc;
|
||||||
use roc_mono::layout::Layout;
|
use roc_mono::ir::TopLevelFunctionLayout;
|
||||||
|
|
||||||
fn promote_expr_to_module(src: &str) -> String {
|
fn promote_expr_to_module(src: &str) -> String {
|
||||||
let mut buffer =
|
let mut buffer =
|
||||||
|
@ -105,7 +105,7 @@ mod test_mono {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fn verify_procedures(
|
fn verify_procedures(
|
||||||
expected: &str,
|
expected: &str,
|
||||||
procedures: MutMap<(Symbol, Layout<'_>), Proc<'_>>,
|
procedures: MutMap<(Symbol, TopLevelFunctionLayout<'_>), Proc<'_>>,
|
||||||
main_fn_symbol: Symbol,
|
main_fn_symbol: Symbol,
|
||||||
) {
|
) {
|
||||||
let index = procedures
|
let index = procedures
|
||||||
|
@ -658,7 +658,7 @@ mod test_mono {
|
||||||
ret Test.3;
|
ret Test.3;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.2 = FunctionPointer Dict.2;
|
let Test.2 = CallByName Dict.2;
|
||||||
let Test.1 = CallByName Dict.8 Test.2;
|
let Test.1 = CallByName Dict.8 Test.2;
|
||||||
ret Test.1;
|
ret Test.1;
|
||||||
"#
|
"#
|
||||||
|
@ -2397,8 +2397,7 @@ mod test_mono {
|
||||||
|
|
||||||
procedure Test.1 (Test.5):
|
procedure Test.1 (Test.5):
|
||||||
let Test.2 = 41i64;
|
let Test.2 = 41i64;
|
||||||
let Test.12 = FunctionPointer Test.3;
|
let Test.11 = Struct {Test.2};
|
||||||
let Test.11 = Struct {Test.12, Test.2};
|
|
||||||
let Test.10 = Array [Test.11];
|
let Test.10 = Array [Test.11];
|
||||||
ret Test.10;
|
ret Test.10;
|
||||||
|
|
||||||
|
|
|
@ -913,7 +913,7 @@ fn annotation_without_body() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn closure() {
|
fn simple_closure() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -1012,6 +1012,7 @@ fn specialize_closure() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn io_poc_effect() {
|
fn io_poc_effect() {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -1042,6 +1043,7 @@ fn io_poc_effect() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn io_poc_desugared() {
|
fn io_poc_desugared() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -1651,7 +1653,7 @@ fn binary_tree_double_pattern_match() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unified_empty_closure() {
|
fn unified_empty_closure_bool() {
|
||||||
// none of the Closure tags will have a payload
|
// none of the Closure tags will have a payload
|
||||||
// this was not handled correctly in the past
|
// this was not handled correctly in the past
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
|
@ -1675,6 +1677,32 @@ fn unified_empty_closure() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
fn unified_empty_closure_byte() {
|
||||||
|
// none of the Closure tags will have a payload
|
||||||
|
// this was not handled correctly in the past
|
||||||
|
assert_non_opt_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
foo = \{} ->
|
||||||
|
when A is
|
||||||
|
A -> (\_ -> 3.14)
|
||||||
|
B -> (\_ -> 3.14)
|
||||||
|
C -> (\_ -> 3.14)
|
||||||
|
|
||||||
|
main : Float *
|
||||||
|
main =
|
||||||
|
(foo {}) 0
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
3.14,
|
||||||
|
f64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn task_always_twice() {
|
fn task_always_twice() {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -1719,6 +1747,7 @@ fn task_always_twice() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn wildcard_rigid() {
|
fn wildcard_rigid() {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -2227,6 +2256,38 @@ fn build_then_apply_closure() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn expanded_result() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
a : Result I64 Str
|
||||||
|
a = Ok 1
|
||||||
|
|
||||||
|
after = \x, f ->
|
||||||
|
when x is
|
||||||
|
Ok v -> f v
|
||||||
|
Err e -> Err e
|
||||||
|
|
||||||
|
main : I64
|
||||||
|
main =
|
||||||
|
helper = after a (\x -> Ok x)
|
||||||
|
|
||||||
|
when helper is
|
||||||
|
Ok v -> v
|
||||||
|
Err _ -> 0
|
||||||
|
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
4,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn backpassing_result() {
|
fn backpassing_result() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub fn helper<'a>(
|
||||||
ignore_problems: bool,
|
ignore_problems: bool,
|
||||||
context: &'a inkwell::context::Context,
|
context: &'a inkwell::context::Context,
|
||||||
) -> (&'static str, String, Library) {
|
) -> (&'static str, String, Library) {
|
||||||
use roc_gen::llvm::build::{build_proc, build_proc_header, Scope};
|
use roc_gen::llvm::build::{build_proc, build_proc_header, build_proc_header_new, Scope};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
let filename = PathBuf::from("Test.roc");
|
let filename = PathBuf::from("Test.roc");
|
||||||
|
@ -239,12 +239,12 @@ pub fn helper<'a>(
|
||||||
// because their bodies may reference each other.
|
// because their bodies may reference each other.
|
||||||
let mut scope = Scope::default();
|
let mut scope = Scope::default();
|
||||||
for ((symbol, layout), proc) in procedures.drain() {
|
for ((symbol, layout), proc) in procedures.drain() {
|
||||||
let fn_val = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
let fn_val = build_proc_header_new(&env, &mut layout_ids, symbol, layout, &proc);
|
||||||
|
|
||||||
if proc.args.is_empty() {
|
if proc.args.is_empty() {
|
||||||
// this is a 0-argument thunk, i.e. a top-level constant definition
|
// this is a 0-argument thunk, i.e. a top-level constant definition
|
||||||
// it must be in-scope everywhere in the module!
|
// it must be in-scope everywhere in the module!
|
||||||
scope.insert_top_level_thunk(symbol, layout, fn_val);
|
scope.insert_top_level_thunk_new(symbol, arena.alloc(layout), fn_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
headers.push((proc, fn_val));
|
headers.push((proc, fn_val));
|
||||||
|
@ -275,7 +275,7 @@ pub fn helper<'a>(
|
||||||
mode,
|
mode,
|
||||||
);
|
);
|
||||||
|
|
||||||
// fn_val.print_to_stderr();
|
fn_val.print_to_stderr();
|
||||||
// module.print_to_stderr();
|
// module.print_to_stderr();
|
||||||
|
|
||||||
panic!(
|
panic!(
|
||||||
|
@ -289,7 +289,7 @@ pub fn helper<'a>(
|
||||||
&env,
|
&env,
|
||||||
&mut layout_ids,
|
&mut layout_ids,
|
||||||
main_fn_symbol,
|
main_fn_symbol,
|
||||||
&main_fn_layout,
|
main_fn_layout,
|
||||||
);
|
);
|
||||||
|
|
||||||
env.dibuilder.finalize();
|
env.dibuilder.finalize();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue