stop unification when ext vars don't unify

This commit is contained in:
Folkert 2020-04-06 19:37:40 +02:00
parent 2d6e47b8a6
commit 3f4346f573
3 changed files with 88 additions and 11 deletions

View file

@ -1025,7 +1025,7 @@ mod report_text {
} else { } else {
let entry_to_text = |(tag_name, arguments)| concat(vec![tag_name, separate(arguments)]); 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 let mut lines: Vec<_> = entries
.into_iter() .into_iter()
@ -1033,7 +1033,7 @@ mod report_text {
.map(|(entry, start)| concat(vec![start, entry_to_text(entry)])) .map(|(entry, start)| concat(vec![start, entry_to_text(entry)]))
.collect(); .collect();
lines.push(plain_text("]")); lines.push(plain_text(" ]"));
lines.push(ext_text); lines.push(ext_text);
concat(lines) concat(lines)
@ -1056,7 +1056,7 @@ mod report_text {
} else { } else {
let entry_to_text = |(tag_name, arguments)| concat(vec![tag_name, separate(arguments)]); 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 let mut lines: Vec<_> = entries
.into_iter() .into_iter()
@ -1064,7 +1064,7 @@ mod report_text {
.map(|(entry, start)| concat(vec![start, entry_to_text(entry)])) .map(|(entry, start)| concat(vec![start, entry_to_text(entry)]))
.collect(); .collect();
lines.push(plain_text("]")); lines.push(plain_text(" ]"));
lines.push(ext_text); lines.push(ext_text);
lines.push(plain_text(" as ")); lines.push(plain_text(" as "));

View file

@ -1190,6 +1190,39 @@ mod test_reporting {
{ foo : Int } { 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 ]
"# "#
), ),
) )

View file

@ -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 { 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 { match &ctx.first_desc.content {
FlexVar(opt_name) => unify_flex(subs, pool, &ctx, opt_name, &ctx.second_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), 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_fields1.is_empty() {
if unique_fields2.is_empty() { if unique_fields2.is_empty() {
let ext_problems = unify_pool(subs, pool, rec1.ext, rec2.ext); 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 other_fields = MutMap::default();
let mut field_problems = let mut field_problems =
unify_shared_fields(subs, pool, ctx, shared_fields, other_fields, rec1.ext); 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 flat_type = FlatType::Record(unique_fields2, rec2.ext);
let sub_record = fresh(subs, pool, ctx, Structure(flat_type)); let sub_record = fresh(subs, pool, ctx, Structure(flat_type));
let ext_problems = unify_pool(subs, pool, rec1.ext, sub_record); 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 other_fields = MutMap::default();
let mut field_problems = let mut field_problems =
unify_shared_fields(subs, pool, ctx, shared_fields, other_fields, sub_record); 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 flat_type = FlatType::Record(unique_fields1, rec1.ext);
let sub_record = fresh(subs, pool, ctx, Structure(flat_type)); let sub_record = fresh(subs, pool, ctx, Structure(flat_type));
let ext_problems = unify_pool(subs, pool, sub_record, rec2.ext); 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 other_fields = MutMap::default();
let mut field_problems = let mut field_problems =
unify_shared_fields(subs, pool, ctx, shared_fields, other_fields, sub_record); 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 sub2 = fresh(subs, pool, ctx, Structure(flat_type2));
let rec1_problems = unify_pool(subs, pool, rec1.ext, sub2); 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); let rec2_problems = unify_pool(subs, pool, sub1, rec2.ext);
if !rec2_problems.is_empty() {
return rec2_problems;
}
let mut field_problems = let mut field_problems =
unify_shared_fields(subs, pool, ctx, shared_fields, other_fields, ext); 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_tags1.is_empty() {
if unique_tags2.is_empty() { if unique_tags2.is_empty() {
let ext_problems = unify_pool(subs, pool, rec1.ext, rec2.ext); 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( let mut tag_problems = unify_shared_tags(
subs, subs,
pool, pool,
@ -379,6 +406,11 @@ fn unify_tag_union(
let flat_type = FlatType::TagUnion(unique_tags2, rec2.ext); let flat_type = FlatType::TagUnion(unique_tags2, rec2.ext);
let sub_record = fresh(subs, pool, ctx, Structure(flat_type)); let sub_record = fresh(subs, pool, ctx, Structure(flat_type));
let ext_problems = unify_pool(subs, pool, rec1.ext, sub_record); 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( let mut tag_problems = unify_shared_tags(
subs, subs,
pool, pool,
@ -397,6 +429,11 @@ fn unify_tag_union(
let flat_type = FlatType::TagUnion(unique_tags1, rec1.ext); let flat_type = FlatType::TagUnion(unique_tags1, rec1.ext);
let sub_record = fresh(subs, pool, ctx, Structure(flat_type)); let sub_record = fresh(subs, pool, ctx, Structure(flat_type));
let ext_problems = unify_pool(subs, pool, sub_record, rec2.ext); 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( let mut tag_problems = unify_shared_tags(
subs, subs,
pool, pool,
@ -420,15 +457,22 @@ fn unify_tag_union(
let sub1 = fresh(subs, pool, ctx, Structure(flat_type1)); let sub1 = fresh(subs, pool, ctx, Structure(flat_type1));
let sub2 = fresh(subs, pool, ctx, Structure(flat_type2)); let sub2 = fresh(subs, pool, ctx, Structure(flat_type2));
let rec1_problems = unify_pool(subs, pool, rec1.ext, sub2); let ext1_problems = unify_pool(subs, pool, rec1.ext, sub2);
let rec2_problems = unify_pool(subs, pool, sub1, rec2.ext); 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 = let mut tag_problems =
unify_shared_tags(subs, pool, ctx, shared_tags, other_tags, ext, recursion_var); unify_shared_tags(subs, pool, ctx, shared_tags, other_tags, ext, recursion_var);
tag_problems.reserve(rec1_problems.len() + rec2_problems.len()); tag_problems.reserve(ext1_problems.len() + ext2_problems.len());
tag_problems.extend(rec1_problems); tag_problems.extend(ext1_problems);
tag_problems.extend(rec2_problems); tag_problems.extend(ext2_problems);
tag_problems tag_problems
} }
@ -610,7 +654,7 @@ fn unify_flat_type(
} }
} }
(other1, other2) => mismatch!( (other1, other2) => mismatch!(
"Trying to two flat types that are incompatible: {:?} ~ {:?}", "Trying to unify two flat types that are incompatible: {:?} ~ {:?}",
other1, other1,
other2 other2
), ),