mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Add RocTagUnion::SingleTagUnion
This commit is contained in:
parent
e9966e6551
commit
314d7a7952
2 changed files with 107 additions and 22 deletions
|
@ -148,27 +148,15 @@ fn add_type(target_info: TargetInfo, id: TypeId, types: &Types, impls: &mut Impl
|
|||
}
|
||||
RocType::TagUnion(tag_union) => {
|
||||
match tag_union {
|
||||
RocTagUnion::Enumeration { tags, name, size } => {
|
||||
if tags.len() == 1 {
|
||||
// An enumeration with one tag is a zero-sized unit type, so
|
||||
// represent it as a zero-sized struct (e.g. "struct Foo()").
|
||||
let derive = derive_str(types.get_type(id), types, true);
|
||||
let struct_name = type_name(id, types);
|
||||
let body = format!("{derive}\nstruct {struct_name}();");
|
||||
|
||||
add_decl(impls, None, target_info, body);
|
||||
} else {
|
||||
add_enumeration(
|
||||
name,
|
||||
target_info,
|
||||
types.get_type(id),
|
||||
tags.iter(),
|
||||
*size,
|
||||
types,
|
||||
impls,
|
||||
)
|
||||
}
|
||||
}
|
||||
RocTagUnion::Enumeration { tags, name, size } => add_enumeration(
|
||||
name,
|
||||
target_info,
|
||||
types.get_type(id),
|
||||
tags.iter(),
|
||||
*size,
|
||||
types,
|
||||
impls,
|
||||
),
|
||||
RocTagUnion::NonRecursive {
|
||||
tags,
|
||||
name,
|
||||
|
@ -236,6 +224,75 @@ fn add_type(target_info: TargetInfo, id: TypeId, types: &Types, impls: &mut Impl
|
|||
RocTagUnion::NonNullableUnwrapped { .. } => {
|
||||
todo!();
|
||||
}
|
||||
RocTagUnion::SingleTagUnion { name, tag_name } => {
|
||||
// An enumeration with one tag is a zero-sized unit type, so
|
||||
// represent it as a zero-sized struct (e.g. "struct Foo()").
|
||||
let derive = derive_str(
|
||||
&RocType::Struct {
|
||||
// Deriving doesn't depend on the struct's name,
|
||||
// so no need to clone name here.
|
||||
name: String::new(),
|
||||
fields: Vec::new(),
|
||||
},
|
||||
types,
|
||||
false,
|
||||
);
|
||||
let body = format!("{derive}\npub struct {name}();");
|
||||
|
||||
add_decl(impls, None, target_info, body);
|
||||
|
||||
let opt_impl = Some(format!("impl {name}"));
|
||||
|
||||
add_decl(
|
||||
impls,
|
||||
opt_impl.clone(),
|
||||
target_info,
|
||||
format!(
|
||||
r#"/// A tag named {tag_name}, which has no payload.
|
||||
pub const {tag_name}: Self = Self();"#,
|
||||
),
|
||||
);
|
||||
|
||||
add_decl(
|
||||
impls,
|
||||
opt_impl.clone(),
|
||||
target_info,
|
||||
format!(
|
||||
r#"/// Other `into_` methods return a payload, but since the {tag_name} tag
|
||||
/// has no payload, this does nothing and is only here for completeness.
|
||||
pub fn into_{tag_name}(self) {{
|
||||
()
|
||||
}}"#,
|
||||
),
|
||||
);
|
||||
|
||||
add_decl(
|
||||
impls,
|
||||
opt_impl.clone(),
|
||||
target_info,
|
||||
format!(
|
||||
r#"/// Other `as` methods return a payload, but since the {tag_name} tag
|
||||
/// has no payload, this does nothing and is only here for completeness.
|
||||
pub unsafe fn as_{tag_name}(&self) {{
|
||||
()
|
||||
}}"#,
|
||||
),
|
||||
);
|
||||
|
||||
// The Debug impl for the single-tag union
|
||||
{
|
||||
let opt_impl = Some(format!("impl core::fmt::Debug for {name}"));
|
||||
let buf = format!(
|
||||
r#"fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {{
|
||||
f.write_str("{name}::")?;
|
||||
|
||||
f.write_str("{tag_name}")
|
||||
}}"#
|
||||
);
|
||||
|
||||
add_decl(impls, opt_impl, target_info, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// These types don't need to be declared in Rust.
|
||||
|
@ -1294,6 +1351,7 @@ fn type_name(id: TypeId, types: &Types) -> String {
|
|||
RocType::Struct { name, .. }
|
||||
| RocType::TagUnionPayload { name, .. }
|
||||
| RocType::TagUnion(RocTagUnion::NonRecursive { name, .. })
|
||||
| RocType::TagUnion(RocTagUnion::SingleTagUnion { name, .. })
|
||||
| RocType::TagUnion(RocTagUnion::Recursive { name, .. })
|
||||
| RocType::TagUnion(RocTagUnion::Enumeration { name, .. })
|
||||
| RocType::TagUnion(RocTagUnion::NullableWrapped { name, .. })
|
||||
|
@ -1909,6 +1967,7 @@ fn cannot_derive_copy(roc_type: &RocType, types: &Types) -> bool {
|
|||
| RocType::Bool
|
||||
| RocType::Num(_)
|
||||
| RocType::TagUnion(RocTagUnion::Enumeration { .. })
|
||||
| RocType::TagUnion(RocTagUnion::SingleTagUnion { .. })
|
||||
| RocType::Function { .. } => false,
|
||||
RocType::RocStr
|
||||
| RocType::RocList(_)
|
||||
|
@ -1960,6 +2019,7 @@ fn has_float_help(roc_type: &RocType, types: &Types, do_not_recurse: &[TypeId])
|
|||
| RocType::RocStr
|
||||
| RocType::Bool
|
||||
| RocType::TagUnion(RocTagUnion::Enumeration { .. })
|
||||
| RocType::TagUnion(RocTagUnion::SingleTagUnion { .. })
|
||||
| RocType::Function { .. } => false,
|
||||
RocType::RocList(id) | RocType::RocSet(id) | RocType::RocBox(id) => {
|
||||
has_float_help(types.get_type(*id), types, do_not_recurse)
|
||||
|
|
|
@ -85,6 +85,14 @@ impl Types {
|
|||
use RocTagUnion::*;
|
||||
|
||||
match (union_a, union_b) {
|
||||
(
|
||||
SingleTagUnion {
|
||||
tag_name: tag_a, ..
|
||||
},
|
||||
SingleTagUnion {
|
||||
tag_name: tag_b, ..
|
||||
},
|
||||
) => tag_a == tag_b,
|
||||
(Enumeration { tags: tags_a, .. }, Enumeration { tags: tags_b, .. }) => {
|
||||
tags_a == tags_b
|
||||
}
|
||||
|
@ -199,7 +207,9 @@ impl Types {
|
|||
}
|
||||
// These are all listed explicitly so that if we ever add a new variant,
|
||||
// we'll get an exhaustiveness error here.
|
||||
(Enumeration { .. }, _)
|
||||
(SingleTagUnion { .. }, _)
|
||||
| (_, SingleTagUnion { .. })
|
||||
| (Enumeration { .. }, _)
|
||||
| (_, Enumeration { .. })
|
||||
| (NonRecursive { .. }, _)
|
||||
| (_, NonRecursive { .. })
|
||||
|
@ -515,6 +525,10 @@ pub enum RocTagUnion {
|
|||
tags: Vec<String>,
|
||||
size: u32,
|
||||
},
|
||||
SingleTagUnion {
|
||||
name: String,
|
||||
tag_name: String,
|
||||
},
|
||||
/// A non-recursive tag union
|
||||
/// e.g. `Result a e : [Ok a, Err e]`
|
||||
NonRecursive {
|
||||
|
@ -1109,6 +1123,17 @@ fn add_tag_union<'a>(
|
|||
tags: tags.into_iter().map(|(tag_name, _)| tag_name).collect(),
|
||||
size: int_width.stack_size(),
|
||||
},
|
||||
Layout::Struct { field_layouts, .. } if field_layouts.is_empty() => {
|
||||
// This should be a single-tag union.
|
||||
debug_assert_eq!(tags.len(), 1);
|
||||
|
||||
let (tag_name, _) = tags.pop().unwrap();
|
||||
|
||||
RocTagUnion::SingleTagUnion {
|
||||
name: name.clone(),
|
||||
tag_name,
|
||||
}
|
||||
}
|
||||
Layout::Builtin(_)
|
||||
| Layout::Struct { .. }
|
||||
| Layout::Boxed(_)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue