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
let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena);
let mut destructs = destructs.clone();
destructs.sort_by(|a, b| a.value.label.cmp(&b.value.label));
let destructs_by_label = env.arena.alloc(MutMap::default());
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);
@ -5387,27 +5387,25 @@ pub fn from_can_pattern<'a>(
// in the source the field is not matche in the source language.
//
// 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();
let mut opt_destruct = it2.next();
for (label, variable, res_layout) in sorted_fields.into_iter() {
match res_layout {
Ok(field_layout) => {
// the field is non-optional according to the type
loop {
match (opt_sorted, opt_destruct) {
(Some((label, variable, Ok(field_layout))), Some(destruct)) => {
if destruct.value.label == label {
match destructs_by_label.remove(&label) {
Some(destruct) => {
// this field is destructured by the pattern
mono_destructs.push(from_can_record_destruct(
env,
layout_cache,
&destruct.value,
field_layout.clone(),
));
opt_sorted = it1.next();
opt_destruct = it2.next();
} else {
// insert underscore pattern
}
None => {
// this field is not destructured by the pattern
// put in an underscore
mono_destructs.push(RecordDestruct {
label: label.clone(),
symbol: env.unique_symbol(),
@ -5415,15 +5413,17 @@ pub fn from_can_pattern<'a>(
layout: field_layout.clone(),
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);
}
(Some((label, variable, Err(field_layout))), Some(destruct)) => {
if destruct.value.label == label {
opt_destruct = it2.next();
Err(field_layout) => {
// the field is optional according to the type
match destructs_by_label.remove(&label) {
Some(destruct) => {
// this field is destructured by the pattern
mono_destructs.push(RecordDestruct {
label: destruct.value.label.clone(),
symbol: destruct.value.symbol,
@ -5441,12 +5441,9 @@ pub fn from_can_pattern<'a>(
},
});
}
opt_sorted = it1.next();
}
(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
None => {
// this field is not destructured by the pattern
// put in an underscore
mono_destructs.push(RecordDestruct {
label: label.clone(),
symbol: env.unique_symbol(),
@ -5454,26 +5451,14 @@ pub fn from_can_pattern<'a>(
layout: field_layout.clone(),
typ: DestructType::Guard(Pattern::Underscore),
});
opt_sorted = it1.next();
}
}
}
}
}
(Some((label, variable, Ok(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 {
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
for (_, destruct) in destructs_by_label.drain() {
// this destruct is not in the type, but is in the pattern
// it must be an optional field, and we will use the default
match &destruct.value.typ {
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"),
}
opt_sorted = None;
opt_destruct = it2.next();
}
(None, None) => {
break;
}
}
}
Pattern::RecordDestructure(