Skip to content

Commit

Permalink
Make unit enums work
Browse files Browse the repository at this point in the history
  • Loading branch information
Rigidity committed Jun 25, 2024
1 parent 4a2d6ae commit 033835f
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 71 deletions.
48 changes: 25 additions & 23 deletions crates/rue-compiler/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ impl<'a> Compiler<'a> {
})
.collect();

format!("{{ {} }}", fields.join(", "))
format!("{{{}}}", fields.join(", "))
} else {
self.type_name_visitor(struct_type.original_type_id, stack)
}
Expand All @@ -173,29 +173,31 @@ impl<'a> Compiler<'a> {
Type::EnumVariant(enum_variant) => {
let enum_name = self.type_name_visitor(enum_variant.enum_type, stack);

let fields: Vec<String> = enum_variant
.fields
.iter()
.map(|(name, ty)| format!("{}: {}", name, self.type_name_visitor(*ty, stack)))
.collect();
let fields: Option<Vec<String>> = enum_variant.fields.as_ref().map(|fields| {
fields
.iter()
.map(|(name, ty)| {
format!("{}: {}", name, self.type_name_visitor(*ty, stack))
})
.collect()
});

format!(
"{}::{} {{ {} }}",
enum_name,
match self.db.ty(enum_variant.enum_type) {
Type::Enum(enum_type) => {
enum_type
.variants
.iter()
.find(|item| *item.1 == enum_variant.original_type_id)
.expect("enum type is missing variant")
.0
.clone()
}
_ => unreachable!(),
},
fields.join(", ")
)
let variant_name = match self.db.ty(enum_variant.enum_type) {
Type::Enum(enum_type) => enum_type
.variants
.iter()
.find(|item| *item.1 == enum_variant.original_type_id)
.expect("enum type is missing variant")
.0
.clone(),
_ => unreachable!(),
};

if let Some(fields) = fields {
format!("{enum_name}::{variant_name} {{{}}}", fields.join(", "))
} else {
format!("{enum_name}::{variant_name}")
}
}
Type::Function(function_type) => {
let params: Vec<String> = function_type
Expand Down
12 changes: 5 additions & 7 deletions crates/rue-compiler/src/compiler/expr/field_access_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,20 @@ impl Compiler<'_> {
}
}
Type::EnumVariant(variant_type) => {
if let Some((index, _, &field_type)) =
variant_type.fields.get_full(field_name.text())
{
let fields = variant_type.fields.unwrap_or_default();

if let Some((index, _, &field_type)) = fields.get_full(field_name.text()) {
let mut type_id = field_type;

if index == variant_type.fields.len() - 1 && variant_type.rest == Rest::Optional
{
if index == fields.len() - 1 && variant_type.rest == Rest::Optional {
type_id = self.db.alloc_type(Type::PossiblyUndefined(type_id));
}

Value::new(
self.compile_index(
old_value.hir_id,
index,
index == variant_type.fields.len() - 1
&& variant_type.rest == Rest::Spread,
index == fields.len() - 1 && variant_type.rest == Rest::Spread,
),
type_id,
)
Expand Down
38 changes: 23 additions & 15 deletions crates/rue-compiler/src/compiler/expr/initializer_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,29 @@ impl Compiler<'_> {
}
}
Some(Type::EnumVariant(enum_variant)) => {
let fields_hir_id = self.compile_initializer_fields(
ty.unwrap(),
&enum_variant.fields,
enum_variant.rest,
initializer.fields(),
initializer.syntax().text_range(),
);

let hir_id = self
.db
.alloc_hir(Hir::Pair(enum_variant.discriminant, fields_hir_id));

match ty {
Some(struct_type) => Value::new(hir_id, struct_type),
None => self.unknown(),
if let Some(fields) = enum_variant.fields {
let fields_hir_id = self.compile_initializer_fields(
ty.unwrap(),
&fields,
enum_variant.rest,
initializer.fields(),
initializer.syntax().text_range(),
);

let hir_id = self
.db
.alloc_hir(Hir::Pair(enum_variant.discriminant, fields_hir_id));

match ty {
Some(struct_type) => Value::new(hir_id, struct_type),
None => self.unknown(),
}
} else {
self.db.error(
ErrorKind::EnumVariantWithoutFields,
initializer.path().unwrap().syntax().text_range(),
);
self.unknown()
}
}
Some(_) => {
Expand Down
7 changes: 1 addition & 6 deletions crates/rue-compiler/src/compiler/expr/path_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,9 @@ impl Compiler<'_> {
PathItem::Symbol(symbol_id) => symbol_id,
PathItem::Type(type_id) => {
if let Type::EnumVariant(variant_type) = self.db.ty(type_id).clone() {
let Type::Enum(enum_type) = self.db.ty(variant_type.enum_type) else {
unreachable!();
};

if enum_type.has_fields {
if variant_type.fields.is_some() {
self.db.error(ErrorKind::EnumVariantWithFields, text_range);
}

return Value::new(variant_type.discriminant, type_id);
}
self.db.error(ErrorKind::ExpectedSymbolPath, text_range);
Expand Down
6 changes: 5 additions & 1 deletion crates/rue-compiler/src/compiler/item/enum_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,11 @@ impl Compiler<'_> {
*self.db.ty_mut(variant_type_id) = Type::EnumVariant(EnumVariantType {
enum_type: enum_type_id,
original_type_id: variant_type_id,
fields,
fields: if variant.fields().is_some() {
Some(fields)
} else {
None
},
rest,
discriminant,
});
Expand Down
23 changes: 12 additions & 11 deletions crates/rue-compiler/src/database/type_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,17 @@ impl Database {
let new_variant = EnumVariantType {
enum_type: enum_variant.enum_type,
original_type_id: enum_variant.original_type_id,
fields: enum_variant
.fields
.iter()
.map(|(k, v)| {
(
k.clone(),
self.substitute_type_visitor(*v, substitutions, visited),
)
})
.collect(),
fields: enum_variant.fields.as_ref().map(|fields| {
fields
.iter()
.map(|(k, v)| {
(
k.clone(),
self.substitute_type_visitor(*v, substitutions, visited),
)
})
.collect()
}),
rest: enum_variant.rest,
discriminant: enum_variant.discriminant,
};
Expand Down Expand Up @@ -755,7 +756,7 @@ mod tests {
*db.ty_mut(variant) = Type::EnumVariant(EnumVariantType {
enum_type,
original_type_id: variant,
fields: fields(&[ty.int]),
fields: Some(fields(&[ty.int])),
discriminant: ty.unknown_hir,
rest: Rest::Nil,
});
Expand Down
5 changes: 4 additions & 1 deletion crates/rue-compiler/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,12 @@ pub enum ErrorKind {
#[error("enum discriminant too large")]
EnumDiscriminantTooLarge,

#[error("cannot reference enum variants of enums with fields")]
#[error("cannot directly reference enum variants with fields")]
EnumVariantWithFields,

#[error("cannot initialize enum variants without fields")]
EnumVariantWithoutFields,

#[error("unknown enum variant `{0}`")]
UnknownEnumVariant(String),

Expand Down
2 changes: 1 addition & 1 deletion crates/rue-compiler/src/value/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub struct EnumType {
pub struct EnumVariantType {
pub enum_type: TypeId,
pub original_type_id: TypeId,
pub fields: IndexMap<String, TypeId>,
pub fields: Option<IndexMap<String, TypeId>>,
pub rest: Rest,
pub discriminant: HirId,
}
Expand Down
10 changes: 4 additions & 6 deletions std/stdlib.rue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

export enum Condition {
Remark = 1 {
// TODO: Optional value
value?: Any,
},
AggSigParent = 43 {
public_key: PublicKey,
Expand Down Expand Up @@ -38,7 +38,7 @@ export enum Condition {
CreateCoin = 51 {
puzzle_hash: Bytes32,
amount: Int,
// TODO: Optional memos
memos?: Bytes[],
},
ReserveFee = 52 {
amount: Int,
Expand Down Expand Up @@ -79,9 +79,7 @@ export enum Condition {
AssertMyBirthHeight = 75 {
height: Int,
},
AssertEphemeral = 76 {
// TODO: Unit variants and enum repr
},
AssertEphemeral = 76,
AssertSecondsRelative = 80 {
seconds: Int,
},
Expand All @@ -108,7 +106,7 @@ export enum Condition {
},
Softfork = 90 {
cost: Int,
// TODO: Rest args with type `Any`
value?: Any,
},
}

Expand Down
10 changes: 10 additions & 0 deletions tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -364,3 +364,13 @@ input = "()"
output = "()"
hash = "42840c6aebec47ce2e01629ce381b461c19695264281a7b1aab5d4ff54506775"
error = "()"

[unit_variant]
parser_errors = []
compiler_errors = [
"unused let binding `non_unit` at 7:9",
"unused let binding `unit` at 8:9",
"unused enum variant `NonUnit` at 2:5",
"unused enum variant `Unit` at 3:5",
"unused enum `Enum` at 1:6",
]
10 changes: 10 additions & 0 deletions tests/types/unit_variant.rue
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
enum Enum {
NonUnit {},
Unit,
}

fun main() -> Int {
let non_unit = Enum::NonUnit {};
let unit = Enum::Unit;
0
}

0 comments on commit 033835f

Please sign in to comment.