Skip to content

Commit

Permalink
feat(frontend): add support for union types
Browse files Browse the repository at this point in the history
  • Loading branch information
W95Psp committed Oct 14, 2024
1 parent c547a6b commit 8e81a9d
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 44 deletions.
10 changes: 5 additions & 5 deletions engine/lib/concrete_ident/concrete_ident.ml
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,9 @@ module View = struct
last.data |> Imported.of_def_path_item |> string_of_def_path_item
|> Option.map ~f:escape
in
let arity0 ty =
let arity0 (ty : Types.ty) =
match ty.Types.kind with
| Types.Bool -> Some "bool"
| Bool -> Some "bool"
| Char -> Some "char"
| Str -> Some "str"
| Never -> Some "never"
Expand All @@ -310,9 +310,9 @@ module View = struct
| _ -> None
in
let apply left right = left ^ "_of_" ^ right in
let rec arity1 ty =
match ty.Types.kind with
| Types.Slice sub -> arity1 sub |> Option.map ~f:(apply "slice")
let rec arity1 (ty : Types.ty) =
match ty.kind with
| Slice sub -> arity1 sub |> Option.map ~f:(apply "slice")
| Ref (_, sub, _) -> arity1 sub |> Option.map ~f:(apply "ref")
| Adt { def_id; generic_args = [ Type arg ]; _ } ->
let* adt = adt def_id in
Expand Down
44 changes: 23 additions & 21 deletions engine/lib/import_thir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -679,9 +679,15 @@ end) : EXPR = struct
(U.make_tuple_expr' ~span @@ List.map ~f:c_expr fields).e
| Array { fields } -> Array (List.map ~f:c_expr fields)
| Adt { info; base; fields; _ } ->
let constructor =
def_id (Constructor { is_struct = info.typ_is_struct }) info.variant
let is_struct, is_record =
match info.kind with
| Struct { named } -> (true, named)
| Enum { named; _ } -> (false, named)
| Union ->
unimplemented ~issue_id:998 [ e.span ]
"Construct union types: not supported"
in
let constructor = def_id (Constructor { is_struct }) info.variant in
let base =
Option.map
~f:(fun base -> (c_expr base.base, W.construct_base))
Expand All @@ -695,14 +701,7 @@ end) : EXPR = struct
(field, value))
fields
in
Construct
{
is_record = info.variant_is_record;
is_struct = info.typ_is_struct;
constructor;
fields;
base;
}
Construct { is_record; is_struct; constructor; fields; base }
| Literal { lit; neg; _ } -> (
match c_lit e.span neg lit typ with
| EL_Lit lit -> Literal lit
Expand Down Expand Up @@ -873,17 +872,17 @@ end) : EXPR = struct
let var = local_ident Expr var in
PBinding { mut; mode; var; typ; subpat }
| Variant { info; subpatterns; _ } ->
let name =
def_id (Constructor { is_struct = info.typ_is_struct }) info.variant
let is_struct, is_record =
match info.kind with
| Struct { named } -> (true, named)
| Enum { named; _ } -> (false, named)
| Union ->
unimplemented ~issue_id:998 [ pat.span ]
"Pattern match on union types: not supported"
in
let name = def_id (Constructor { is_struct }) info.variant in
let args = List.map ~f:(c_field_pat info) subpatterns in
PConstruct
{
name;
args;
is_record = info.variant_is_record;
is_struct = info.typ_is_struct;
}
PConstruct { name; args; is_record; is_struct }
| Tuple { subpatterns } ->
(List.map ~f:c_pat subpatterns |> U.make_tuple_pat').p
| Deref { subpattern } ->
Expand Down Expand Up @@ -1519,7 +1518,8 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list =
~f:
(fun ({ data; def_id = variant_id; attributes; _ } as original) ->
let is_record =
[%matches? Types.Struct { fields = _ :: _; _ }] data
[%matches? (Struct { fields = _ :: _; _ } : Types.variant_data)]
data
in
let name = Concrete_ident.of_def_id kind variant_id in
let arguments =
Expand Down Expand Up @@ -1757,8 +1757,10 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list =
}
in
[ { span; v; ident = Concrete_ident.of_def_id Value def_id; attrs } ]
| Union _ ->
unimplemented ~issue_id:998 [ item.span ] "Union types: not supported"
| ExternCrate _ | Static _ | Macro _ | Mod _ | ForeignMod _ | GlobalAsm _
| OpaqueTy _ | Union _ | TraitAlias _ ->
| OpaqueTy _ | TraitAlias _ ->
mk NotImplementedYet

let import_item ~drop_body (item : Thir.item) :
Expand Down
20 changes: 13 additions & 7 deletions frontend/exporter/src/rustc_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,28 @@ pub(crate) fn get_variant_information<'s, S: UnderOwnerState<'s>>(
variant_index: rustc_target::abi::VariantIdx,
s: &S,
) -> VariantInformations {
fn is_record<'s, I: std::iter::Iterator<Item = &'s ty::FieldDef> + Clone>(it: I) -> bool {
s_assert!(s, !adt_def.is_union() || *CORE_EXTRACTION_MODE);
fn is_named<'s, I: std::iter::Iterator<Item = &'s ty::FieldDef> + Clone>(it: I) -> bool {
it.clone()
.any(|field| field.name.to_ident_string().parse::<u64>().is_err())
}
let variant_def = adt_def.variant(variant_index);
let variant = variant_def.def_id;
let constructs_type: DefId = adt_def.did().sinto(s);
let kind = if adt_def.is_struct() {
let named = is_named(adt_def.all_fields());
VariantKind::Struct { named }
} else if adt_def.is_union() {
VariantKind::Union
} else {
let named = is_named(variant_def.fields.iter());
let index = variant_index.into();
VariantKind::Enum { index, named }
};
VariantInformations {
typ: constructs_type.clone(),
variant: variant.sinto(s),
variant_index: variant_index.into(),

typ_is_record: adt_def.is_struct() && is_record(adt_def.all_fields()),
variant_is_record: is_record(variant_def.fields.iter()),
typ_is_struct: adt_def.is_struct(),

kind,
type_namespace: DefId {
path: match constructs_type.path.as_slice() {
[init @ .., _] => init.to_vec(),
Expand Down
32 changes: 21 additions & 11 deletions frontend/exporter/src/types/copied.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2075,6 +2075,26 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, AdtDef> for rustc_middle::ty::AdtD
}
}

/// Describe the kind of a variant
#[derive_group(Serializers)]
#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum VariantKind {
/// The variant is the only variant of a `struct` type
Struct {
/// Are the fields on this struct all named?
named: bool,
},
/// The variant is the only variant of a `union` type
Union,
/// The variant is one of the many variants of a `enum` type
Enum {
/// The index of this variant in the `enum`
index: VariantIdx,
/// Are the fields on this struct all named?
named: bool,
},
}

/// Describe a variant
#[derive_group(Serializers)]
#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)]
Expand All @@ -2083,17 +2103,7 @@ pub struct VariantInformations {

pub typ: DefId,
pub variant: DefId,
pub variant_index: VariantIdx,

/// A record type is a type with only one variant which is a
/// record variant.
pub typ_is_record: bool,
/// A record variant is a variant whose fields are named, a record
/// variant always has at least one field.
pub variant_is_record: bool,
/// A struct is a type with exactly one variant. Note that one
/// variant is named exactly as the type.
pub typ_is_struct: bool,
pub kind: VariantKind,
}

/// Reflects [`rustc_middle::thir::PatKind`]
Expand Down

0 comments on commit 8e81a9d

Please sign in to comment.