mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-17 02:53:30 +00:00
parent
53e7a41f27
commit
5ad04dcd2c
6 changed files with 80 additions and 31 deletions
|
|
@ -1084,7 +1084,8 @@ fn type_to_union_tags<'a>(
|
||||||
|
|
||||||
let ext = {
|
let ext = {
|
||||||
let (it, ext) =
|
let (it, ext) =
|
||||||
roc_types::types::gather_tags_unsorted_iter(subs, UnionTags::default(), temp_ext_var);
|
roc_types::types::gather_tags_unsorted_iter(subs, UnionTags::default(), temp_ext_var)
|
||||||
|
.expect("not a tag union");
|
||||||
|
|
||||||
tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));
|
tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));
|
||||||
tag_vars.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
tag_vars.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
|
|
||||||
|
|
@ -3056,7 +3056,9 @@ pub fn ext_var_is_empty_tag_union(subs: &Subs, ext_var: Variable) -> bool {
|
||||||
// the ext_var is empty
|
// the ext_var is empty
|
||||||
let mut ext_fields = std::vec::Vec::new();
|
let mut ext_fields = std::vec::Vec::new();
|
||||||
match roc_types::pretty_print::chase_ext_tag_union(subs, ext_var, &mut ext_fields) {
|
match roc_types::pretty_print::chase_ext_tag_union(subs, ext_var, &mut ext_fields) {
|
||||||
Ok(()) | Err((_, Content::FlexVar(_) | Content::RigidVar(_))) => ext_fields.is_empty(),
|
Ok(()) | Err((_, Content::FlexVar(_) | Content::RigidVar(_) | Content::Error)) => {
|
||||||
|
ext_fields.is_empty()
|
||||||
|
}
|
||||||
Err(content) => panic!("invalid content in ext_var: {:?}", content),
|
Err(content) => panic!("invalid content in ext_var: {:?}", content),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2807,7 +2807,8 @@ fn type_to_variable<'a>(
|
||||||
subs,
|
subs,
|
||||||
UnionTags::default(),
|
UnionTags::default(),
|
||||||
temp_ext_var,
|
temp_ext_var,
|
||||||
);
|
)
|
||||||
|
.expect("extension var could not be seen as a tag union");
|
||||||
|
|
||||||
for _ in it {
|
for _ in it {
|
||||||
unreachable!("we assert that the ext var is empty; otherwise we'd already know it was a tag union!");
|
unreachable!("we assert that the ext var is empty; otherwise we'd already know it was a tag union!");
|
||||||
|
|
@ -3351,7 +3352,8 @@ fn type_to_union_tags<'a>(
|
||||||
subs,
|
subs,
|
||||||
UnionTags::default(),
|
UnionTags::default(),
|
||||||
temp_ext_var,
|
temp_ext_var,
|
||||||
);
|
)
|
||||||
|
.expect("extension var could not be seen as tag union");
|
||||||
|
|
||||||
tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));
|
tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1861,3 +1861,27 @@ fn issue_3560_newtype_tag_constructor_has_nested_constructor_with_no_payload() {
|
||||||
RocStr
|
RocStr
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
#[should_panic(expected = r#"Roc failed with message: "Erroneous: Expr::Closure""#)]
|
||||||
|
fn error_type_in_tag_union_payload() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
f : ([] -> Bool) -> Bool
|
||||||
|
f = \fun ->
|
||||||
|
if True then
|
||||||
|
fun 42
|
||||||
|
else
|
||||||
|
False
|
||||||
|
|
||||||
|
f (\x -> x)
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
0,
|
||||||
|
u8,
|
||||||
|
|x| x,
|
||||||
|
true // ignore type errors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2702,7 +2702,8 @@ impl UnionTags {
|
||||||
subs: &'a Subs,
|
subs: &'a Subs,
|
||||||
ext: Variable,
|
ext: Variable,
|
||||||
) -> impl Iterator<Item = (&TagName, &[Variable])> + 'a {
|
) -> impl Iterator<Item = (&TagName, &[Variable])> + 'a {
|
||||||
let (it, _) = crate::types::gather_tags_unsorted_iter(subs, *self, ext);
|
let (it, _) =
|
||||||
|
crate::types::gather_tags_unsorted_iter(subs, *self, ext).expect("not a tag union");
|
||||||
|
|
||||||
let f = move |(label, slice): (_, SubsSlice<Variable>)| (label, subs.get_subs_slice(slice));
|
let f = move |(label, slice): (_, SubsSlice<Variable>)| (label, subs.get_subs_slice(slice));
|
||||||
|
|
||||||
|
|
@ -2715,7 +2716,8 @@ impl UnionTags {
|
||||||
subs: &'a Subs,
|
subs: &'a Subs,
|
||||||
ext: Variable,
|
ext: Variable,
|
||||||
) -> (UnsortedUnionLabels<'a, TagName>, Variable) {
|
) -> (UnsortedUnionLabels<'a, TagName>, Variable) {
|
||||||
let (it, ext) = crate::types::gather_tags_unsorted_iter(subs, *self, ext);
|
let (it, ext) =
|
||||||
|
crate::types::gather_tags_unsorted_iter(subs, *self, ext).expect("not a tag union");
|
||||||
let f = move |(label, slice): (_, SubsSlice<Variable>)| (label, subs.get_subs_slice(slice));
|
let f = move |(label, slice): (_, SubsSlice<Variable>)| (label, subs.get_subs_slice(slice));
|
||||||
let it = it.map(f);
|
let it = it.map(f);
|
||||||
|
|
||||||
|
|
@ -2741,7 +2743,8 @@ impl UnionTags {
|
||||||
ext,
|
ext,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let union_structure = crate::types::gather_tags(subs, *self, ext);
|
let union_structure =
|
||||||
|
crate::types::gather_tags(subs, *self, ext).expect("not a tag union");
|
||||||
|
|
||||||
(
|
(
|
||||||
Box::new(union_structure.fields.into_iter()),
|
Box::new(union_structure.fields.into_iter()),
|
||||||
|
|
@ -2767,7 +2770,8 @@ impl UnionTags {
|
||||||
ext,
|
ext,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let (fields, ext) = crate::types::gather_tags_slices(subs, *self, ext);
|
let (fields, ext) =
|
||||||
|
crate::types::gather_tags_slices(subs, *self, ext).expect("not a tag union");
|
||||||
|
|
||||||
(Box::new(fields.into_iter()), ext)
|
(Box::new(fields.into_iter()), ext)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2674,14 +2674,28 @@ pub fn gather_fields(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GatherTagsError {
|
||||||
|
NotATagUnion(Variable),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gathers tag payloads of a type, assuming it is a tag.
|
||||||
|
///
|
||||||
|
/// If the given type is unbound or an error, no payloads are returned.
|
||||||
|
///
|
||||||
|
/// If the given type cannot be seen as a tag, unbound type, or error, this
|
||||||
|
/// function returns an error.
|
||||||
pub fn gather_tags_unsorted_iter(
|
pub fn gather_tags_unsorted_iter(
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
other_fields: UnionTags,
|
other_fields: UnionTags,
|
||||||
mut var: Variable,
|
mut var: Variable,
|
||||||
) -> (
|
) -> Result<
|
||||||
|
(
|
||||||
impl Iterator<Item = (&TagName, VariableSubsSlice)> + '_,
|
impl Iterator<Item = (&TagName, VariableSubsSlice)> + '_,
|
||||||
Variable,
|
Variable,
|
||||||
) {
|
),
|
||||||
|
GatherTagsError,
|
||||||
|
> {
|
||||||
use crate::subs::Content::*;
|
use crate::subs::Content::*;
|
||||||
use crate::subs::FlatType::*;
|
use crate::subs::FlatType::*;
|
||||||
|
|
||||||
|
|
@ -2711,20 +2725,18 @@ pub fn gather_tags_unsorted_iter(
|
||||||
}
|
}
|
||||||
|
|
||||||
Alias(_, _, actual_var, _) => {
|
Alias(_, _, actual_var, _) => {
|
||||||
// TODO according to elm/compiler: "TODO may be dropping useful alias info here"
|
|
||||||
var = *actual_var;
|
var = *actual_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
Structure(EmptyTagUnion) => break,
|
Structure(EmptyTagUnion) => break,
|
||||||
FlexVar(_) => break,
|
FlexVar(_) => break,
|
||||||
|
|
||||||
// TODO investigate this likely can happen when there is a type error
|
// TODO investigate, this likely can happen when there is a type error
|
||||||
RigidVar(_) => break,
|
RigidVar(_) => break,
|
||||||
|
|
||||||
other => unreachable!(
|
Error => break,
|
||||||
"something weird ended up in a tag union type: {:?} at {:?}",
|
|
||||||
other, var
|
_ => return Err(GatherTagsError::NotATagUnion(var)),
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2738,15 +2750,15 @@ pub fn gather_tags_unsorted_iter(
|
||||||
(tag_name, subs_slice)
|
(tag_name, subs_slice)
|
||||||
});
|
});
|
||||||
|
|
||||||
(it, var)
|
Ok((it, var))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_tags_slices(
|
pub fn gather_tags_slices(
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
other_fields: UnionTags,
|
other_fields: UnionTags,
|
||||||
var: Variable,
|
var: Variable,
|
||||||
) -> (Vec<(TagName, VariableSubsSlice)>, Variable) {
|
) -> Result<(Vec<(TagName, VariableSubsSlice)>, Variable), GatherTagsError> {
|
||||||
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, var);
|
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, var)?;
|
||||||
|
|
||||||
let mut result: Vec<_> = it
|
let mut result: Vec<_> = it
|
||||||
.map(|(ref_label, field): (_, VariableSubsSlice)| (ref_label.clone(), field))
|
.map(|(ref_label, field): (_, VariableSubsSlice)| (ref_label.clone(), field))
|
||||||
|
|
@ -2754,11 +2766,15 @@ pub fn gather_tags_slices(
|
||||||
|
|
||||||
result.sort_by(|(a, _), (b, _)| a.cmp(b));
|
result.sort_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
|
||||||
(result, ext)
|
Ok((result, ext))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_tags(subs: &Subs, other_fields: UnionTags, var: Variable) -> TagUnionStructure {
|
pub fn gather_tags(
|
||||||
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, var);
|
subs: &Subs,
|
||||||
|
other_fields: UnionTags,
|
||||||
|
var: Variable,
|
||||||
|
) -> Result<TagUnionStructure, GatherTagsError> {
|
||||||
|
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, var)?;
|
||||||
|
|
||||||
let mut result: Vec<_> = it
|
let mut result: Vec<_> = it
|
||||||
.map(|(ref_label, field): (_, VariableSubsSlice)| {
|
.map(|(ref_label, field): (_, VariableSubsSlice)| {
|
||||||
|
|
@ -2768,10 +2784,10 @@ pub fn gather_tags(subs: &Subs, other_fields: UnionTags, var: Variable) -> TagUn
|
||||||
|
|
||||||
result.sort_by(|(a, _), (b, _)| a.cmp(b));
|
result.sort_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
|
||||||
TagUnionStructure {
|
Ok(TagUnionStructure {
|
||||||
fields: result,
|
fields: result,
|
||||||
ext,
|
ext,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instantiate_lambda_sets_as_unspecialized(
|
fn instantiate_lambda_sets_as_unspecialized(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue