diff options
| author | FintanH | 2019-08-03 18:45:32 +0100 | 
|---|---|---|
| committer | FintanH | 2019-08-03 18:45:32 +0100 | 
| commit | 6bcb9bed4820f2307b1d3e512fa2d7252ba82f02 (patch) | |
| tree | 1012ed5c2443301b7af440a973a9573d3285d743 /dhall/src/phase | |
| parent | 0cc150a43dc9a851e81a2b6278447400856c1aba (diff) | |
| parent | 9113e15534f57626ae9be662738e1d3d22434e88 (diff) | |
Merge remote-tracking branch 'origin/master' into fintan/typecheck-combine
Diffstat (limited to '')
| -rw-r--r-- | dhall/src/phase/normalize.rs | 19 | ||||
| -rw-r--r-- | dhall/src/phase/typecheck.rs | 52 | 
2 files changed, 57 insertions, 14 deletions
| diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index e3c5d68..7d86833 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -382,13 +382,13 @@ enum Ret<'a> {  /// * `fu` - Will convert the values of the second map  ///          into the target value.  /// -/// * `ftu` - Will convert the key and values from both maps +/// * `fktu` - Will convert the key and values from both maps  ///           into the target type.  ///  /// # Description  ///  /// If the key is present in both maps then the final value for -/// that key is computed via the `ftu` function. Otherwise, the +/// that key is computed via the `fktu` function. Otherwise, the  /// final value will be calculated by either the `ft` or `fu` value  /// depending on which map the key is present in.  /// @@ -397,35 +397,36 @@ enum Ret<'a> {  pub(crate) fn outer_join<K, T, U, V>(      mut ft: impl FnMut(&T) -> V,      mut fu: impl FnMut(&U) -> V, -    mut ftu: impl FnMut(&K, &T, &U) -> V, +    mut fktu: impl FnMut(&K, &T, &U) -> V,      map1: &HashMap<K, T>,      map2: &HashMap<K, U>,  ) -> HashMap<K, V>  where      K: std::hash::Hash + Eq + Clone,  { -    let mut kus = HashMap::new(); +    let mut kvs = HashMap::new(); +      for (k1, t) in map1 {          let v = if let Some(u) = map2.get(k1) {              // The key exists in both maps              // so use all values for computation -            ftu(k1, t, u) +            fktu(k1, t, u)          } else {              // Key only exists in map1              ft(t)          }; -        kus.insert(k1.clone(), v); +        kvs.insert(k1.clone(), v);      }      for (k1, u) in map2 {          // Insert if key was missing in map1 -        kus.entry(k1.clone()).or_insert(fu(u)); +        kvs.entry(k1.clone()).or_insert(fu(u));      } -    kus +    kvs  } -fn merge_maps<K, V>( +pub(crate) fn merge_maps<K, V>(      map1: &HashMap<K, V>,      map2: &HashMap<K, V>,      mut f: impl FnMut(&V, &V) -> V, diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index c927ae2..9bb0e32 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -598,6 +598,47 @@ fn type_last_layer(              }              Ok(RetTypeOnly(text_type))          } +        BinOp(RightBiasedRecordMerge, l, r) => { +            use crate::phase::normalize::merge_maps; + +            let l_type = l.get_type()?; +            let l_kind = l_type.get_type()?; +            let r_type = r.get_type()?; +            let r_kind = r_type.get_type()?; + +            // Check the equality of kinds. +            // This is to disallow expression such as: +            // "{ x = Text } // { y = 1 }" +            ensure_equal!( +                l_kind, +                r_kind, +                mkerr(RecordMismatch(l.clone(), r.clone())), +            ); + +            // Extract the LHS record type +            let kts_x = match l_type.to_value() { +                Value::RecordType(kts) => kts, +                _ => return Err(mkerr(MustCombineRecord(l.clone()))), +            }; + +            // Extract the RHS record type +            let kts_y = match r_type.to_value() { +                Value::RecordType(kts) => kts, +                _ => return Err(mkerr(MustCombineRecord(r.clone()))), +            }; + +            // Union the two records, prefering +            // the values found in the RHS. +            let kts = merge_maps(&kts_x, &kts_y, |_, r_t| r_t.clone()); + +            // Construct the final record type from the union +            Ok(RetTypeOnly(tck_record_type( +                ctx, +                kts.iter() +                   .map(|(x, v)| Ok((x.clone(), v.to_type()))), +            )? +            .into_type())) +        }          BinOp(RecursiveRecordMerge, l, r) => {              // A recursive function to dig down into              // records of records when merging. @@ -687,6 +728,7 @@ fn type_last_layer(                  NaturalTimes => Natural,                  TextAppend => Text,                  ListAppend => unreachable!(), +                RightBiasedRecordMerge => unreachable!(),                  RecursiveRecordMerge => unreachable!(),                  _ => return Err(mkerr(Unimplemented)),              })?; @@ -1201,11 +1243,11 @@ mod spec_tests {      // ti_success!(ti_success_unit_RecursiveRecordTypeMergeTwo, "unit/RecursiveRecordTypeMergeTwo");      // ti_success!(ti_success_unit_RecursiveRecordTypeMergeTwoKinds, "unit/RecursiveRecordTypeMergeTwoKinds");      // ti_success!(ti_success_unit_RecursiveRecordTypeMergeTwoTypes, "unit/RecursiveRecordTypeMergeTwoTypes"); -    // ti_success!(ti_success_unit_RightBiasedRecordMergeRhsEmpty, "unit/RightBiasedRecordMergeRhsEmpty"); -    // ti_success!(ti_success_unit_RightBiasedRecordMergeTwo, "unit/RightBiasedRecordMergeTwo"); -    // ti_success!(ti_success_unit_RightBiasedRecordMergeTwoDifferent, "unit/RightBiasedRecordMergeTwoDifferent"); -    // ti_success!(ti_success_unit_RightBiasedRecordMergeTwoKinds, "unit/RightBiasedRecordMergeTwoKinds"); -    // ti_success!(ti_success_unit_RightBiasedRecordMergeTwoTypes, "unit/RightBiasedRecordMergeTwoTypes"); +    ti_success!(ti_success_unit_RightBiasedRecordMergeRhsEmpty, "unit/RightBiasedRecordMergeRhsEmpty"); +    ti_success!(ti_success_unit_RightBiasedRecordMergeTwo, "unit/RightBiasedRecordMergeTwo"); +    ti_success!(ti_success_unit_RightBiasedRecordMergeTwoDifferent, "unit/RightBiasedRecordMergeTwoDifferent"); +    ti_success!(ti_success_unit_RightBiasedRecordMergeTwoKinds, "unit/RightBiasedRecordMergeTwoKinds"); +    ti_success!(ti_success_unit_RightBiasedRecordMergeTwoTypes, "unit/RightBiasedRecordMergeTwoTypes");      ti_success!(ti_success_unit_SomeTrue, "unit/SomeTrue");      ti_success!(ti_success_unit_Text, "unit/Text");      ti_success!(ti_success_unit_TextLiteral, "unit/TextLiteral"); | 
