mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
Wrap content that is unwrapped and passes through a type alias correctly
Closes #2592
This commit is contained in:
parent
67658ed7b5
commit
4742847ba9
3 changed files with 55 additions and 2 deletions
|
@ -1862,6 +1862,14 @@ impl UnionTags {
|
|||
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 {
|
||||
Self::from_slices(
|
||||
SubsSlice::new(index.index, 1),
|
||||
|
|
|
@ -70,6 +70,7 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum NewtypeKind<'a> {
|
||||
Tag(&'a TagName),
|
||||
RecordField(&'a str),
|
||||
|
@ -89,10 +90,11 @@ fn unroll_newtypes<'a>(
|
|||
mut content: &'a Content,
|
||||
) -> (Vec<'a, NewtypeKind<'a>>, &'a Content) {
|
||||
let mut newtype_containers = Vec::with_capacity_in(1, env.arena);
|
||||
let mut force_alias_content = None;
|
||||
loop {
|
||||
match content {
|
||||
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
|
||||
.unsorted_iterator(env.subs, Variable::EMPTY_TAG_UNION)
|
||||
|
@ -113,7 +115,20 @@ fn unroll_newtypes<'a>(
|
|||
let field_var = *field.as_inner();
|
||||
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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"#,
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue