mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Merge pull request #3611 from rtfeldman/i3266
Emit runtime error when tag unions have an error type
This commit is contained in:
commit
d55d1b00d9
6 changed files with 80 additions and 31 deletions
|
@ -1084,7 +1084,8 @@ fn type_to_union_tags<'a>(
|
|||
|
||||
let 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.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
|
||||
let mut ext_fields = std::vec::Vec::new();
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2807,7 +2807,8 @@ fn type_to_variable<'a>(
|
|||
subs,
|
||||
UnionTags::default(),
|
||||
temp_ext_var,
|
||||
);
|
||||
)
|
||||
.expect("extension var could not be seen as a tag union");
|
||||
|
||||
for _ in it {
|
||||
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,
|
||||
UnionTags::default(),
|
||||
temp_ext_var,
|
||||
);
|
||||
)
|
||||
.expect("extension var could not be seen as tag union");
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
#[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,
|
||||
ext: Variable,
|
||||
) -> 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));
|
||||
|
||||
|
@ -2715,7 +2716,8 @@ impl UnionTags {
|
|||
subs: &'a Subs,
|
||||
ext: 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 it = it.map(f);
|
||||
|
||||
|
@ -2741,7 +2743,8 @@ impl UnionTags {
|
|||
ext,
|
||||
)
|
||||
} 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()),
|
||||
|
@ -2767,7 +2770,8 @@ impl UnionTags {
|
|||
ext,
|
||||
)
|
||||
} 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)
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
subs: &Subs,
|
||||
other_fields: UnionTags,
|
||||
mut var: Variable,
|
||||
) -> (
|
||||
impl Iterator<Item = (&TagName, VariableSubsSlice)> + '_,
|
||||
Variable,
|
||||
) {
|
||||
) -> Result<
|
||||
(
|
||||
impl Iterator<Item = (&TagName, VariableSubsSlice)> + '_,
|
||||
Variable,
|
||||
),
|
||||
GatherTagsError,
|
||||
> {
|
||||
use crate::subs::Content::*;
|
||||
use crate::subs::FlatType::*;
|
||||
|
||||
|
@ -2697,34 +2711,32 @@ pub fn gather_tags_unsorted_iter(
|
|||
|
||||
Structure(FunctionOrTagUnion(_tag_name_index, _, _sub_ext)) => {
|
||||
todo!("this variant does not use SOA yet, and therefore this case is unreachable right now")
|
||||
// let sub_fields: UnionTags = (*tag_name_index).into();
|
||||
// stack.push(sub_fields);
|
||||
// let sub_fields: UnionTags = (*tag_name_index).into();
|
||||
// stack.push(sub_fields);
|
||||
//
|
||||
// var = *sub_ext;
|
||||
// var = *sub_ext;
|
||||
}
|
||||
|
||||
Structure(RecursiveTagUnion(_, _sub_fields, _sub_ext)) => {
|
||||
todo!("this variant does not use SOA yet, and therefore this case is unreachable right now")
|
||||
// stack.push(*sub_fields);
|
||||
// stack.push(*sub_fields);
|
||||
//
|
||||
// var = *sub_ext;
|
||||
// var = *sub_ext;
|
||||
}
|
||||
|
||||
Alias(_, _, actual_var, _) => {
|
||||
// TODO according to elm/compiler: "TODO may be dropping useful alias info here"
|
||||
var = *actual_var;
|
||||
}
|
||||
|
||||
Structure(EmptyTagUnion) => 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,
|
||||
|
||||
other => unreachable!(
|
||||
"something weird ended up in a tag union type: {:?} at {:?}",
|
||||
other, var
|
||||
),
|
||||
Error => break,
|
||||
|
||||
_ => return Err(GatherTagsError::NotATagUnion(var)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2738,15 +2750,15 @@ pub fn gather_tags_unsorted_iter(
|
|||
(tag_name, subs_slice)
|
||||
});
|
||||
|
||||
(it, var)
|
||||
Ok((it, var))
|
||||
}
|
||||
|
||||
pub fn gather_tags_slices(
|
||||
subs: &Subs,
|
||||
other_fields: UnionTags,
|
||||
var: Variable,
|
||||
) -> (Vec<(TagName, VariableSubsSlice)>, Variable) {
|
||||
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, var);
|
||||
) -> Result<(Vec<(TagName, VariableSubsSlice)>, Variable), GatherTagsError> {
|
||||
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, var)?;
|
||||
|
||||
let mut result: Vec<_> = it
|
||||
.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, ext)
|
||||
Ok((result, ext))
|
||||
}
|
||||
|
||||
pub fn gather_tags(subs: &Subs, other_fields: UnionTags, var: Variable) -> TagUnionStructure {
|
||||
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, var);
|
||||
pub fn gather_tags(
|
||||
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
|
||||
.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));
|
||||
|
||||
TagUnionStructure {
|
||||
Ok(TagUnionStructure {
|
||||
fields: result,
|
||||
ext,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn instantiate_lambda_sets_as_unspecialized(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue