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
|
@ -9,7 +9,7 @@ use roc_region::all::{Located, Region};
|
||||||
use roc_types::boolean_algebra::Bool;
|
use roc_types::boolean_algebra::Bool;
|
||||||
use roc_types::solved_types::{BuiltinAlias, SolvedBool, SolvedType};
|
use roc_types::solved_types::{BuiltinAlias, SolvedBool, SolvedType};
|
||||||
use roc_types::subs::{VarId, VarStore, Variable};
|
use roc_types::subs::{VarId, VarStore, Variable};
|
||||||
use roc_types::types::{Alias, Problem, Type};
|
use roc_types::types::{Alias, Problem, RecordField, Type};
|
||||||
|
|
||||||
pub type SubsByModule = MutMap<ModuleId, ExposedModuleTypes>;
|
pub type SubsByModule = MutMap<ModuleId, ExposedModuleTypes>;
|
||||||
|
|
||||||
|
@ -214,10 +214,17 @@ fn to_type(solved_type: &SolvedType, free_vars: &mut FreeVars, var_store: &mut V
|
||||||
Type::Variable(var)
|
Type::Variable(var)
|
||||||
}
|
}
|
||||||
Record { fields, ext } => {
|
Record { fields, ext } => {
|
||||||
|
use RecordField::*;
|
||||||
|
|
||||||
let mut new_fields = SendMap::default();
|
let mut new_fields = SendMap::default();
|
||||||
|
|
||||||
for (label, typ) in fields {
|
for (label, field) in fields {
|
||||||
new_fields.insert(label.clone(), to_type(&typ, free_vars, var_store));
|
let field_val = match field {
|
||||||
|
Required(typ) => Required(to_type(&typ, free_vars, var_store)),
|
||||||
|
Optional(typ) => Optional(to_type(&typ, free_vars, var_store)),
|
||||||
|
};
|
||||||
|
|
||||||
|
new_fields.insert(label.clone(), field_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Record(new_fields, Box::new(to_type(ext, free_vars, var_store)))
|
Type::Record(new_fields, Box::new(to_type(ext, free_vars, var_store)))
|
||||||
|
|
|
@ -2,13 +2,13 @@ use crate::builtins;
|
||||||
use roc_can::constraint::Constraint;
|
use roc_can::constraint::Constraint;
|
||||||
use roc_can::expected::{Expected, PExpected};
|
use roc_can::expected::{Expected, PExpected};
|
||||||
use roc_can::pattern::Pattern::{self, *};
|
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_collections::all::{Index, SendMap};
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
use roc_types::subs::Variable;
|
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 struct PatternState {
|
||||||
pub headers: SendMap<Symbol, Located<Type>>,
|
pub headers: SendMap<Symbol, Located<Type>>,
|
||||||
|
@ -61,12 +61,20 @@ fn headers_from_annotation_help(
|
||||||
|
|
||||||
RecordDestructure { destructs, .. } => match annotation.value.shallow_dealias() {
|
RecordDestructure { destructs, .. } => match annotation.value.shallow_dealias() {
|
||||||
Type::Record(fields, _) => {
|
Type::Record(fields, _) => {
|
||||||
for destruct in destructs {
|
for loc_destruct in destructs {
|
||||||
// NOTE ignores the .guard field.
|
let destruct = &loc_destruct.value;
|
||||||
if let Some(field_type) = fields.get(&destruct.value.label) {
|
|
||||||
|
// 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(
|
headers.insert(
|
||||||
destruct.value.symbol,
|
destruct.symbol,
|
||||||
Located::at(annotation.region, field_type.clone()),
|
Located::at(annotation.region, field_type.clone().into_inner()),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -179,7 +187,7 @@ pub fn constrain_pattern(
|
||||||
state.vars.push(*ext_var);
|
state.vars.push(*ext_var);
|
||||||
let ext_type = Type::Variable(*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 {
|
for Located {
|
||||||
value:
|
value:
|
||||||
|
@ -187,7 +195,7 @@ pub fn constrain_pattern(
|
||||||
var,
|
var,
|
||||||
label,
|
label,
|
||||||
symbol,
|
symbol,
|
||||||
guard,
|
typ,
|
||||||
},
|
},
|
||||||
..
|
..
|
||||||
} in destructs
|
} in destructs
|
||||||
|
@ -201,23 +209,36 @@ pub fn constrain_pattern(
|
||||||
.insert(*symbol, Located::at(region, pat_type.clone()));
|
.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 {
|
constrain_pattern(&loc_guard.value, loc_guard.region, expected, state);
|
||||||
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);
|
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);
|
state.vars.push(*var);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue