From 28a2f9656edc62d73501bdcc21cf28f4818e90d0 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Sat, 18 Jul 2020 14:51:18 -0400 Subject: [PATCH] Constrain optional fields --- compiler/can/src/pattern.rs | 3 ++- compiler/constrain/src/expr.rs | 12 ++++++++++-- compiler/constrain/src/pattern.rs | 30 ++++++++++++++++++++++++------ compiler/constrain/src/uniq.rs | 2 +- compiler/types/src/types.rs | 2 ++ 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/compiler/can/src/pattern.rs b/compiler/can/src/pattern.rs index ecc40c7652..a8bc6ba307 100644 --- a/compiler/can/src/pattern.rs +++ b/compiler/can/src/pattern.rs @@ -1,4 +1,5 @@ use crate::env::Env; +use crate::expr::Expr; use crate::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int}; use crate::scope::Scope; use roc_module::ident::{Ident, Lowercase, TagName}; @@ -50,7 +51,7 @@ pub struct RecordDestruct { #[derive(Clone, Debug, PartialEq)] pub enum DestructType { Required, - Optional(Variable), + Optional(Variable, Located), Guard(Variable, Located), } diff --git a/compiler/constrain/src/expr.rs b/compiler/constrain/src/expr.rs index a4fa372dfb..a646e03275 100644 --- a/compiler/constrain/src/expr.rs +++ b/compiler/constrain/src/expr.rs @@ -327,6 +327,7 @@ pub fn constrain_expr( pattern_types.push(pattern_type); constrain_pattern( + env, &loc_pattern.value, loc_pattern.region, pattern_expected, @@ -843,6 +844,7 @@ fn constrain_when_branch( // then unify that variable with the expectation? for loc_pattern in &when_branch.patterns { constrain_pattern( + env, &loc_pattern.value, loc_pattern.region, pattern_expected.clone(), @@ -947,7 +949,11 @@ pub fn constrain_decls( constraint } -fn constrain_def_pattern(loc_pattern: &Located, expr_type: Type) -> PatternState { +fn constrain_def_pattern( + env: &Env, + loc_pattern: &Located, + expr_type: Type, +) -> PatternState { let pattern_expected = PExpected::NoExpectation(expr_type); let mut state = PatternState { @@ -957,6 +963,7 @@ fn constrain_def_pattern(loc_pattern: &Located, expr_type: Type) -> Pat }; constrain_pattern( + env, &loc_pattern.value, loc_pattern.region, pattern_expected, @@ -970,7 +977,7 @@ fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint { let expr_var = def.expr_var; let expr_type = Type::Variable(expr_var); - let mut pattern_state = constrain_def_pattern(&def.loc_pattern, expr_type.clone()); + let mut pattern_state = constrain_def_pattern(env, &def.loc_pattern, expr_type.clone()); pattern_state.vars.push(expr_var); @@ -1117,6 +1124,7 @@ pub fn rec_defs_help( }; constrain_pattern( + env, &def.loc_pattern.value, def.loc_pattern.region, pattern_expected, diff --git a/compiler/constrain/src/pattern.rs b/compiler/constrain/src/pattern.rs index 21bca628b4..25db18453a 100644 --- a/compiler/constrain/src/pattern.rs +++ b/compiler/constrain/src/pattern.rs @@ -1,4 +1,5 @@ use crate::builtins; +use crate::expr::{constrain_expr, Env}; use roc_can::constraint::Constraint; use roc_can::expected::{Expected, PExpected}; use roc_can::pattern::Pattern::{self, *}; @@ -8,7 +9,7 @@ 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, RecordField, Type}; +use roc_types::types::{Category, PReason, PatternCategory, Reason, RecordField, Type}; pub struct PatternState { pub headers: SendMap>, @@ -120,6 +121,7 @@ fn headers_from_annotation_help( /// intiialize the Vecs in PatternState using with_capacity /// based on its knowledge of their lengths. pub fn constrain_pattern( + env: &Env, pattern: &Pattern, region: Region, expected: PExpected, @@ -223,14 +225,30 @@ pub fn constrain_pattern( )); state.vars.push(*guard_var); - constrain_pattern(&loc_guard.value, loc_guard.region, expected, state); + constrain_pattern(env, &loc_guard.value, loc_guard.region, expected, state); RecordField::Required(pat_type) } - DestructType::Optional(_var) => { - todo!("Add a constraint for the default value."); + DestructType::Optional(expr_var, loc_expr) => { + // Eq(Type, Expected, Category, Region), + let expr_expected = Expected::ForReason( + Reason::RecordDefaultField(label.clone()), + pat_type.clone(), + loc_expr.region, + ); - // RecordField::Optional(pat_type) + state.constraints.push(Constraint::Eq( + Type::Variable(*expr_var), + expr_expected.clone(), + Category::DefaultValue(label.clone()), + region, + )); + + state.vars.push(*expr_var); + + constrain_expr(env, loc_expr.region, &loc_expr.value, expr_expected); + + RecordField::Optional(pat_type) } DestructType::Required => { // No extra constraints necessary. @@ -283,7 +301,7 @@ pub fn constrain_pattern( pattern_type, region, ); - constrain_pattern(&loc_pattern.value, loc_pattern.region, expected, state); + constrain_pattern(env, &loc_pattern.value, loc_pattern.region, expected, state); } let whole_con = Constraint::Eq( diff --git a/compiler/constrain/src/uniq.rs b/compiler/constrain/src/uniq.rs index 2addd2522e..073ec5d01d 100644 --- a/compiler/constrain/src/uniq.rs +++ b/compiler/constrain/src/uniq.rs @@ -250,7 +250,7 @@ fn constrain_pattern( RecordField::Required(pat_type) } - DestructType::Optional(_var) => { + DestructType::Optional(_expr_var, _loc_expr) => { todo!("Add a constraint for the default value."); // RecordField::Optional(pat_type) diff --git a/compiler/types/src/types.rs b/compiler/types/src/types.rs index 4d753d72c1..ae41d94814 100644 --- a/compiler/types/src/types.rs +++ b/compiler/types/src/types.rs @@ -864,6 +864,7 @@ pub enum Reason { }, RecordUpdateValue(Lowercase), RecordUpdateKeys(Symbol, SendMap), + RecordDefaultField(Lowercase), } #[derive(PartialEq, Debug, Clone)] @@ -893,6 +894,7 @@ pub enum Category { Record, Accessor(Lowercase), Access(Lowercase), + DefaultValue(Lowercase), // for setting optional fields } #[derive(Debug, Clone, PartialEq, Eq)]