mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
Constrain uniquness for optional fields
This commit is contained in:
parent
1409421de2
commit
8a2d6004ee
1 changed files with 72 additions and 29 deletions
|
@ -5,7 +5,7 @@ use roc_can::constraint::LetConstraint;
|
|||
use roc_can::def::{Declaration, Def};
|
||||
use roc_can::expected::{Expected, PExpected};
|
||||
use roc_can::expr::{Expr, Field, WhenBranch};
|
||||
use roc_can::pattern::{Pattern, RecordDestruct};
|
||||
use roc_can::pattern::{DestructType, Pattern, RecordDestruct};
|
||||
use roc_collections::all::{ImMap, ImSet, Index, SendMap};
|
||||
use roc_module::ident::{Ident, Lowercase};
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
|
@ -14,7 +14,7 @@ use roc_types::boolean_algebra::Bool;
|
|||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::AnnotationSource::{self, *};
|
||||
use roc_types::types::Type::{self, *};
|
||||
use roc_types::types::{Alias, Category, PReason, Reason};
|
||||
use roc_types::types::{Alias, Category, PReason, Reason, RecordField};
|
||||
use roc_uniq::builtins::{attr_type, empty_list_type, list_type, str_type};
|
||||
use roc_uniq::sharing::{self, FieldAccess, Mark, Usage, VarUsage};
|
||||
|
||||
|
@ -213,14 +213,14 @@ 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:
|
||||
RecordDestruct {
|
||||
var,
|
||||
label,
|
||||
symbol,
|
||||
guard,
|
||||
typ,
|
||||
},
|
||||
..
|
||||
} in destructs
|
||||
|
@ -237,18 +237,31 @@ fn constrain_pattern(
|
|||
.insert(*symbol, Located::at(pattern.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(
|
||||
pattern.region,
|
||||
PatternCategory::PatternGuard,
|
||||
Type::Variable(*guard_var),
|
||||
PExpected::NoExpectation(pat_type.clone()),
|
||||
));
|
||||
state.vars.push(*guard_var);
|
||||
constrain_pattern(var_store, state, loc_guard, expected);
|
||||
|
||||
if let Some((guard_var, loc_guard)) = guard {
|
||||
state.constraints.push(Constraint::Pattern(
|
||||
pattern.region,
|
||||
PatternCategory::PatternGuard,
|
||||
Type::Variable(*guard_var),
|
||||
PExpected::NoExpectation(pat_type.clone()),
|
||||
));
|
||||
state.vars.push(*guard_var);
|
||||
constrain_pattern(var_store, state, loc_guard, expected);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -495,7 +508,7 @@ pub fn constrain_expr(
|
|||
);
|
||||
|
||||
field_vars.push(field_var);
|
||||
field_types.insert(label.clone(), field_type);
|
||||
field_types.insert(label.clone(), RecordField::Required(field_type));
|
||||
|
||||
constraints.push(field_con);
|
||||
}
|
||||
|
@ -1224,7 +1237,7 @@ pub fn constrain_expr(
|
|||
symbol,
|
||||
updates,
|
||||
} => {
|
||||
let mut fields: SendMap<Lowercase, Type> = SendMap::default();
|
||||
let mut fields: SendMap<Lowercase, RecordField<Type>> = SendMap::default();
|
||||
let mut vars = Vec::with_capacity(updates.len() + 2);
|
||||
let mut cons = Vec::with_capacity(updates.len() + 3);
|
||||
for (field_name, Field { var, loc_expr, .. }) in updates.clone() {
|
||||
|
@ -1238,7 +1251,7 @@ pub fn constrain_expr(
|
|||
field_name.clone(),
|
||||
&loc_expr,
|
||||
);
|
||||
fields.insert(field_name, tipe);
|
||||
fields.insert(field_name, RecordField::Required(tipe));
|
||||
vars.push(var);
|
||||
cons.push(con);
|
||||
}
|
||||
|
@ -1300,7 +1313,7 @@ pub fn constrain_expr(
|
|||
let field_uniq_type = Bool::variable(field_uniq_var);
|
||||
let field_type = attr_type(field_uniq_type, Type::Variable(*field_var));
|
||||
|
||||
field_types.insert(field.clone(), field_type.clone());
|
||||
field_types.insert(field.clone(), RecordField::Required(field_type.clone()));
|
||||
|
||||
let record_uniq_var = var_store.fresh();
|
||||
let record_uniq_type = Bool::container(record_uniq_var, vec![field_uniq_var]);
|
||||
|
@ -1357,7 +1370,7 @@ pub fn constrain_expr(
|
|||
let field_uniq_type = Bool::variable(field_uniq_var);
|
||||
let field_type = attr_type(field_uniq_type, Type::Variable(*field_var));
|
||||
|
||||
field_types.insert(field.clone(), field_type.clone());
|
||||
field_types.insert(field.clone(), RecordField::Required(field_type.clone()));
|
||||
|
||||
let record_uniq_var = var_store.fresh();
|
||||
let record_uniq_type = Bool::container(record_uniq_var, vec![field_uniq_var]);
|
||||
|
@ -1589,8 +1602,11 @@ fn constrain_by_usage_record(
|
|||
|
||||
let field_type = attr_type(Bool::Shared, nested_type);
|
||||
|
||||
field_types.insert(lowercase.clone(), field_type);
|
||||
// In expressions, it's only possible to do record access on
|
||||
// Required fields.
|
||||
field_types.insert(lowercase.clone(), RecordField::Required(field_type));
|
||||
}
|
||||
|
||||
(
|
||||
Bool::Shared,
|
||||
Type::Record(
|
||||
|
@ -1622,8 +1638,11 @@ fn constrain_by_usage_record(
|
|||
Bool::Shared => attr_type(Bool::Shared, nested_type),
|
||||
};
|
||||
|
||||
field_types.insert(lowercase.clone(), field_type);
|
||||
// In expressions, it's only possible to do record access on
|
||||
// Required fields.
|
||||
field_types.insert(lowercase.clone(), RecordField::Required(field_type));
|
||||
}
|
||||
|
||||
(
|
||||
Bool::container(record_uniq_var, uniq_vars),
|
||||
Type::Record(
|
||||
|
@ -1828,10 +1847,28 @@ fn annotation_to_attr_type(
|
|||
let mut vars = Vec::with_capacity(fields.len());
|
||||
let mut lifted_fields = SendMap::default();
|
||||
|
||||
for (label, tipe) in fields.clone() {
|
||||
let (new_vars, lifted_field) =
|
||||
annotation_to_attr_type(var_store, &tipe, rigids, change_var_kind);
|
||||
vars.extend(new_vars);
|
||||
for (label, field) in fields.clone() {
|
||||
use RecordField::*;
|
||||
|
||||
let lifted_field = match field {
|
||||
Required(tipe) => {
|
||||
let (new_vars, lifted_field) =
|
||||
annotation_to_attr_type(var_store, &tipe, rigids, change_var_kind);
|
||||
|
||||
vars.extend(new_vars);
|
||||
|
||||
Required(lifted_field)
|
||||
}
|
||||
Optional(tipe) => {
|
||||
let (new_vars, lifted_field) =
|
||||
annotation_to_attr_type(var_store, &tipe, rigids, change_var_kind);
|
||||
|
||||
vars.extend(new_vars);
|
||||
|
||||
Optional(lifted_field)
|
||||
}
|
||||
};
|
||||
|
||||
lifted_fields.insert(label, lifted_field);
|
||||
}
|
||||
|
||||
|
@ -2425,9 +2462,15 @@ fn fix_mutual_recursive_alias_help_help(rec_var: Variable, attribute: &Type, int
|
|||
|
||||
Record(fields, ext) => {
|
||||
fix_mutual_recursive_alias_help(rec_var, attribute, ext);
|
||||
fields
|
||||
.iter_mut()
|
||||
.for_each(|arg| fix_mutual_recursive_alias_help(rec_var, attribute, arg));
|
||||
|
||||
for field in fields.iter_mut() {
|
||||
let arg = match field {
|
||||
RecordField::Required(arg) => arg,
|
||||
RecordField::Optional(arg) => arg,
|
||||
};
|
||||
|
||||
fix_mutual_recursive_alias_help(rec_var, attribute, arg);
|
||||
}
|
||||
}
|
||||
Alias(_, _, actual_type) => {
|
||||
// call help_help, because actual_type is not wrapped in ATTR
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue