From fdceedda005e8587b957dcb18a40e4d07a7c2f54 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Sat, 18 Jul 2020 14:16:46 -0400 Subject: [PATCH] Fix unifying optional fields --- compiler/solve/tests/solve_expr.rs | 30 ++++++++++++++++++++++++++++++ compiler/unify/src/unify.rs | 15 +++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index df9125ceee..76f8296003 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -2565,4 +2565,34 @@ mod solve_expr { "should fail", ); } + + // OPTIONAL RECORD FIELDS + + #[test] + fn optional_field_unifies_with_missing() { + infer_eq_without_problem( + indoc!( + r#" + negatePoint : { x : Int, y : Int, z ? Num c } -> { x : Int, y : Int, z : Num c } + + negatePoint { x: 1, y: 2 } + "# + ), + "{ x : Int, y : Int, z : Num c }", + ); + } + + #[test] + fn optional_field_unifies_with_present() { + infer_eq_without_problem( + indoc!( + r#" + negatePoint : { x : Num a, y : Num b, z ? c } -> { x : Num a, y : Num b, z : c } + + negatePoint { x: 1, y: 2.1, z: 0x3 } + "# + ), + "{ x : Num a, y : Float, z : Int }", + ); + } } diff --git a/compiler/unify/src/unify.rs b/compiler/unify/src/unify.rs index 7ff9edfd2d..78c84c1a1f 100644 --- a/compiler/unify/src/unify.rs +++ b/compiler/unify/src/unify.rs @@ -614,6 +614,17 @@ fn unify_shared_tags( } } +fn has_no_required_fields<'a, I, T>(fields: &mut I) -> bool +where + I: Iterator>, + T: 'a, +{ + fields.all(|field| match field { + RecordField::Required(_) => false, + RecordField::Optional(_) => true, + }) +} + #[inline(always)] fn unify_flat_type( subs: &mut Subs, @@ -627,11 +638,11 @@ fn unify_flat_type( match (left, right) { (EmptyRecord, EmptyRecord) => merge(subs, ctx, Structure(left.clone())), - (Record(fields, ext), EmptyRecord) if fields.is_empty() => { + (Record(fields, ext), EmptyRecord) if has_no_required_fields(&mut fields.values()) => { unify_pool(subs, pool, *ext, ctx.second) } - (EmptyRecord, Record(fields, ext)) if fields.is_empty() => { + (EmptyRecord, Record(fields, ext)) if has_no_required_fields(&mut fields.values()) => { unify_pool(subs, pool, ctx.first, *ext) }