Merge pull request #3535 from rtfeldman/bindgen-unit-result-bool

Bindgen Result, Bool, {}, and []
This commit is contained in:
Richard Feldman 2022-07-17 10:28:32 -04:00 committed by GitHub
commit 19436cc58a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 112 additions and 16 deletions

View file

@ -255,8 +255,11 @@ fn add_type(target_info: TargetInfo, id: TypeId, types: &Types, impls: &mut Impl
}
}
// These types don't need to be declared in Rust.
RocType::Num(_)
RocType::Unit
| RocType::EmptyTagUnion
| RocType::Num(_)
| RocType::Bool
| RocType::RocResult(_, _)
| RocType::RocStr
| RocType::RocDict(_, _)
| RocType::RocSet(_)
@ -609,7 +612,9 @@ pub struct {name} {{
}
match payload_type {
RocType::RocStr
RocType::Unit
| RocType::EmptyTagUnion
| RocType::RocStr
| RocType::Bool
| RocType::Num(_)
| RocType::RocList(_)
@ -617,6 +622,7 @@ pub struct {name} {{
| RocType::RocSet(_)
| RocType::RocBox(_)
| RocType::TagUnion(_)
| RocType::RocResult(_, _)
| RocType::RecursivePointer { .. } => {
owned_ret_type = type_name(*payload_id, types);
borrowed_ret_type = format!("&{}", owned_ret_type);
@ -1100,7 +1106,9 @@ pub struct {name} {{
};
let fields_str = match payload_type {
RocType::RocStr
RocType::Unit
| RocType::EmptyTagUnion
| RocType::RocStr
| RocType::Bool
| RocType::Num(_)
| RocType::RocList(_)
@ -1108,6 +1116,7 @@ pub struct {name} {{
| RocType::RocSet(_)
| RocType::RocBox(_)
| RocType::TagUnion(_)
| RocType::RocResult(_, _)
| RocType::Struct { .. }
| RocType::RecursivePointer { .. } => {
format!(".field({deref_str}{actual_self}.{tag_name})")
@ -1258,6 +1267,8 @@ fn add_struct<S: Display>(
fn type_name(id: TypeId, types: &Types) -> String {
match types.get_type(id) {
RocType::Unit => "()".to_string(),
RocType::EmptyTagUnion => "std::convert::Infallible".to_string(),
RocType::RocStr => "roc_std::RocStr".to_string(),
RocType::Bool => "bool".to_string(),
RocType::Num(RocNum::U8) => "u8".to_string(),
@ -1282,6 +1293,13 @@ fn type_name(id: TypeId, types: &Types) -> String {
RocType::RocSet(elem_id) => format!("roc_std::RocSet<{}>", type_name(*elem_id, types)),
RocType::RocList(elem_id) => format!("roc_std::RocList<{}>", type_name(*elem_id, types)),
RocType::RocBox(elem_id) => format!("roc_std::RocBox<{}>", type_name(*elem_id, types)),
RocType::RocResult(ok_id, err_id) => {
format!(
"roc_std::RocResult<{}, {}>",
type_name(*ok_id, types),
type_name(*err_id, types)
)
}
RocType::Struct { name, .. }
| RocType::TagUnionPayload { name, .. }
| RocType::TagUnion(RocTagUnion::NonRecursive { name, .. })
@ -1398,13 +1416,16 @@ pub struct {name} {{
let borrowed_ret;
match payload_type {
RocType::RocStr
RocType::Unit
| RocType::EmptyTagUnion
| RocType::RocStr
| RocType::Bool
| RocType::Num(_)
| RocType::RocList(_)
| RocType::RocDict(_, _)
| RocType::RocSet(_)
| RocType::RocBox(_)
| RocType::RocResult(_, _)
| RocType::TagUnion(_)
| RocType::RecursivePointer { .. } => {
owned_ret_type = type_name(non_null_payload, types);
@ -1634,13 +1655,16 @@ pub struct {name} {{
let extra_deref = if cannot_derive_copy { "*" } else { "" };
let fields_str = match payload_type {
RocType::RocStr
RocType::Unit
| RocType::EmptyTagUnion
| RocType::RocStr
| RocType::Bool
| RocType::Num(_)
| RocType::RocList(_)
| RocType::RocDict(_, _)
| RocType::RocSet(_)
| RocType::RocBox(_)
| RocType::RocResult(_, _)
| RocType::TagUnion(_)
| RocType::RecursivePointer { .. } => {
format!(
@ -1863,9 +1887,12 @@ fn tag_union_struct_help<'a, I: Iterator<Item = &'a (L, TypeId)>, L: Display + P
fn cannot_derive_default(roc_type: &RocType, types: &Types) -> bool {
match roc_type {
RocType::TagUnion { .. } | RocType::RecursivePointer { .. } | RocType::Function(_, _) => {
true
}
RocType::Unit
| RocType::EmptyTagUnion
| RocType::TagUnion { .. }
| RocType::RocResult(_, _)
| RocType::RecursivePointer { .. }
| RocType::Function(_, _) => true,
RocType::RocStr | RocType::Bool | RocType::Num(_) => false,
RocType::RocList(id) | RocType::RocSet(id) | RocType::RocBox(id) => {
cannot_derive_default(types.get_type(*id), types)
@ -1886,7 +1913,9 @@ fn cannot_derive_default(roc_type: &RocType, types: &Types) -> bool {
/// Useful when determining whether to derive Copy in a Rust type.
fn cannot_derive_copy(roc_type: &RocType, types: &Types) -> bool {
match roc_type {
RocType::Bool
RocType::Unit
| RocType::EmptyTagUnion
| RocType::Bool
| RocType::Num(_)
| RocType::TagUnion(RocTagUnion::Enumeration { .. })
| RocType::Function(_, _) => false,
@ -1907,6 +1936,10 @@ fn cannot_derive_copy(roc_type: &RocType, types: &Types) -> bool {
.any(|id| cannot_derive_copy(types.get_type(*id), types))
})
}
RocType::RocResult(ok_id, err_id) => {
cannot_derive_copy(types.get_type(*ok_id), types)
|| cannot_derive_copy(types.get_type(*err_id), types)
}
RocType::Struct { fields, .. } => fields
.iter()
.any(|(_, type_id)| cannot_derive_copy(types.get_type(*type_id), types)),
@ -1931,13 +1964,19 @@ fn has_float_help(roc_type: &RocType, types: &Types, do_not_recurse: &[TypeId])
I8 | U8 | I16 | U16 | I32 | U32 | I64 | U64 | I128 | U128 | Dec => false,
}
}
RocType::RocStr
RocType::Unit
| RocType::EmptyTagUnion
| RocType::RocStr
| RocType::Bool
| RocType::TagUnion(RocTagUnion::Enumeration { .. })
| RocType::Function(_, _) => false,
RocType::RocList(id) | RocType::RocSet(id) | RocType::RocBox(id) => {
has_float_help(types.get_type(*id), types, do_not_recurse)
}
RocType::RocResult(ok_id, err_id) => {
has_float_help(types.get_type(*ok_id), types, do_not_recurse)
|| has_float_help(types.get_type(*err_id), types, do_not_recurse)
}
RocType::RocDict(key_id, val_id) => {
has_float_help(types.get_type(*key_id), types, do_not_recurse)
|| has_float_help(types.get_type(*val_id), types, do_not_recurse)

View file

@ -26,6 +26,9 @@ impl TypeId {
/// have *some* TypeId value until we later in the process determine
/// their real TypeId and can go back and fix them up.
pub(crate) const PENDING: Self = Self(usize::MAX);
/// When adding, we check for overflow based on whether we've exceeded this.
const MAX: Self = Self(Self::PENDING.0 - 1);
}
#[derive(Debug, Clone)]
@ -56,6 +59,8 @@ impl Types {
pub fn add(&mut self, typ: RocType, layout: Layout<'_>) -> TypeId {
let id = TypeId(self.types.len());
assert!(id.0 <= TypeId::MAX.0);
self.types.push(typ);
self.sizes
.push(layout.stack_size_without_alignment(self.target));
@ -138,12 +143,14 @@ impl Types {
pub enum RocType {
RocStr,
Bool,
RocResult(TypeId, TypeId),
Num(RocNum),
RocList(TypeId),
RocDict(TypeId, TypeId),
RocSet(TypeId),
RocBox(TypeId),
TagUnion(RocTagUnion),
EmptyTagUnion,
Struct {
name: String,
fields: Vec<(String, TypeId)>,
@ -157,6 +164,8 @@ pub enum RocType {
/// and the TypeId is the TypeId of StrConsList itself.
RecursivePointer(TypeId),
Function(Vec<TypeId>, TypeId),
/// A zero-sized type, such as an empty record or a single-tag union with no payload
Unit,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
@ -466,17 +475,65 @@ fn add_type_help<'a>(
todo!()
}
Content::Structure(FlatType::Erroneous(_)) => todo!(),
Content::Structure(FlatType::EmptyRecord) => todo!(),
Content::Structure(FlatType::EmptyTagUnion) => {
// This can happen when unwrapping a tag union; don't do anything.
todo!()
}
Content::Alias(name, _, real_var, _) => {
Content::Structure(FlatType::EmptyRecord) => types.add(RocType::Unit, layout),
Content::Structure(FlatType::EmptyTagUnion) => types.add(RocType::EmptyTagUnion, layout),
Content::Alias(name, alias_vars, real_var, _) => {
if name.is_builtin() {
match layout {
Layout::Builtin(builtin) => {
add_builtin_type(env, builtin, var, opt_name, types, layout)
}
Layout::Union(union_layout) if *name == Symbol::BOOL_BOOL => {
if cfg!(debug_assertions) {
match union_layout {
UnionLayout::NonRecursive(tag_layouts) => {
// Bool should always have exactly two tags: True and False
debug_assert_eq!(tag_layouts.len(), 2);
// Both tags should have no payload
debug_assert_eq!(tag_layouts[0].len(), 0);
debug_assert_eq!(tag_layouts[1].len(), 0);
}
_ => debug_assert!(false),
}
}
types.add(RocType::Bool, layout)
}
Layout::Union(union_layout) if *name == Symbol::RESULT_RESULT => {
match union_layout {
UnionLayout::NonRecursive(tags) => {
// Result should always have exactly two tags: Ok and Err
debug_assert_eq!(tags.len(), 2);
let type_vars =
env.subs.get_subs_slice(alias_vars.type_variables());
let ok_var = type_vars[0];
let ok_layout =
env.layout_cache.from_var(env.arena, ok_var, subs).unwrap();
let ok_id = add_type_help(env, ok_layout, ok_var, None, types);
let err_var = type_vars[1];
let err_layout =
env.layout_cache.from_var(env.arena, err_var, subs).unwrap();
let err_id = add_type_help(env, err_layout, err_var, None, types);
let type_id = types.add(RocType::RocResult(ok_id, err_id), layout);
types.depends(type_id, ok_id);
types.depends(type_id, err_id);
type_id
}
UnionLayout::Recursive(_)
| UnionLayout::NonNullableUnwrapped(_)
| UnionLayout::NullableWrapped { .. }
| UnionLayout::NullableUnwrapped { .. } => {
unreachable!();
}
}
}
_ => {
unreachable!()
}