Add RocTagUnion::SingleTagUnion

This commit is contained in:
Richard Feldman 2022-08-05 13:49:24 -04:00
parent e9966e6551
commit 314d7a7952
No known key found for this signature in database
GPG key ID: 7E4127D1E4241798
2 changed files with 107 additions and 22 deletions

View file

@ -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)