mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Verify layouts of extracted specialization symbols
This commit is contained in:
parent
8228df55c7
commit
674ec3beae
2 changed files with 131 additions and 23 deletions
|
@ -1210,8 +1210,15 @@ pub fn optimize_when<'a>(
|
||||||
// bind the fields referenced in the pattern. For guards this happens separately, so
|
// bind the fields referenced in the pattern. For guards this happens separately, so
|
||||||
// the pattern variables are defined when evaluating the guard.
|
// the pattern variables are defined when evaluating the guard.
|
||||||
if !has_guard {
|
if !has_guard {
|
||||||
branch =
|
branch = crate::ir::store_pattern(
|
||||||
crate::ir::store_pattern(env, procs, layout_cache, &pattern, cond_symbol, branch);
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
&pattern,
|
||||||
|
cond_layout,
|
||||||
|
cond_symbol,
|
||||||
|
branch,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ((branch_index, choice), opt_jump) = create_choices(&target_counts, index, branch);
|
let ((branch_index, choice), opt_jump) = create_choices(&target_counts, index, branch);
|
||||||
|
@ -1723,7 +1730,15 @@ fn decide_to_branching<'a>(
|
||||||
body: arena.alloc(decide),
|
body: arena.alloc(decide),
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::ir::store_pattern(env, procs, layout_cache, &pattern, cond_symbol, join)
|
crate::ir::store_pattern(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
&pattern,
|
||||||
|
cond_layout,
|
||||||
|
cond_symbol,
|
||||||
|
join,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Chain {
|
Chain {
|
||||||
test_chain,
|
test_chain,
|
||||||
|
|
|
@ -772,14 +772,23 @@ impl<'a> Procs<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expects and removes a single specialization symbol for the given requested symbol.
|
/// Expects and removes a single specialization symbol for the given requested symbol.
|
||||||
fn remove_single_symbol_specialization(&mut self, symbol: Symbol) -> Option<Symbol> {
|
/// In debug builds, we assert that the layout of the specialization is the layout expected by
|
||||||
|
/// the requested symbol.
|
||||||
|
fn remove_single_symbol_specialization(
|
||||||
|
&mut self,
|
||||||
|
symbol: Symbol,
|
||||||
|
layout: Layout,
|
||||||
|
) -> Option<Symbol> {
|
||||||
let mut specialized_symbols = self
|
let mut specialized_symbols = self
|
||||||
.needed_symbol_specializations
|
.needed_symbol_specializations
|
||||||
.drain_filter(|(sym, _), _| sym == &symbol);
|
.drain_filter(|(sym, _), _| sym == &symbol);
|
||||||
|
|
||||||
let specialization_symbol = specialized_symbols
|
let specialization_symbol = specialized_symbols
|
||||||
.next()
|
.next()
|
||||||
.map(|(_, (_, specialized_symbol))| specialized_symbol);
|
.map(|((_, specialized_layout), (_, specialized_symbol))| {
|
||||||
|
debug_assert_eq!(specialized_layout, layout, "Requested the single specialization of {:?}, but the specialization layout ({:?}) doesn't match the expected layout ({:?})", symbol, specialized_layout, layout);
|
||||||
|
specialized_symbol
|
||||||
|
});
|
||||||
|
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
specialized_symbols.count(),
|
specialized_symbols.count(),
|
||||||
|
@ -3342,7 +3351,18 @@ pub fn with_hole<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
let outer_symbol = env.unique_symbol();
|
let outer_symbol = env.unique_symbol();
|
||||||
stmt = store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt);
|
let pattern_layout = layout_cache
|
||||||
|
.from_var(env.arena, def.expr_var, env.subs)
|
||||||
|
.expect("Pattern has no layout");
|
||||||
|
stmt = store_pattern(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
&mono_pattern,
|
||||||
|
pattern_layout,
|
||||||
|
outer_symbol,
|
||||||
|
stmt,
|
||||||
|
);
|
||||||
|
|
||||||
// convert the def body, store in outer_symbol
|
// convert the def body, store in outer_symbol
|
||||||
with_hole(
|
with_hole(
|
||||||
|
@ -5750,8 +5770,11 @@ pub fn from_can<'a>(
|
||||||
|
|
||||||
// layer on any default record fields
|
// layer on any default record fields
|
||||||
for (symbol, variable, expr) in assignments {
|
for (symbol, variable, expr) in assignments {
|
||||||
|
let layout = layout_cache
|
||||||
|
.from_var(env.arena, variable, env.subs)
|
||||||
|
.expect("Default field has no layout");
|
||||||
let specialization_symbol = procs
|
let specialization_symbol = procs
|
||||||
.remove_single_symbol_specialization(symbol)
|
.remove_single_symbol_specialization(symbol, layout)
|
||||||
// Can happen when the symbol was never used under this body, and hence has no
|
// Can happen when the symbol was never used under this body, and hence has no
|
||||||
// requested specialization.
|
// requested specialization.
|
||||||
.unwrap_or(symbol);
|
.unwrap_or(symbol);
|
||||||
|
@ -5768,12 +5791,30 @@ pub fn from_can<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pattern_layout = layout_cache
|
||||||
|
.from_var(env.arena, def.expr_var, env.subs)
|
||||||
|
.expect("Pattern has no layout");
|
||||||
if let roc_can::expr::Expr::Var(outer_symbol) = def.loc_expr.value {
|
if let roc_can::expr::Expr::Var(outer_symbol) = def.loc_expr.value {
|
||||||
store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt)
|
store_pattern(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
&mono_pattern,
|
||||||
|
pattern_layout,
|
||||||
|
outer_symbol,
|
||||||
|
stmt,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let outer_symbol = env.unique_symbol();
|
let outer_symbol = env.unique_symbol();
|
||||||
stmt =
|
stmt = store_pattern(
|
||||||
store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt);
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
&mono_pattern,
|
||||||
|
pattern_layout,
|
||||||
|
outer_symbol,
|
||||||
|
stmt,
|
||||||
|
);
|
||||||
|
|
||||||
// convert the def body, store in outer_symbol
|
// convert the def body, store in outer_symbol
|
||||||
with_hole(
|
with_hole(
|
||||||
|
@ -6339,10 +6380,19 @@ pub fn store_pattern<'a>(
|
||||||
procs: &mut Procs<'a>,
|
procs: &mut Procs<'a>,
|
||||||
layout_cache: &mut LayoutCache<'a>,
|
layout_cache: &mut LayoutCache<'a>,
|
||||||
can_pat: &Pattern<'a>,
|
can_pat: &Pattern<'a>,
|
||||||
|
pattern_layout: Layout,
|
||||||
outer_symbol: Symbol,
|
outer_symbol: Symbol,
|
||||||
stmt: Stmt<'a>,
|
stmt: Stmt<'a>,
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
match store_pattern_help(env, procs, layout_cache, can_pat, outer_symbol, stmt) {
|
match store_pattern_help(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
can_pat,
|
||||||
|
pattern_layout,
|
||||||
|
outer_symbol,
|
||||||
|
stmt,
|
||||||
|
) {
|
||||||
StorePattern::Productive(new) => new,
|
StorePattern::Productive(new) => new,
|
||||||
StorePattern::NotProductive(new) => new,
|
StorePattern::NotProductive(new) => new,
|
||||||
}
|
}
|
||||||
|
@ -6362,6 +6412,7 @@ fn store_pattern_help<'a>(
|
||||||
procs: &mut Procs<'a>,
|
procs: &mut Procs<'a>,
|
||||||
layout_cache: &mut LayoutCache<'a>,
|
layout_cache: &mut LayoutCache<'a>,
|
||||||
can_pat: &Pattern<'a>,
|
can_pat: &Pattern<'a>,
|
||||||
|
pattern_layout: Layout,
|
||||||
outer_symbol: Symbol,
|
outer_symbol: Symbol,
|
||||||
mut stmt: Stmt<'a>,
|
mut stmt: Stmt<'a>,
|
||||||
) -> StorePattern<'a> {
|
) -> StorePattern<'a> {
|
||||||
|
@ -6372,7 +6423,7 @@ fn store_pattern_help<'a>(
|
||||||
// An identifier in a pattern can define at most one specialization!
|
// An identifier in a pattern can define at most one specialization!
|
||||||
// Remove any requested specializations for this name now, since this is the definition site.
|
// Remove any requested specializations for this name now, since this is the definition site.
|
||||||
let specialization_symbol = procs
|
let specialization_symbol = procs
|
||||||
.remove_single_symbol_specialization(*symbol)
|
.remove_single_symbol_specialization(*symbol, pattern_layout)
|
||||||
// Can happen when the symbol was never used under this body, and hence has no
|
// Can happen when the symbol was never used under this body, and hence has no
|
||||||
// requested specialization.
|
// requested specialization.
|
||||||
.unwrap_or(*symbol);
|
.unwrap_or(*symbol);
|
||||||
|
@ -6393,8 +6444,16 @@ fn store_pattern_help<'a>(
|
||||||
return StorePattern::NotProductive(stmt);
|
return StorePattern::NotProductive(stmt);
|
||||||
}
|
}
|
||||||
NewtypeDestructure { arguments, .. } => match arguments.as_slice() {
|
NewtypeDestructure { arguments, .. } => match arguments.as_slice() {
|
||||||
[single] => {
|
[(pattern, layout)] => {
|
||||||
return store_pattern_help(env, procs, layout_cache, &single.0, outer_symbol, stmt);
|
return store_pattern_help(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
pattern,
|
||||||
|
*layout,
|
||||||
|
outer_symbol,
|
||||||
|
stmt,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut fields = Vec::with_capacity_in(arguments.len(), env.arena);
|
let mut fields = Vec::with_capacity_in(arguments.len(), env.arena);
|
||||||
|
@ -6431,7 +6490,16 @@ fn store_pattern_help<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
OpaqueUnwrap { argument, .. } => {
|
OpaqueUnwrap { argument, .. } => {
|
||||||
return store_pattern_help(env, procs, layout_cache, &argument.0, outer_symbol, stmt);
|
let (pattern, layout) = &**argument;
|
||||||
|
return store_pattern_help(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
pattern,
|
||||||
|
*layout,
|
||||||
|
outer_symbol,
|
||||||
|
stmt,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordDestructure(destructs, [_single_field]) => {
|
RecordDestructure(destructs, [_single_field]) => {
|
||||||
|
@ -6439,7 +6507,7 @@ fn store_pattern_help<'a>(
|
||||||
match &destruct.typ {
|
match &destruct.typ {
|
||||||
DestructType::Required(symbol) => {
|
DestructType::Required(symbol) => {
|
||||||
let specialization_symbol = procs
|
let specialization_symbol = procs
|
||||||
.remove_single_symbol_specialization(*symbol)
|
.remove_single_symbol_specialization(*symbol, destruct.layout)
|
||||||
// Can happen when the symbol was never used under this body, and hence has no
|
// Can happen when the symbol was never used under this body, and hence has no
|
||||||
// requested specialization.
|
// requested specialization.
|
||||||
.unwrap_or(*symbol);
|
.unwrap_or(*symbol);
|
||||||
|
@ -6457,6 +6525,7 @@ fn store_pattern_help<'a>(
|
||||||
procs,
|
procs,
|
||||||
layout_cache,
|
layout_cache,
|
||||||
guard_pattern,
|
guard_pattern,
|
||||||
|
destruct.layout,
|
||||||
outer_symbol,
|
outer_symbol,
|
||||||
stmt,
|
stmt,
|
||||||
);
|
);
|
||||||
|
@ -6529,7 +6598,7 @@ fn store_tag_pattern<'a>(
|
||||||
Identifier(symbol) => {
|
Identifier(symbol) => {
|
||||||
// Pattern can define only one specialization
|
// Pattern can define only one specialization
|
||||||
let symbol = procs
|
let symbol = procs
|
||||||
.remove_single_symbol_specialization(*symbol)
|
.remove_single_symbol_specialization(*symbol, arg_layout)
|
||||||
.unwrap_or(*symbol);
|
.unwrap_or(*symbol);
|
||||||
|
|
||||||
// store immediately in the given symbol
|
// store immediately in the given symbol
|
||||||
|
@ -6550,7 +6619,15 @@ fn store_tag_pattern<'a>(
|
||||||
let symbol = env.unique_symbol();
|
let symbol = env.unique_symbol();
|
||||||
|
|
||||||
// first recurse, continuing to unpack symbol
|
// first recurse, continuing to unpack symbol
|
||||||
match store_pattern_help(env, procs, layout_cache, argument, symbol, stmt) {
|
match store_pattern_help(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
argument,
|
||||||
|
arg_layout,
|
||||||
|
symbol,
|
||||||
|
stmt,
|
||||||
|
) {
|
||||||
StorePattern::Productive(new) => {
|
StorePattern::Productive(new) => {
|
||||||
is_productive = true;
|
is_productive = true;
|
||||||
stmt = new;
|
stmt = new;
|
||||||
|
@ -6610,7 +6687,7 @@ fn store_newtype_pattern<'a>(
|
||||||
Identifier(symbol) => {
|
Identifier(symbol) => {
|
||||||
// store immediately in the given symbol, removing it specialization if it had any
|
// store immediately in the given symbol, removing it specialization if it had any
|
||||||
let specialization_symbol = procs
|
let specialization_symbol = procs
|
||||||
.remove_single_symbol_specialization(*symbol)
|
.remove_single_symbol_specialization(*symbol, arg_layout)
|
||||||
// Can happen when the symbol was never used under this body, and hence has no
|
// Can happen when the symbol was never used under this body, and hence has no
|
||||||
// requested specialization.
|
// requested specialization.
|
||||||
.unwrap_or(*symbol);
|
.unwrap_or(*symbol);
|
||||||
|
@ -6637,7 +6714,15 @@ fn store_newtype_pattern<'a>(
|
||||||
let symbol = env.unique_symbol();
|
let symbol = env.unique_symbol();
|
||||||
|
|
||||||
// first recurse, continuing to unpack symbol
|
// first recurse, continuing to unpack symbol
|
||||||
match store_pattern_help(env, procs, layout_cache, argument, symbol, stmt) {
|
match store_pattern_help(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
argument,
|
||||||
|
arg_layout,
|
||||||
|
symbol,
|
||||||
|
stmt,
|
||||||
|
) {
|
||||||
StorePattern::Productive(new) => {
|
StorePattern::Productive(new) => {
|
||||||
is_productive = true;
|
is_productive = true;
|
||||||
stmt = new;
|
stmt = new;
|
||||||
|
@ -6685,7 +6770,7 @@ fn store_record_destruct<'a>(
|
||||||
// A destructure can define at most one specialization!
|
// A destructure can define at most one specialization!
|
||||||
// Remove any requested specializations for this name now, since this is the definition site.
|
// Remove any requested specializations for this name now, since this is the definition site.
|
||||||
let specialization_symbol = procs
|
let specialization_symbol = procs
|
||||||
.remove_single_symbol_specialization(*symbol)
|
.remove_single_symbol_specialization(*symbol, destruct.layout)
|
||||||
// Can happen when the symbol was never used under this body, and hence has no
|
// Can happen when the symbol was never used under this body, and hence has no
|
||||||
// requested specialization.
|
// requested specialization.
|
||||||
.unwrap_or(*symbol);
|
.unwrap_or(*symbol);
|
||||||
|
@ -6700,7 +6785,7 @@ fn store_record_destruct<'a>(
|
||||||
DestructType::Guard(guard_pattern) => match &guard_pattern {
|
DestructType::Guard(guard_pattern) => match &guard_pattern {
|
||||||
Identifier(symbol) => {
|
Identifier(symbol) => {
|
||||||
let specialization_symbol = procs
|
let specialization_symbol = procs
|
||||||
.remove_single_symbol_specialization(*symbol)
|
.remove_single_symbol_specialization(*symbol, destruct.layout)
|
||||||
// Can happen when the symbol was never used under this body, and hence has no
|
// Can happen when the symbol was never used under this body, and hence has no
|
||||||
// requested specialization.
|
// requested specialization.
|
||||||
.unwrap_or(*symbol);
|
.unwrap_or(*symbol);
|
||||||
|
@ -6738,7 +6823,15 @@ fn store_record_destruct<'a>(
|
||||||
_ => {
|
_ => {
|
||||||
let symbol = env.unique_symbol();
|
let symbol = env.unique_symbol();
|
||||||
|
|
||||||
match store_pattern_help(env, procs, layout_cache, guard_pattern, symbol, stmt) {
|
match store_pattern_help(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
guard_pattern,
|
||||||
|
destruct.layout,
|
||||||
|
symbol,
|
||||||
|
stmt,
|
||||||
|
) {
|
||||||
StorePattern::Productive(new) => {
|
StorePattern::Productive(new) => {
|
||||||
stmt = new;
|
stmt = new;
|
||||||
stmt = Stmt::Let(symbol, load, destruct.layout, env.arena.alloc(stmt));
|
stmt = Stmt::Let(symbol, load, destruct.layout, env.arena.alloc(stmt));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue