Specialize polymorphic values before binding to pattern

Closes #2811
This commit is contained in:
Ayaz Hafiz 2022-04-07 14:03:29 -04:00
parent 37729c08cc
commit a12e40a310
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
4 changed files with 50 additions and 7 deletions

View file

@ -3053,7 +3053,7 @@ fn specialize_naked_symbol<'a>(
let opt_fn_var = Some(variable); let opt_fn_var = Some(variable);
// if this is a function symbol, ensure that it's properly specialized! // if this is a function symbol, ensure that it's properly specialized!
reuse_function_symbol( specialize_symbol(
env, env,
procs, procs,
layout_cache, layout_cache,
@ -3558,7 +3558,7 @@ pub fn with_hole<'a>(
// this symbol is already defined; nothing to do // this symbol is already defined; nothing to do
} }
Field::Function(symbol, variable) => { Field::Function(symbol, variable) => {
stmt = reuse_function_symbol( stmt = specialize_symbol(
env, env,
procs, procs,
layout_cache, layout_cache,
@ -4114,7 +4114,7 @@ pub fn with_hole<'a>(
Stmt::Let(*symbol, access_expr, *field_layout, arena.alloc(stmt)); Stmt::Let(*symbol, access_expr, *field_layout, arena.alloc(stmt));
if record_needs_specialization { if record_needs_specialization {
stmt = reuse_function_symbol( stmt = specialize_symbol(
env, env,
procs, procs,
layout_cache, layout_cache,
@ -4804,8 +4804,7 @@ fn construct_closure_data<'a>(
// symbols to be inlined when specializing the closure body elsewhere. // symbols to be inlined when specializing the closure body elsewhere.
for &&(symbol, var) in symbols { for &&(symbol, var) in symbols {
if procs.partial_exprs.contains(symbol) { if procs.partial_exprs.contains(symbol) {
result = result = specialize_symbol(env, procs, layout_cache, Some(var), symbol, result, symbol);
reuse_function_symbol(env, procs, layout_cache, Some(var), symbol, result, symbol);
} }
} }
@ -6318,6 +6317,20 @@ fn store_pattern_help<'a>(
match can_pat { match can_pat {
Identifier(symbol) => { Identifier(symbol) => {
if let Some((_, var)) = procs.partial_exprs.get(outer_symbol) {
// It might be the case that symbol we're storing hasn't been reified to a value
// yet, if it's polymorphic. Do that now.
stmt = specialize_symbol(
env,
procs,
layout_cache,
Some(var),
*symbol,
stmt,
outer_symbol,
);
}
substitute_in_exprs(env.arena, &mut stmt, *symbol, outer_symbol); substitute_in_exprs(env.arena, &mut stmt, *symbol, outer_symbol);
} }
Underscore => { Underscore => {
@ -6771,7 +6784,7 @@ fn let_empty_struct<'a>(assigned: Symbol, hole: &'a Stmt<'a>) -> Stmt<'a> {
/// If the symbol is a function, make sure it is properly specialized /// If the symbol is a function, make sure it is properly specialized
// TODO: rename this now that we handle polymorphic non-function expressions too // TODO: rename this now that we handle polymorphic non-function expressions too
fn reuse_function_symbol<'a>( fn specialize_symbol<'a>(
env: &mut Env<'a, '_>, env: &mut Env<'a, '_>,
procs: &mut Procs<'a>, procs: &mut Procs<'a>,
layout_cache: &mut LayoutCache<'a>, layout_cache: &mut LayoutCache<'a>,
@ -6980,7 +6993,7 @@ fn assign_to_symbol<'a>(
match can_reuse_symbol(env, procs, &loc_arg.value) { match can_reuse_symbol(env, procs, &loc_arg.value) {
Imported(original) | LocalFunction(original) | UnspecializedExpr(original) => { Imported(original) | LocalFunction(original) | UnspecializedExpr(original) => {
// for functions we must make sure they are specialized correctly // for functions we must make sure they are specialized correctly
reuse_function_symbol( specialize_symbol(
env, env,
procs, procs,
layout_cache, layout_cache,

View file

@ -1587,3 +1587,19 @@ fn str_to_dec() {
RocDec RocDec
); );
} }
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn issue_2811() {
assert_evals_to!(
indoc!(
r#"
x = Command { tool: "bash" }
Command c = x
c.tool
"#
),
RocStr::from("bash"),
RocStr
);
}

View file

@ -0,0 +1,3 @@
procedure Test.0 ():
let Test.6 : Str = "bash";
ret Test.6;

View file

@ -1282,6 +1282,17 @@ fn issue_2583_specialize_errors_behind_unified_branches() {
) )
} }
#[mono_test]
fn issue_2811() {
indoc!(
r#"
x = Command { tool: "bash" }
Command c = x
c.tool
"#
)
}
// #[ignore] // #[ignore]
// #[mono_test] // #[mono_test]
// fn static_str_closure() { // fn static_str_closure() {