|
| 1 | +use rustc_ast::ast::DUMMY_NODE_ID; |
| 2 | +use rustc_ast::ptr::P; |
| 3 | +use rustc_ast::{ |
| 4 | + AngleBracketedArg, AngleBracketedArgs, AssocItem, AssocItemKind, Const, Defaultness, FnHeader, |
| 5 | + FnRetTy, FnSig, GenericArg, GenericArgs, Generics, ImplPolarity, ItemKind, MetaItem, Path, |
| 6 | + PathSegment, Unsafe, Visibility, VisibilityKind, |
| 7 | +}; |
| 8 | +use rustc_errors::struct_span_err; |
| 9 | +use rustc_expand::base::{Annotatable, ExtCtxt}; |
| 10 | +use rustc_span::symbol::{sym, Ident}; |
| 11 | +use rustc_span::{Span, DUMMY_SP}; |
| 12 | + |
| 13 | +macro_rules! invalid_derive { |
| 14 | + ($cx:ident, $span:ident) => { |
| 15 | + struct_span_err!( |
| 16 | + &$cx.sess.parse_sess.span_diagnostic, |
| 17 | + $span, |
| 18 | + FIXME, |
| 19 | + "`Into` can only be derived for enums with an explicit integer representation" |
| 20 | + ) |
| 21 | + .emit(); |
| 22 | + }; |
| 23 | +} |
| 24 | + |
| 25 | +pub fn expand_deriving_into( |
| 26 | + cx: &mut ExtCtxt<'_>, |
| 27 | + span: Span, |
| 28 | + _mitem: &MetaItem, |
| 29 | + item: &Annotatable, |
| 30 | + push: &mut dyn FnMut(Annotatable), |
| 31 | +) { |
| 32 | + match *item { |
| 33 | + Annotatable::Item(ref annitem) => match annitem.kind { |
| 34 | + ItemKind::Enum(_, _) => { |
| 35 | + let reprs: Vec<_> = annitem |
| 36 | + .attrs |
| 37 | + .iter() |
| 38 | + .filter_map(|attr| { |
| 39 | + for r in rustc_attr::find_repr_attrs(&cx.sess, attr) { |
| 40 | + use rustc_attr::*; |
| 41 | + match r { |
| 42 | + ReprInt(rustc_attr::IntType::UnsignedInt(int_type)) => { |
| 43 | + return Some(int_type.name()); |
| 44 | + } |
| 45 | + ReprInt(rustc_attr::IntType::SignedInt(int_type)) => { |
| 46 | + return Some(int_type.name()); |
| 47 | + } |
| 48 | + ReprC | ReprPacked(..) | ReprSimd | ReprTransparent |
| 49 | + | ReprAlign(..) | ReprNoNiche => {} |
| 50 | + } |
| 51 | + } |
| 52 | + None |
| 53 | + }) |
| 54 | + .collect(); |
| 55 | + if reprs.len() != 1 { |
| 56 | + invalid_derive!(cx, span); |
| 57 | + return; |
| 58 | + } |
| 59 | + |
| 60 | + let repr_ident = Ident { name: reprs[0], span: DUMMY_SP }; |
| 61 | + let repr_ty = cx.ty_ident(DUMMY_SP, repr_ident); |
| 62 | + |
| 63 | + let ty = cx.ty_ident(DUMMY_SP, annitem.ident); |
| 64 | + |
| 65 | + let param_ident = Ident::from_str("value"); |
| 66 | + |
| 67 | + let decl = cx.fn_decl( |
| 68 | + vec![cx.param(DUMMY_SP, param_ident, ty)], |
| 69 | + FnRetTy::Ty(repr_ty.clone()), |
| 70 | + ); |
| 71 | + |
| 72 | + let fn_item = P(AssocItem { |
| 73 | + attrs: vec![cx.attribute(cx.meta_word(span, sym::inline))], |
| 74 | + id: DUMMY_NODE_ID, |
| 75 | + span: DUMMY_SP, |
| 76 | + vis: Visibility { kind: VisibilityKind::Inherited, span, tokens: None }, |
| 77 | + ident: Ident::from_str("from"), |
| 78 | + |
| 79 | + kind: AssocItemKind::Fn( |
| 80 | + Defaultness::Final, |
| 81 | + FnSig { header: FnHeader::default(), decl, span: DUMMY_SP }, |
| 82 | + Generics::default(), |
| 83 | + Some(cx.block_expr(cx.expr_cast( |
| 84 | + DUMMY_SP, |
| 85 | + cx.expr_path(Path::from_ident(param_ident)), |
| 86 | + repr_ty.clone(), |
| 87 | + ))), |
| 88 | + ), |
| 89 | + tokens: None, |
| 90 | + }); |
| 91 | + |
| 92 | + let mut trait_path = Path { |
| 93 | + span: DUMMY_SP, |
| 94 | + segments: cx |
| 95 | + .std_path(&[sym::convert]) |
| 96 | + .into_iter() |
| 97 | + .map(PathSegment::from_ident) |
| 98 | + .collect(), |
| 99 | + tokens: None, |
| 100 | + }; |
| 101 | + trait_path.segments.push(PathSegment { |
| 102 | + ident: Ident { name: sym::From, span: DUMMY_SP }, |
| 103 | + id: DUMMY_NODE_ID, |
| 104 | + args: Some(P(GenericArgs::AngleBracketed(AngleBracketedArgs { |
| 105 | + span: DUMMY_SP, |
| 106 | + args: vec![AngleBracketedArg::Arg(GenericArg::Type( |
| 107 | + cx.ty_ident(DUMMY_SP, annitem.ident), |
| 108 | + ))], |
| 109 | + }))), |
| 110 | + }); |
| 111 | + |
| 112 | + let trait_item = Annotatable::Item(cx.item( |
| 113 | + DUMMY_SP, |
| 114 | + Ident::invalid(), |
| 115 | + Vec::new(), |
| 116 | + ItemKind::Impl { |
| 117 | + unsafety: Unsafe::No, |
| 118 | + polarity: ImplPolarity::Positive, |
| 119 | + defaultness: Defaultness::Final, |
| 120 | + constness: Const::No, |
| 121 | + generics: Generics::default(), |
| 122 | + of_trait: Some(cx.trait_ref(trait_path)), |
| 123 | + self_ty: repr_ty, |
| 124 | + items: vec![fn_item], |
| 125 | + }, |
| 126 | + )); |
| 127 | + |
| 128 | + push(trait_item); |
| 129 | + } |
| 130 | + _ => invalid_derive!(cx, span), |
| 131 | + }, |
| 132 | + _ => invalid_derive!(cx, span), |
| 133 | + } |
| 134 | +} |
0 commit comments