Wrap content that is unwrapped and passes through a type alias correctly

Closes #2592
This commit is contained in:
ayazhafiz 2022-02-26 15:04:11 -05:00
parent 67658ed7b5
commit 4742847ba9
3 changed files with 55 additions and 2 deletions

View file

@ -1862,6 +1862,14 @@ impl UnionTags {
slice.length == 1 slice.length == 1
} }
pub fn is_newtype_wrapper_of_global_tag(&self, subs: &Subs) -> bool {
self.is_newtype_wrapper(subs) && {
let tags = &subs.tag_names[self.tag_names().indices()];
debug_assert_eq!(tags.len(), 1);
matches!(tags[0], TagName::Global(_))
}
}
pub fn from_tag_name_index(index: SubsIndex<TagName>) -> Self { pub fn from_tag_name_index(index: SubsIndex<TagName>) -> Self {
Self::from_slices( Self::from_slices(
SubsSlice::new(index.index, 1), SubsSlice::new(index.index, 1),

View file

@ -70,6 +70,7 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>(
} }
} }
#[derive(Debug)]
enum NewtypeKind<'a> { enum NewtypeKind<'a> {
Tag(&'a TagName), Tag(&'a TagName),
RecordField(&'a str), RecordField(&'a str),
@ -89,10 +90,11 @@ fn unroll_newtypes<'a>(
mut content: &'a Content, mut content: &'a Content,
) -> (Vec<'a, NewtypeKind<'a>>, &'a Content) { ) -> (Vec<'a, NewtypeKind<'a>>, &'a Content) {
let mut newtype_containers = Vec::with_capacity_in(1, env.arena); let mut newtype_containers = Vec::with_capacity_in(1, env.arena);
let mut force_alias_content = None;
loop { loop {
match content { match content {
Content::Structure(FlatType::TagUnion(tags, _)) Content::Structure(FlatType::TagUnion(tags, _))
if tags.is_newtype_wrapper(env.subs) => if tags.is_newtype_wrapper_of_global_tag(env.subs) =>
{ {
let (tag_name, vars): (&TagName, &[Variable]) = tags let (tag_name, vars): (&TagName, &[Variable]) = tags
.unsorted_iterator(env.subs, Variable::EMPTY_TAG_UNION) .unsorted_iterator(env.subs, Variable::EMPTY_TAG_UNION)
@ -113,7 +115,20 @@ fn unroll_newtypes<'a>(
let field_var = *field.as_inner(); let field_var = *field.as_inner();
content = env.subs.get_content_without_compacting(field_var); content = env.subs.get_content_without_compacting(field_var);
} }
_ => return (newtype_containers, content), Content::Alias(_, _, real_var) => {
// We need to pass through aliases too, because their underlying types may have
// unrolled newtypes. In such cases return the list of unrolled newtypes, but keep
// the content as the alias for readability. For example,
// T : { a : Str }
// v : T
// v = { a : "value" }
// v
// Here we need the newtype container to be `[RecordField(a)]`, but the content to
// remain as the alias `T`.
force_alias_content = Some(content);
content = env.subs.get_content_without_compacting(*real_var);
}
_ => return (newtype_containers, force_alias_content.unwrap_or(content)),
} }
} }
} }

View file

@ -975,3 +975,33 @@ fn issue_2343_complete_mono_with_shadowed_vars() {
), ),
); );
} }
#[test]
fn record_with_type_behind_alias() {
expect_success(
indoc!(
r#"
T : { a: Str }
v : T
v = { a: "value" }
v
"#
),
r#"{ a: "value" } : T"#,
);
}
#[test]
fn tag_with_type_behind_alias() {
expect_success(
indoc!(
r#"
T : [ A Str ]
v : T
v = A "value"
v
"#
),
r#"A "value" : T"#,
);
}