simplify handling of optional fields

This commit is contained in:
Folkert 2020-11-24 20:57:10 +01:00
parent 9c7514c449
commit 517f8f4a4a

View file

@ -5374,8 +5374,8 @@ pub fn from_can_pattern<'a>(
// sorted fields based on the destruct // sorted fields based on the destruct
let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena); let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena);
let mut destructs = destructs.clone(); let destructs_by_label = env.arena.alloc(MutMap::default());
destructs.sort_by(|a, b| a.value.label.cmp(&b.value.label)); destructs_by_label.extend(destructs.iter().map(|x| (&x.value.label, x)));
let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena); let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena);
@ -5387,27 +5387,25 @@ pub fn from_can_pattern<'a>(
// in the source the field is not matche in the source language. // in the source the field is not matche in the source language.
// //
// Optional fields somewhat complicate the matter here // Optional fields somewhat complicate the matter here
let mut it1 = sorted_fields.into_iter();
let mut opt_sorted = it1.next();
let mut it2 = destructs.iter(); for (label, variable, res_layout) in sorted_fields.into_iter() {
let mut opt_destruct = it2.next(); match res_layout {
Ok(field_layout) => {
// the field is non-optional according to the type
loop { match destructs_by_label.remove(&label) {
match (opt_sorted, opt_destruct) { Some(destruct) => {
(Some((label, variable, Ok(field_layout))), Some(destruct)) => { // this field is destructured by the pattern
if destruct.value.label == label {
mono_destructs.push(from_can_record_destruct( mono_destructs.push(from_can_record_destruct(
env, env,
layout_cache, layout_cache,
&destruct.value, &destruct.value,
field_layout.clone(), field_layout.clone(),
)); ));
}
opt_sorted = it1.next(); None => {
opt_destruct = it2.next(); // this field is not destructured by the pattern
} else { // put in an underscore
// insert underscore pattern
mono_destructs.push(RecordDestruct { mono_destructs.push(RecordDestruct {
label: label.clone(), label: label.clone(),
symbol: env.unique_symbol(), symbol: env.unique_symbol(),
@ -5415,15 +5413,17 @@ pub fn from_can_pattern<'a>(
layout: field_layout.clone(), layout: field_layout.clone(),
typ: DestructType::Guard(Pattern::Underscore), typ: DestructType::Guard(Pattern::Underscore),
}); });
opt_sorted = it1.next();
} }
}
// the layout of this field is part of the layout of the record
field_layouts.push(field_layout); field_layouts.push(field_layout);
} }
(Some((label, variable, Err(field_layout))), Some(destruct)) => { Err(field_layout) => {
if destruct.value.label == label { // the field is optional according to the type
opt_destruct = it2.next(); match destructs_by_label.remove(&label) {
Some(destruct) => {
// this field is destructured by the pattern
mono_destructs.push(RecordDestruct { mono_destructs.push(RecordDestruct {
label: destruct.value.label.clone(), label: destruct.value.label.clone(),
symbol: destruct.value.symbol, symbol: destruct.value.symbol,
@ -5441,12 +5441,9 @@ pub fn from_can_pattern<'a>(
}, },
}); });
} }
opt_sorted = it1.next(); None => {
} // this field is not destructured by the pattern
// put in an underscore
(Some((label, variable, Err(field_layout))), None) => {
// the remainder of the fields (from the type) is not matched on in
// this pattern; to fill it out, we put underscores
mono_destructs.push(RecordDestruct { mono_destructs.push(RecordDestruct {
label: label.clone(), label: label.clone(),
symbol: env.unique_symbol(), symbol: env.unique_symbol(),
@ -5454,26 +5451,14 @@ pub fn from_can_pattern<'a>(
layout: field_layout.clone(), layout: field_layout.clone(),
typ: DestructType::Guard(Pattern::Underscore), typ: DestructType::Guard(Pattern::Underscore),
}); });
}
opt_sorted = it1.next(); }
}
}
} }
(Some((label, variable, Ok(field_layout))), None) => { for (_, destruct) in destructs_by_label.drain() {
// the remainder of the fields (from the type) is not matched on in // this destruct is not in the type, but is in the pattern
// this pattern; to fill it out, we put underscores
mono_destructs.push(RecordDestruct {
label: label.clone(),
symbol: env.unique_symbol(),
variable,
layout: field_layout.clone(),
typ: DestructType::Guard(Pattern::Underscore),
});
field_layouts.push(field_layout);
opt_sorted = it1.next();
}
(None, Some(destruct)) => {
// destruct is not in the type, but is in the pattern
// it must be an optional field, and we will use the default // it must be an optional field, and we will use the default
match &destruct.value.typ { match &destruct.value.typ {
roc_can::pattern::DestructType::Optional(field_var, loc_expr) => { roc_can::pattern::DestructType::Optional(field_var, loc_expr) => {
@ -5493,14 +5478,6 @@ pub fn from_can_pattern<'a>(
} }
_ => unreachable!("only optional destructs can be optional fields"), _ => unreachable!("only optional destructs can be optional fields"),
} }
opt_sorted = None;
opt_destruct = it2.next();
}
(None, None) => {
break;
}
}
} }
Pattern::RecordDestructure( Pattern::RecordDestructure(