Skip to content

Commit 1fd4b08

Browse files
committed
transpile: Translate EnumConstant with associated constants
1 parent 0b1c443 commit 1fd4b08

8 files changed

Lines changed: 202 additions & 135 deletions

File tree

c2rust-ast-builder/src/builder.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,6 +1373,26 @@ impl Builder {
13731373
}))
13741374
}
13751375

1376+
pub fn const_impl_item<I>(self, name: I, ty: Box<Type>, init: Box<Expr>) -> ImplItem
1377+
where
1378+
I: Make<Ident>,
1379+
{
1380+
let name = name.make(&self);
1381+
ImplItem::Const(ImplItemConst {
1382+
attrs: self.attrs,
1383+
vis: self.vis,
1384+
defaultness: None,
1385+
const_token: Token![const](self.span),
1386+
ident: name,
1387+
generics: self.generics,
1388+
colon_token: Token![:](self.span),
1389+
ty: *ty,
1390+
eq_token: Token![=](self.span),
1391+
expr: *init,
1392+
semi_token: Token![;](self.span),
1393+
})
1394+
}
1395+
13761396
pub fn fn_item<S>(self, sig: S, block: Block) -> Box<Item>
13771397
where
13781398
S: Make<Signature>,

c2rust-transpile/src/translator/enums.rs

Lines changed: 82 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use c2rust_ast_builder::mk;
22
use proc_macro2::Span;
3-
use syn::Expr;
3+
use syn::{Expr, ImplItem};
44

55
use crate::{
6-
c_ast,
6+
c_ast::{self, iterators::SomeId},
77
diagnostics::TranslationResult,
88
translator::{signed_int_expr, ConvertedDecl, ExprContext, Translation},
99
with_stmts::WithStmts,
@@ -17,6 +17,7 @@ impl<'c> Translation<'c> {
1717
enum_id: CEnumId,
1818
span: Span,
1919
integral_type: CQualTypeId,
20+
variants: &[CEnumConstantId],
2021
) -> TranslationResult<ConvertedDecl> {
2122
let enum_name = &self
2223
.type_converter
@@ -34,43 +35,61 @@ impl<'c> Translation<'c> {
3435
.pub_()
3536
.struct_item(enum_name, vec![field], true);
3637

37-
Ok(ConvertedDecl::Item(item))
38-
}
38+
if variants.is_empty() {
39+
return Ok(ConvertedDecl::Item(item));
40+
}
3941

40-
pub fn convert_enum_constant(
41-
&self,
42-
enum_constant_id: CEnumConstantId,
43-
span: Span,
44-
value: ConstIntExpr,
45-
) -> TranslationResult<ConvertedDecl> {
46-
let name = self
47-
.renamer
48-
.borrow_mut()
49-
.get(&enum_constant_id)
50-
.expect("Enum constant not named");
51-
let enum_id = self.ast_context.parents[&enum_constant_id];
52-
let enum_name = self
53-
.type_converter
54-
.borrow()
55-
.resolve_decl_name(enum_id)
56-
.expect("Enums should already be renamed");
42+
let self_ty = mk().ident_ty("Self");
43+
let constants: Vec<ImplItem> = variants
44+
.iter()
45+
.map(|&enum_constant_id| {
46+
let span = self
47+
.get_span(SomeId::Decl(enum_constant_id))
48+
.unwrap_or_else(Span::call_site);
5749

58-
let ty = mk().ident_ty(enum_name);
59-
let val = match value {
60-
ConstIntExpr::I(value) => signed_int_expr(value),
61-
ConstIntExpr::U(value) => mk().lit_expr(mk().int_unsuffixed_lit(value as u128)),
62-
};
63-
let init = self.enum_constructor_expr(enum_id, val);
50+
let (name, value) = match self.ast_context[enum_constant_id].kind {
51+
CDeclKind::EnumConstant {
52+
ref name, value, ..
53+
} => (name, value),
54+
_ => panic!("{:?} does not point to an enum variant", enum_constant_id),
55+
};
56+
let name = self.type_converter.borrow_mut().declare_field_name(
57+
enum_id,
58+
enum_constant_id,
59+
name,
60+
);
6461

65-
Ok(ConvertedDecl::Item(
66-
mk().span(span).pub_().const_item(name, ty, init),
67-
))
62+
let val = match value {
63+
ConstIntExpr::I(value) => signed_int_expr(value),
64+
ConstIntExpr::U(value) => mk().lit_expr(mk().int_unsuffixed_lit(value as u128)),
65+
};
66+
let init = self.enum_constructor_expr(enum_id, val, true);
67+
68+
mk().span(span)
69+
.pub_()
70+
.const_impl_item(name, self_ty.clone(), init)
71+
})
72+
.collect();
73+
let impl_block = mk().impl_item(mk().ident_ty(enum_name), constants);
74+
75+
Ok(ConvertedDecl::Items(vec![item, impl_block]))
6876
}
6977

7078
pub fn convert_enum_zero_initializer(&self, enum_id: CEnumId) -> WithStmts<Box<Expr>> {
7179
WithStmts::new_val(self.enum_for_i64(enum_id, 0))
7280
}
7381

82+
/// Translates a `DeclRef` for an `EnumConstant`.
83+
pub fn convert_enum_constant_decl_ref(
84+
&self,
85+
enum_constant_id: CEnumConstantId,
86+
target_cty: CTypeId,
87+
) -> TranslationResult<Box<Expr>> {
88+
let enum_id = self.ast_context.parents[&enum_constant_id];
89+
let val = self.enum_constant_expr(enum_id, enum_constant_id);
90+
self.convert_cast_from_enum(target_cty, val)
91+
}
92+
7493
/// Translate a cast where the source type, but not the target type, is an `enum` type.
7594
pub fn convert_cast_from_enum(
7695
&self,
@@ -116,7 +135,7 @@ impl<'c> Translation<'c> {
116135
// If this DeclRef expanded to a const macro, we actually need to insert a cast,
117136
// because the translation of a const macro skips implicit casts in its context.
118137
if !expr_is_macro {
119-
return Ok(self.enum_constant_expr(enum_constant_id));
138+
return Ok(self.enum_constant_expr(enum_id, enum_constant_id));
120139
}
121140
}
122141

@@ -151,7 +170,7 @@ impl<'c> Translation<'c> {
151170
if needs_cast {
152171
let ty = self.convert_type(integral_type.ctype)?;
153172
val = mk().cast_expr(val, ty);
154-
val = self.enum_constructor_expr(enum_id, val);
173+
val = self.enum_constructor_expr(enum_id, val, false);
155174
}
156175

157176
Ok(val)
@@ -161,7 +180,7 @@ impl<'c> Translation<'c> {
161180
/// variant directly, otherwise it converts a number to the enum type.
162181
fn enum_for_i64(&self, enum_id: CEnumId, value: i64) -> Box<Expr> {
163182
if let Some(enum_constant_id) = self.enum_variant_for_i64(enum_id, value) {
164-
return self.enum_constant_expr(enum_constant_id);
183+
return self.enum_constant_expr(enum_id, enum_constant_id);
165184
}
166185

167186
let underlying_type_id = self.enum_integral_type(enum_id);
@@ -171,7 +190,7 @@ impl<'c> Translation<'c> {
171190
_ => signed_int_expr(value),
172191
};
173192

174-
self.enum_constructor_expr(enum_id, value)
193+
self.enum_constructor_expr(enum_id, value, false)
175194
}
176195

177196
/// Returns the id of the variant of `enum_id` whose value matches `value`, if any.
@@ -201,20 +220,41 @@ impl<'c> Translation<'c> {
201220
variants.contains(&enum_constant_id)
202221
}
203222

204-
fn enum_constructor_expr(&self, enum_id: CEnumId, value: Box<Expr>) -> Box<Expr> {
223+
fn enum_constructor_expr(
224+
&self,
225+
enum_id: CEnumId,
226+
value: Box<Expr>,
227+
use_self_ty: bool,
228+
) -> Box<Expr> {
229+
let func = if use_self_ty {
230+
mk().ident_expr("Self")
231+
} else {
232+
let enum_name = self
233+
.type_converter
234+
.borrow()
235+
.resolve_decl_name(enum_id)
236+
.unwrap();
237+
self.add_import(enum_id, &enum_name);
238+
mk().ident_expr(enum_name)
239+
};
240+
241+
mk().call_expr(func, vec![value])
242+
}
243+
244+
fn enum_constant_expr(&self, enum_id: CEnumId, enum_constant_id: CEnumConstantId) -> Box<Expr> {
205245
let enum_name = self
206246
.type_converter
207247
.borrow()
208248
.resolve_decl_name(enum_id)
209249
.unwrap();
210-
self.add_import(enum_id, &enum_name);
211-
mk().call_expr(mk().ident_expr(enum_name), vec![value])
212-
}
250+
let name = self
251+
.type_converter
252+
.borrow()
253+
.resolve_field_name(Some(enum_id), enum_constant_id)
254+
.unwrap();
213255

214-
fn enum_constant_expr(&self, enum_constant_id: CEnumConstantId) -> Box<Expr> {
215-
let name = self.renamer.borrow().get(&enum_constant_id).unwrap();
216-
self.add_import(enum_constant_id, &name);
217-
mk().ident_expr(name)
256+
self.add_import(enum_id, &enum_name);
257+
mk().path_expr(vec![enum_name, name])
218258
}
219259

220260
fn enum_integral_type(&self, enum_id: CEnumId) -> CQualTypeId {

0 commit comments

Comments
 (0)