Merge pull request #3409 from rtfeldman/i3224

Compile lambdas that have an empty lambda set
This commit is contained in:
Folkert de Vries 2022-07-06 22:22:48 +02:00 committed by GitHub
commit 957c4258b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 128 additions and 17 deletions

View file

@ -104,6 +104,9 @@ flags! {
/// Prints debug information during the alias analysis pass.
ROC_DEBUG_ALIAS_ANALYSIS
/// Print to stderr when a runtime error function is generated.
ROC_PRINT_RUNTIME_ERROR_GEN
// ===LLVM Gen===
/// Prints LLVM function verification output.

View file

@ -15,6 +15,7 @@ use roc_debug_flags::dbg_do;
#[cfg(debug_assertions)]
use roc_debug_flags::{
ROC_PRINT_IR_AFTER_REFCOUNT, ROC_PRINT_IR_AFTER_RESET_REUSE, ROC_PRINT_IR_AFTER_SPECIALIZATION,
ROC_PRINT_RUNTIME_ERROR_GEN,
};
use roc_derive_key::GlobalDerivedSymbols;
use roc_error_macros::{internal_error, todo_abilities};
@ -2807,22 +2808,26 @@ fn generate_runtime_error_function<'a>(
)
.unwrap();
eprintln!(
"emitted runtime error function {:?} for layout {:?}",
&msg, layout
);
dbg_do!(ROC_PRINT_RUNTIME_ERROR_GEN, {
eprintln!(
"emitted runtime error function {:?} for layout {:?}",
&msg, layout
);
});
let runtime_error = Stmt::RuntimeError(msg.into_bump_str());
let (args, ret_layout) = match layout {
RawFunctionLayout::Function(arg_layouts, lambda_set, ret_layout) => {
let mut args = Vec::with_capacity_in(arg_layouts.len(), env.arena);
let real_arg_layouts = lambda_set.extend_argument_list(env.arena, arg_layouts);
let mut args = Vec::with_capacity_in(real_arg_layouts.len(), env.arena);
for arg in arg_layouts {
args.push((*arg, env.unique_symbol()));
}
args.push((Layout::LambdaSet(lambda_set), Symbol::ARG_CLOSURE));
if real_arg_layouts.len() != arg_layouts.len() {
args.push((Layout::LambdaSet(lambda_set), Symbol::ARG_CLOSURE));
}
(args.into_bump_slice(), *ret_layout)
}
@ -2878,6 +2883,15 @@ fn specialize_external<'a>(
let specialized =
build_specialized_proc_from_var(env, layout_cache, lambda_name, pattern_symbols, fn_var)?;
let recursivity = if partial_proc.is_self_recursive {
SelfRecursive::SelfRecursive(JoinPointId(env.unique_symbol()))
} else {
SelfRecursive::NotSelfRecursive
};
let body = partial_proc.body.clone();
let body_var = partial_proc.body_var;
// determine the layout of aliases/rigids exposed to the host
let host_exposed_layouts = if host_exposed_variables.is_empty() {
HostExposedLayouts::NotHostExposed
@ -2922,6 +2936,7 @@ fn specialize_external<'a>(
let body = match_on_lambda_set(
env,
procs,
lambda_set,
Symbol::ARG_CLOSURE,
argument_symbols.into_bump_slice(),
@ -2965,15 +2980,7 @@ fn specialize_external<'a>(
}
};
let recursivity = if partial_proc.is_self_recursive {
SelfRecursive::SelfRecursive(JoinPointId(env.unique_symbol()))
} else {
SelfRecursive::NotSelfRecursive
};
let body = partial_proc.body.clone();
let mut specialized_body = from_can(env, partial_proc.body_var, body, procs, layout_cache);
let mut specialized_body = from_can(env, body_var, body, procs, layout_cache);
match specialized {
SpecializedLayout::FunctionPointerBody {
@ -4712,6 +4719,7 @@ pub fn with_hole<'a>(
result = match_on_lambda_set(
env,
procs,
lambda_set,
closure_data_symbol,
arg_symbols,
@ -4752,6 +4760,7 @@ pub fn with_hole<'a>(
result = match_on_lambda_set(
env,
procs,
lambda_set,
closure_data_symbol,
arg_symbols,
@ -4809,6 +4818,7 @@ pub fn with_hole<'a>(
result = match_on_lambda_set(
env,
procs,
lambda_set,
closure_data_symbol,
arg_symbols,
@ -7485,6 +7495,7 @@ fn call_by_name<'a>(
let result = match_on_lambda_set(
env,
procs,
lambda_set,
closure_data_symbol,
arg_symbols,
@ -8045,6 +8056,7 @@ fn call_specialized_proc<'a>(
let new_hole = match_on_lambda_set(
env,
procs,
lambda_set,
closure_data_symbol,
field_symbols,
@ -9118,6 +9130,7 @@ where
#[allow(clippy::too_many_arguments)]
fn match_on_lambda_set<'a>(
env: &mut Env<'a, '_>,
procs: &mut Procs<'a>,
lambda_set: LambdaSet<'a>,
closure_data_symbol: Symbol,
argument_symbols: &'a [Symbol],
@ -9161,7 +9174,22 @@ fn match_on_lambda_set<'a>(
field_layouts,
field_order_hash,
} => {
let function_symbol = lambda_set.iter_set().next().unwrap();
let function_symbol = match lambda_set.iter_set().next() {
Some(function_symbol) => function_symbol,
None => {
// Lambda set is empty, so this function is never called; synthesize a function
// that always yields a runtime error.
let name = env.unique_symbol();
let function_layout =
RawFunctionLayout::Function(argument_layouts, lambda_set, return_layout);
let proc = generate_runtime_error_function(env, name, function_layout);
let top_level =
ProcLayout::from_raw(env.arena, function_layout, CapturesNiche::no_niche());
procs.specialized.insert_specialized(name, top_level, proc);
LambdaName::no_niche(name)
}
};
let closure_info = match field_layouts {
[] => ClosureInfo::DoesNotCapture,

View file

@ -2958,3 +2958,37 @@ fn with_capacity() {
RocList<u64>
);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn call_function_in_empty_list() {
assert_evals_to!(
indoc!(
r#"
lst : List ({} -> {})
lst = []
List.map lst \f -> f {}
"#
),
RocList::from_slice(&[]),
RocList<()>
)
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
// TODO to be improved, if we can generate the void function type for the function in the list,
// this should succeed.
#[should_panic(expected = r#"Roc failed with message: "#)]
fn call_function_in_empty_list_unbound() {
assert_evals_to!(
indoc!(
r#"
lst = []
List.map lst \f -> f {}
"#
),
RocList::from_slice(&[]),
RocList<()>
)
}

View file

@ -0,0 +1,18 @@
procedure List.5 (#Attr.2, #Attr.3):
let List.279 : List {} = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
decref #Attr.2;
ret List.279;
procedure Test.2 (Test.3):
let Test.7 : {} = Struct {};
let Test.6 : {} = CallByName Test.8 Test.7;
ret Test.6;
procedure Test.8 (Test.9):
Error The `#UserApp.IdentId(8)` function could not be generated, likely due to a type error.
procedure Test.0 ():
let Test.1 : List {} = Array [];
let Test.5 : {} = Struct {};
let Test.4 : List {} = CallByName List.5 Test.1 Test.5;
ret Test.4;

View file

@ -0,0 +1,6 @@
procedure List.5 (#Attr.2, #Attr.3):
Error UnresolvedTypeVar crates/compiler/mono/src/ir.rs line 5030
procedure Test.0 ():
let Test.1 : List {} = Array [];
Error UnresolvedTypeVar crates/compiler/mono/src/ir.rs line 4557

View file

@ -1682,3 +1682,24 @@ fn choose_u128_layout() {
"#
)
}
#[mono_test]
fn call_function_in_empty_list() {
indoc!(
r#"
lst : List ({} -> {})
lst = []
List.map lst \f -> f {}
"#
)
}
#[mono_test]
fn call_function_in_empty_list_unbound() {
indoc!(
r#"
lst = []
List.map lst \f -> f {}
"#
)
}