early return in common tag case

This commit is contained in:
Folkert 2021-07-21 22:02:30 +02:00
parent 05b43c6799
commit 564efd528a

View file

@ -449,18 +449,22 @@ fn unify_tag_union(
let tags1 = rec1.tags; let tags1 = rec1.tags;
let tags2 = rec2.tags; let tags2 = rec2.tags;
let Separate {
only_in_1: unique_tags1,
only_in_2: unique_tags2,
in_both: shared_tags,
} = separate(tags1, tags2);
let recursion_var = match recursion { let recursion_var = match recursion {
(None, None) => None, (None, None) => None,
(Some(v), None) | (None, Some(v)) => Some(v), (Some(v), None) | (None, Some(v)) => Some(v),
(Some(v1), Some(_v2)) => Some(v1), (Some(v1), Some(_v2)) => Some(v1),
}; };
if tags1.len() == 1 && tags2.len() == 1 && tags1 == tags2 {
return unify_shared_tags_merge(subs, ctx, tags1, rec1.ext, recursion_var);
}
let Separate {
only_in_1: unique_tags1,
only_in_2: unique_tags2,
in_both: shared_tags,
} = separate(tags1, tags2);
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);
@ -724,8 +728,8 @@ fn unify_tag_union_not_recursive_recursive(
/// into it. /// into it.
#[allow(dead_code)] #[allow(dead_code)]
fn is_structure(var: Variable, subs: &mut Subs) -> bool { fn is_structure(var: Variable, subs: &mut Subs) -> bool {
match subs.get(var).content { match subs.get_content_without_compacting(var) {
Content::Alias(_, _, actual) => is_structure(actual, subs), Content::Alias(_, _, actual) => is_structure(*actual, subs),
Content::Structure(_) => true, Content::Structure(_) => true,
_ => false, _ => false,
} }
@ -875,6 +879,8 @@ fn unify_shared_tags(
} }
if num_shared_tags == matching_tags.len() { if num_shared_tags == matching_tags.len() {
let mut new_tags = matching_tags;
// merge fields from the ext_var into this tag union // merge fields from the ext_var into this tag union
let mut fields = Vec::new(); let mut fields = Vec::new();
let new_ext_var = match roc_types::pretty_print::chase_ext_tag_union(subs, ext, &mut fields) let new_ext_var = match roc_types::pretty_print::chase_ext_tag_union(subs, ext, &mut fields)
@ -882,8 +888,7 @@ fn unify_shared_tags(
Ok(()) => Variable::EMPTY_TAG_UNION, Ok(()) => Variable::EMPTY_TAG_UNION,
Err((new, _)) => new, Err((new, _)) => new,
}; };
new_tags.extend(fields.into_iter());
let mut new_tags = matching_tags;
match other_tags { match other_tags {
OtherTags::Empty => {} OtherTags::Empty => {}
@ -893,16 +898,7 @@ fn unify_shared_tags(
} }
} }
new_tags.extend(fields.into_iter()); unify_shared_tags_merge(subs, ctx, new_tags, new_ext_var, recursion_var)
let flat_type = if let Some(rec) = recursion_var {
debug_assert!(is_recursion_var(subs, rec));
FlatType::RecursiveTagUnion(rec, new_tags, new_ext_var)
} else {
FlatType::TagUnion(new_tags, new_ext_var)
};
merge(subs, ctx, Structure(flat_type))
} else { } else {
mismatch!( mismatch!(
"Problem with Tag Union\nThere should be {:?} matching tags, but I only got \n{:?}", "Problem with Tag Union\nThere should be {:?} matching tags, but I only got \n{:?}",
@ -912,6 +908,23 @@ fn unify_shared_tags(
} }
} }
fn unify_shared_tags_merge(
subs: &mut Subs,
ctx: &Context,
new_tags: MutMap<TagName, Vec<Variable>>,
new_ext_var: Variable,
recursion_var: Option<Variable>,
) -> Outcome {
let flat_type = if let Some(rec) = recursion_var {
debug_assert!(is_recursion_var(subs, rec));
FlatType::RecursiveTagUnion(rec, new_tags, new_ext_var)
} else {
FlatType::TagUnion(new_tags, new_ext_var)
};
merge(subs, ctx, Structure(flat_type))
}
fn has_only_optional_fields<'a, I, T>(fields: &mut I) -> bool fn has_only_optional_fields<'a, I, T>(fields: &mut I) -> bool
where where
I: Iterator<Item = &'a RecordField<T>>, I: Iterator<Item = &'a RecordField<T>>,
@ -1069,8 +1082,8 @@ fn unify_flat_type(
if tag_name_1 == tag_name_2 { if tag_name_1 == tag_name_2 {
let problems = unify_pool(subs, pool, *ext_1, *ext_2); let problems = unify_pool(subs, pool, *ext_1, *ext_2);
if problems.is_empty() { if problems.is_empty() {
let desc = subs.get(ctx.second); let content = subs.get_content_without_compacting(ctx.second).clone();
merge(subs, ctx, desc.content) merge(subs, ctx, content)
} else { } else {
problems problems
} }
@ -1292,19 +1305,25 @@ fn fresh(subs: &mut Subs, pool: &mut Pool, ctx: &Context, content: Content) -> V
fn gather_tags( fn gather_tags(
subs: &mut Subs, subs: &mut Subs,
tags: MutMap<TagName, Vec<Variable>>, mut tags: MutMap<TagName, Vec<Variable>>,
var: Variable, var: Variable,
) -> TagUnionStructure { ) -> TagUnionStructure {
use roc_types::subs::Content::*; use roc_types::subs::Content::*;
use roc_types::subs::FlatType::*; use roc_types::subs::FlatType::*;
match subs.get(var).content { match subs.get_content_without_compacting(var) {
Structure(TagUnion(sub_tags, sub_ext)) => { Structure(TagUnion(sub_tags, sub_ext)) => {
gather_tags(subs, union(tags, &sub_tags), sub_ext) for (k, v) in sub_tags {
tags.insert(k.clone(), v.clone());
}
let sub_ext = *sub_ext;
gather_tags(subs, tags, sub_ext)
} }
Alias(_, _, var) => { Alias(_, _, var) => {
// TODO according to elm/compiler: "TODO may be dropping useful alias info here" // TODO according to elm/compiler: "TODO may be dropping useful alias info here"
let var = *var;
gather_tags(subs, tags, var) gather_tags(subs, tags, var)
} }
@ -1314,7 +1333,7 @@ fn gather_tags(
fn is_recursion_var(subs: &Subs, var: Variable) -> bool { fn is_recursion_var(subs: &Subs, var: Variable) -> bool {
matches!( matches!(
subs.get_without_compacting(var).content, subs.get_content_without_compacting(var),
Content::RecursionVar { .. } Content::RecursionVar { .. }
) )
} }