From 3f4346f5739c8538dee667bf124163acf16b27c4 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 6 Apr 2020 19:37:40 +0200 Subject: [PATCH] stop unification when ext vars don't unify --- compiler/reporting/src/type_error.rs | 8 +-- compiler/reporting/tests/test_reporting.rs | 33 ++++++++++++ compiler/unify/src/unify.rs | 58 +++++++++++++++++++--- 3 files changed, 88 insertions(+), 11 deletions(-) diff --git a/compiler/reporting/src/type_error.rs b/compiler/reporting/src/type_error.rs index 2ec09739b2..2054384d32 100644 --- a/compiler/reporting/src/type_error.rs +++ b/compiler/reporting/src/type_error.rs @@ -1025,7 +1025,7 @@ mod report_text { } else { let entry_to_text = |(tag_name, arguments)| concat(vec![tag_name, separate(arguments)]); - let starts = std::iter::once(plain_text("[")).chain(std::iter::repeat(plain_text(","))); + let starts = std::iter::once(plain_text("[ ")).chain(std::iter::repeat(plain_text(", "))); let mut lines: Vec<_> = entries .into_iter() @@ -1033,7 +1033,7 @@ mod report_text { .map(|(entry, start)| concat(vec![start, entry_to_text(entry)])) .collect(); - lines.push(plain_text("]")); + lines.push(plain_text(" ]")); lines.push(ext_text); concat(lines) @@ -1056,7 +1056,7 @@ mod report_text { } else { let entry_to_text = |(tag_name, arguments)| concat(vec![tag_name, separate(arguments)]); - let starts = std::iter::once(plain_text("[")).chain(std::iter::repeat(plain_text(","))); + let starts = std::iter::once(plain_text("[ ")).chain(std::iter::repeat(plain_text(", "))); let mut lines: Vec<_> = entries .into_iter() @@ -1064,7 +1064,7 @@ mod report_text { .map(|(entry, start)| concat(vec![start, entry_to_text(entry)])) .collect(); - lines.push(plain_text("]")); + lines.push(plain_text(" ]")); lines.push(ext_text); lines.push(plain_text(" as ")); diff --git a/compiler/reporting/tests/test_reporting.rs b/compiler/reporting/tests/test_reporting.rs index 7aa9c0c046..c18dc3367d 100644 --- a/compiler/reporting/tests/test_reporting.rs +++ b/compiler/reporting/tests/test_reporting.rs @@ -1190,6 +1190,39 @@ mod test_reporting { { foo : Int } + + "# + ), + ) + } + + #[test] + fn tag_mismatch() { + report_problem_as( + indoc!( + r#" + f : [ Red, Green ] -> Bool + f = \_ -> True + + f Blue + "# + ), + indoc!( + r#" + The 1st argument to `f` is not what I expect: + + 4 ┆ f Blue + ┆ ^^^^ + + This `Blue` global tag application produces: + + [ Blue, Green, Red ] + + But `f` needs the 1st argument to be: + + [ Green, Red ] + + "# ), ) diff --git a/compiler/unify/src/unify.rs b/compiler/unify/src/unify.rs index 205b2770ce..6c952d9d13 100644 --- a/compiler/unify/src/unify.rs +++ b/compiler/unify/src/unify.rs @@ -116,7 +116,7 @@ pub fn unify_pool(subs: &mut Subs, pool: &mut Pool, var1: Variable, var2: Variab } fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome { - // println!( "{:?} {:?} ~ {:?} {:?}", ctx.first, ctx.first_desc.content, ctx.second, ctx.second_desc.content); + // println!( "{:?} {:?} ~ {:?} {:?}", ctx.first, ctx.first_desc.content, ctx.second, ctx.second_desc.content,); match &ctx.first_desc.content { FlexVar(opt_name) => unify_flex(subs, pool, &ctx, opt_name, &ctx.second_desc.content), RigidVar(name) => unify_rigid(subs, &ctx, name, &ctx.second_desc.content), @@ -245,6 +245,11 @@ fn unify_record( if unique_fields1.is_empty() { if unique_fields2.is_empty() { let ext_problems = unify_pool(subs, pool, rec1.ext, rec2.ext); + + if !ext_problems.is_empty() { + return ext_problems; + } + let other_fields = MutMap::default(); let mut field_problems = unify_shared_fields(subs, pool, ctx, shared_fields, other_fields, rec1.ext); @@ -256,6 +261,11 @@ fn unify_record( let flat_type = FlatType::Record(unique_fields2, rec2.ext); let sub_record = fresh(subs, pool, ctx, Structure(flat_type)); let ext_problems = unify_pool(subs, pool, rec1.ext, sub_record); + + if !ext_problems.is_empty() { + return ext_problems; + } + let other_fields = MutMap::default(); let mut field_problems = unify_shared_fields(subs, pool, ctx, shared_fields, other_fields, sub_record); @@ -268,6 +278,11 @@ fn unify_record( let flat_type = FlatType::Record(unique_fields1, rec1.ext); let sub_record = fresh(subs, pool, ctx, Structure(flat_type)); let ext_problems = unify_pool(subs, pool, sub_record, rec2.ext); + + if !ext_problems.is_empty() { + return ext_problems; + } + let other_fields = MutMap::default(); let mut field_problems = unify_shared_fields(subs, pool, ctx, shared_fields, other_fields, sub_record); @@ -286,7 +301,14 @@ fn unify_record( let sub2 = fresh(subs, pool, ctx, Structure(flat_type2)); let rec1_problems = unify_pool(subs, pool, rec1.ext, sub2); + if !rec1_problems.is_empty() { + return rec1_problems; + } + let rec2_problems = unify_pool(subs, pool, sub1, rec2.ext); + if !rec2_problems.is_empty() { + return rec2_problems; + } let mut field_problems = unify_shared_fields(subs, pool, ctx, shared_fields, other_fields, ext); @@ -362,6 +384,11 @@ fn unify_tag_union( if unique_tags1.is_empty() { if unique_tags2.is_empty() { let ext_problems = unify_pool(subs, pool, rec1.ext, rec2.ext); + + if !ext_problems.is_empty() { + return ext_problems; + } + let mut tag_problems = unify_shared_tags( subs, pool, @@ -379,6 +406,11 @@ fn unify_tag_union( let flat_type = FlatType::TagUnion(unique_tags2, rec2.ext); let sub_record = fresh(subs, pool, ctx, Structure(flat_type)); let ext_problems = unify_pool(subs, pool, rec1.ext, sub_record); + + if !ext_problems.is_empty() { + return ext_problems; + } + let mut tag_problems = unify_shared_tags( subs, pool, @@ -397,6 +429,11 @@ fn unify_tag_union( let flat_type = FlatType::TagUnion(unique_tags1, rec1.ext); let sub_record = fresh(subs, pool, ctx, Structure(flat_type)); let ext_problems = unify_pool(subs, pool, sub_record, rec2.ext); + + if !ext_problems.is_empty() { + return ext_problems; + } + let mut tag_problems = unify_shared_tags( subs, pool, @@ -420,15 +457,22 @@ fn unify_tag_union( let sub1 = fresh(subs, pool, ctx, Structure(flat_type1)); let sub2 = fresh(subs, pool, ctx, Structure(flat_type2)); - let rec1_problems = unify_pool(subs, pool, rec1.ext, sub2); - let rec2_problems = unify_pool(subs, pool, sub1, rec2.ext); + let ext1_problems = unify_pool(subs, pool, rec1.ext, sub2); + if !ext1_problems.is_empty() { + return ext1_problems; + } + + let ext2_problems = unify_pool(subs, pool, sub1, rec2.ext); + if !ext2_problems.is_empty() { + return ext2_problems; + } let mut tag_problems = unify_shared_tags(subs, pool, ctx, shared_tags, other_tags, ext, recursion_var); - tag_problems.reserve(rec1_problems.len() + rec2_problems.len()); - tag_problems.extend(rec1_problems); - tag_problems.extend(rec2_problems); + tag_problems.reserve(ext1_problems.len() + ext2_problems.len()); + tag_problems.extend(ext1_problems); + tag_problems.extend(ext2_problems); tag_problems } @@ -610,7 +654,7 @@ fn unify_flat_type( } } (other1, other2) => mismatch!( - "Trying to two flat types that are incompatible: {:?} ~ {:?}", + "Trying to unify two flat types that are incompatible: {:?} ~ {:?}", other1, other2 ),