mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
stop unification when ext vars don't unify
This commit is contained in:
parent
2d6e47b8a6
commit
3f4346f573
3 changed files with 88 additions and 11 deletions
|
@ -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 "));
|
||||||
|
|
|
@ -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 ]
|
||||||
|
|
||||||
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
),
|
),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue