rustc_builtin_macros/deriving/
from.rs1use rustc_ast as ast;
2use rustc_ast::{ItemKind, Safety, VariantData};
3use rustc_errors::MultiSpan;
4use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
5use rustc_span::{Ident, Span, kw, sym};
6use thin_vec::thin_vec;
7
8use crate::deriving::generic::ty::{Bounds, Path, PathKind, Ty};
9use crate::deriving::generic::*;
10use crate::deriving::pathvec;
11use crate::diagnostics;
12
13pub(crate) fn expand_deriving_from(
16 cx: &ExtCtxt<'_>,
17 span: Span,
18 mitem: &ast::MetaItem,
19 annotatable: &Annotatable,
20 push: &mut dyn FnMut(Annotatable),
21 is_const: bool,
22) {
23 let Annotatable::Item(item) = &annotatable else {
24 cx.dcx().bug("derive(From) used on something else than an item");
25 };
26
27 let err_span = || {
28 let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span);
29 MultiSpan::from_spans(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[span, item_span]))vec![span, item_span])
30 };
31
32 let field = match &item.kind {
34 ItemKind::Struct(_, _, data) => {
35 if let [field] = data.fields() {
36 Ok(field.clone())
37 } else {
38 let guar = cx.dcx().emit_err(diagnostics::DeriveFromWrongFieldCount {
39 span: err_span(),
40 multiple_fields: data.fields().len() > 1,
41 });
42 Err(guar)
43 }
44 }
45 ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => {
46 let guar = cx.dcx().emit_err(diagnostics::DeriveFromWrongTarget {
47 span: err_span(),
48 kind: &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} {1}", item.kind.article(),
item.kind.descr()))
})format!("{} {}", item.kind.article(), item.kind.descr()),
49 });
50 Err(guar)
51 }
52 _ => cx.dcx().bug("Invalid derive(From) ADT input"),
53 };
54
55 let from_type = Ty::AstTy(match field {
56 Ok(ref field) => field.ty.clone(),
57 Err(guar) => cx.ty(span, ast::TyKind::Err(guar)),
58 });
59
60 let path =
61 Path::new_({
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[sym::convert, sym::From]))
}pathvec!(convert::From), ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Box::new(from_type.clone())]))vec![Box::new(from_type.clone())], PathKind::Std);
62
63 let from_trait_def = TraitDef {
74 span,
75 path,
76 skip_path_as_bound: true,
77 needs_copy_as_bound_if_packed: false,
78 additional_bounds: SmallVec::new(),
79 supports_unions: false,
80 methods: {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(MethodDef {
name: sym::from,
generics: Bounds { bounds: ::alloc::vec::Vec::new() },
explicit_self: false,
nonself_args: {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push((from_type, sym::value));
vec
} else {
::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(from_type, sym::value)])))
}
},
ret_ty: Ty::Self_,
attributes: {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(cx.attr_word(sym::inline, span));
vec
},
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
combine_substructure: combine_substructure(|cx, span,
substructure|
{
let field =
match field {
Ok(ref field) => field,
Err(guar) => {
return BlockOrExpr::new_expr(DummyResult::raw_expr(span,
Some(guar)));
}
};
let self_kw = Ident::new(kw::SelfUpper, span);
let expr: Box<ast::Expr> =
match substructure.fields {
SubstructureFields::StaticStruct(variant, _) =>
match variant {
VariantData::Struct { .. } =>
cx.expr_struct_ident(span, self_kw,
{
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(cx.field_imm(span, field.ident.unwrap(),
cx.expr_ident(span, Ident::new(sym::value, span))));
vec
}),
VariantData::Tuple(_, _) =>
cx.expr_call_ident(span, self_kw,
{
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(cx.expr_ident(span, Ident::new(sym::value, span)));
vec
}),
variant => {
cx.dcx().bug(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Invalid derive(From) ADT variant: {0:?}",
variant))
}));
}
},
_ => cx.dcx().bug("Invalid derive(From) ADT input"),
};
BlockOrExpr::new_expr(expr)
}),
});
vec
} else {
::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[MethodDef {
name: sym::from,
generics: Bounds { bounds: ::alloc::vec::Vec::new() },
explicit_self: false,
nonself_args: {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push((from_type, sym::value));
vec
} else {
::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(from_type, sym::value)])))
}
},
ret_ty: Ty::Self_,
attributes: {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(cx.attr_word(sym::inline, span));
vec
},
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
combine_substructure: combine_substructure(|cx, span,
substructure|
{
let field =
match field {
Ok(ref field) => field,
Err(guar) => {
return BlockOrExpr::new_expr(DummyResult::raw_expr(span,
Some(guar)));
}
};
let self_kw = Ident::new(kw::SelfUpper, span);
let expr: Box<ast::Expr> =
match substructure.fields {
SubstructureFields::StaticStruct(variant, _) =>
match variant {
VariantData::Struct { .. } =>
cx.expr_struct_ident(span, self_kw,
{
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(cx.field_imm(span, field.ident.unwrap(),
cx.expr_ident(span, Ident::new(sym::value, span))));
vec
}),
VariantData::Tuple(_, _) =>
cx.expr_call_ident(span, self_kw,
{
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(cx.expr_ident(span, Ident::new(sym::value, span)));
vec
}),
variant => {
cx.dcx().bug(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Invalid derive(From) ADT variant: {0:?}",
variant))
}));
}
},
_ => cx.dcx().bug("Invalid derive(From) ADT input"),
};
BlockOrExpr::new_expr(expr)
}),
}])))
}
}smallvec![MethodDef {
81 name: sym::from,
82 generics: Bounds { bounds: vec![] },
83 explicit_self: false,
84 nonself_args: smallvec![(from_type, sym::value)],
85 ret_ty: Ty::Self_,
86 attributes: thin_vec![cx.attr_word(sym::inline, span)],
87 fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
88 combine_substructure: combine_substructure(|cx, span, substructure| {
89 let field = match field {
90 Ok(ref field) => field,
91 Err(guar) => {
92 return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(guar)));
93 }
94 };
95
96 let self_kw = Ident::new(kw::SelfUpper, span);
97 let expr: Box<ast::Expr> = match substructure.fields {
98 SubstructureFields::StaticStruct(variant, _) => match variant {
99 VariantData::Struct { .. } => cx.expr_struct_ident(
101 span,
102 self_kw,
103 thin_vec![cx.field_imm(
104 span,
105 field.ident.unwrap(),
106 cx.expr_ident(span, Ident::new(sym::value, span))
107 )],
108 ),
109 VariantData::Tuple(_, _) => cx.expr_call_ident(
111 span,
112 self_kw,
113 thin_vec![cx.expr_ident(span, Ident::new(sym::value, span))],
114 ),
115 variant => {
116 cx.dcx().bug(format!("Invalid derive(From) ADT variant: {variant:?}"));
117 }
118 },
119 _ => cx.dcx().bug("Invalid derive(From) ADT input"),
120 };
121 BlockOrExpr::new_expr(expr)
122 }),
123 }],
124 associated_types: SmallVec::new(),
125 is_const,
126 safety: Safety::Default,
127 document: true,
128 };
129
130 from_trait_def.expand(cx, mitem, annotatable, push);
131}