mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 08:17:40 +03:00
expand record pattern matches to bind all unused fields with underscore
this will simplify exhaustiveness checking, because a record is not like a one-tag union
This commit is contained in:
parent
5fc96c09ee
commit
0985037754
@ -942,6 +942,19 @@ fn store_record_destruct<'a>(
|
|||||||
Pattern::Identifier(symbol) => {
|
Pattern::Identifier(symbol) => {
|
||||||
stored.push((*symbol, destruct.layout.clone(), load));
|
stored.push((*symbol, destruct.layout.clone(), load));
|
||||||
}
|
}
|
||||||
|
Pattern::Underscore => {
|
||||||
|
// important that this is special-cased: mono record patterns will extract all the
|
||||||
|
// fields, but those not bound in the source code are guarded with the underscore
|
||||||
|
// pattern. So given some record `{ x : a, y : b }`, a match
|
||||||
|
//
|
||||||
|
// { x } -> ...
|
||||||
|
//
|
||||||
|
// is actually
|
||||||
|
//
|
||||||
|
// { x, y: _ } -> ...
|
||||||
|
//
|
||||||
|
// internally. But `y` is never used, so we must make sure it't not stored/loaded.
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let symbol = env.fresh_symbol();
|
let symbol = env.fresh_symbol();
|
||||||
stored.push((symbol, destruct.layout.clone(), load));
|
stored.push((symbol, destruct.layout.clone(), load));
|
||||||
@ -1320,15 +1333,42 @@ fn from_can_pattern<'a>(
|
|||||||
} => match Layout::from_var(env.arena, *whole_var, env.subs, env.pointer_size) {
|
} => match Layout::from_var(env.arena, *whole_var, env.subs, env.pointer_size) {
|
||||||
Ok(Layout::Struct(field_layouts)) => {
|
Ok(Layout::Struct(field_layouts)) => {
|
||||||
let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena);
|
let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena);
|
||||||
for (loc_rec_des, (label, field_layout)) in
|
let mut destructs = destructs.clone();
|
||||||
destructs.iter().zip(field_layouts.iter())
|
destructs.sort_by(|a, b| a.value.label.cmp(&b.value.label));
|
||||||
{
|
|
||||||
debug_assert!(&loc_rec_des.value.label == label);
|
let mut it = destructs.iter();
|
||||||
mono_destructs.push(from_can_record_destruct(
|
let mut opt_destruct = it.next();
|
||||||
env,
|
|
||||||
&loc_rec_des.value,
|
// insert underscore patterns for unused fields. We need the record to be fully
|
||||||
field_layout.clone(),
|
// matched for pattern exhaustiveness checking
|
||||||
));
|
for (label, field_layout) in field_layouts.iter() {
|
||||||
|
if let Some(destruct) = opt_destruct {
|
||||||
|
if &destruct.value.label == label {
|
||||||
|
opt_destruct = it.next();
|
||||||
|
|
||||||
|
mono_destructs.push(from_can_record_destruct(
|
||||||
|
env,
|
||||||
|
&destruct.value,
|
||||||
|
field_layout.clone(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
// insert underscore pattern
|
||||||
|
mono_destructs.push(RecordDestruct {
|
||||||
|
label: label.clone(),
|
||||||
|
symbol: env.fresh_symbol(),
|
||||||
|
layout: field_layout.clone(),
|
||||||
|
guard: Some(Pattern::Underscore),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// insert underscore pattern
|
||||||
|
mono_destructs.push(RecordDestruct {
|
||||||
|
label: label.clone(),
|
||||||
|
symbol: env.fresh_symbol(),
|
||||||
|
layout: field_layout.clone(),
|
||||||
|
guard: Some(Pattern::Underscore),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern::RecordDestructure(mono_destructs, Layout::Struct(field_layouts))
|
Pattern::RecordDestructure(mono_destructs, Layout::Struct(field_layouts))
|
||||||
|
Loading…
Reference in New Issue
Block a user