mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
Constrain optional record fields
This commit is contained in:
parent
8fc9a450b3
commit
1409421de2
2 changed files with 55 additions and 27 deletions
|
@ -2,13 +2,13 @@ use crate::builtins;
|
|||
use roc_can::constraint::Constraint;
|
||||
use roc_can::expected::{Expected, PExpected};
|
||||
use roc_can::pattern::Pattern::{self, *};
|
||||
use roc_can::pattern::RecordDestruct;
|
||||
use roc_can::pattern::{DestructType, RecordDestruct};
|
||||
use roc_collections::all::{Index, SendMap};
|
||||
use roc_module::ident::Lowercase;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Located, Region};
|
||||
use roc_types::subs::Variable;
|
||||
use roc_types::types::{Category, PReason, PatternCategory, Type};
|
||||
use roc_types::types::{Category, PReason, PatternCategory, RecordField, Type};
|
||||
|
||||
pub struct PatternState {
|
||||
pub headers: SendMap<Symbol, Located<Type>>,
|
||||
|
@ -61,12 +61,20 @@ fn headers_from_annotation_help(
|
|||
|
||||
RecordDestructure { destructs, .. } => match annotation.value.shallow_dealias() {
|
||||
Type::Record(fields, _) => {
|
||||
for destruct in destructs {
|
||||
// NOTE ignores the .guard field.
|
||||
if let Some(field_type) = fields.get(&destruct.value.label) {
|
||||
for loc_destruct in destructs {
|
||||
let destruct = &loc_destruct.value;
|
||||
|
||||
// NOTE: We ignore both Guard and optionality when
|
||||
// determining the type of the assigned def (which is what
|
||||
// gets added to the header here).
|
||||
//
|
||||
// For example, no matter whether it's `{ x } = rec` or
|
||||
// `{ x ? 0 } = rec` or `{ x: 5 } -> ...` in all cases
|
||||
// the type of `x` within the binding itself is the same.
|
||||
if let Some(field_type) = fields.get(&destruct.label) {
|
||||
headers.insert(
|
||||
destruct.value.symbol,
|
||||
Located::at(annotation.region, field_type.clone()),
|
||||
destruct.symbol,
|
||||
Located::at(annotation.region, field_type.clone().into_inner()),
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
|
@ -179,7 +187,7 @@ pub fn constrain_pattern(
|
|||
state.vars.push(*ext_var);
|
||||
let ext_type = Type::Variable(*ext_var);
|
||||
|
||||
let mut field_types: SendMap<Lowercase, Type> = SendMap::default();
|
||||
let mut field_types: SendMap<Lowercase, RecordField<Type>> = SendMap::default();
|
||||
|
||||
for Located {
|
||||
value:
|
||||
|
@ -187,7 +195,7 @@ pub fn constrain_pattern(
|
|||
var,
|
||||
label,
|
||||
symbol,
|
||||
guard,
|
||||
typ,
|
||||
},
|
||||
..
|
||||
} in destructs
|
||||
|
@ -201,23 +209,36 @@ pub fn constrain_pattern(
|
|||
.insert(*symbol, Located::at(region, pat_type.clone()));
|
||||
}
|
||||
|
||||
field_types.insert(label.clone(), pat_type.clone());
|
||||
let field_type = match typ {
|
||||
DestructType::Guard(guard_var, loc_guard) => {
|
||||
state.constraints.push(Constraint::Pattern(
|
||||
region,
|
||||
PatternCategory::PatternGuard,
|
||||
Type::Variable(*guard_var),
|
||||
PExpected::ForReason(
|
||||
PReason::PatternGuard,
|
||||
pat_type.clone(),
|
||||
loc_guard.region,
|
||||
),
|
||||
));
|
||||
state.vars.push(*guard_var);
|
||||
|
||||
if let Some((guard_var, loc_guard)) = guard {
|
||||
state.constraints.push(Constraint::Pattern(
|
||||
region,
|
||||
PatternCategory::PatternGuard,
|
||||
Type::Variable(*guard_var),
|
||||
PExpected::ForReason(
|
||||
PReason::PatternGuard,
|
||||
pat_type.clone(),
|
||||
loc_guard.region,
|
||||
),
|
||||
));
|
||||
state.vars.push(*guard_var);
|
||||
constrain_pattern(&loc_guard.value, loc_guard.region, expected, state);
|
||||
|
||||
constrain_pattern(&loc_guard.value, loc_guard.region, expected, state);
|
||||
}
|
||||
RecordField::Required(pat_type)
|
||||
}
|
||||
DestructType::Optional(_var) => {
|
||||
todo!("Add a constraint for the default value.");
|
||||
|
||||
// RecordField::Optional(pat_type)
|
||||
}
|
||||
DestructType::Required => {
|
||||
// No extra constraints necessary.
|
||||
RecordField::Required(pat_type)
|
||||
}
|
||||
};
|
||||
|
||||
field_types.insert(label.clone(), field_type);
|
||||
|
||||
state.vars.push(*var);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue