rustc_builtin_macros/deriving/
from.rs1use rustc_ast as ast;
2use rustc_ast::{ItemKind, Safety, VariantData};
3use rustc_errors::MultiSpan;
4use rustc_expand::base::{DummyResult, ExtCtxt};
5use rustc_span::{Ident, Span, kw, sym};
6use thin_vec::thin_vec;
7
8use crate::deriving::generic::*;
9use crate::deriving::{new_path, pathvec};
10use crate::diagnostics;
11
12pub(crate) fn expand_deriving_from(
15 cx: &ExtCtxt<'_>,
16 span: Span,
17 item: &ast::Item,
18 push: &mut dyn FnMut(Box<ast::Item>),
19 is_const: bool,
20) {
21 let err_span = || {
22 let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span);
23 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])
24 };
25
26 let field = match &item.kind {
28 ItemKind::Struct(_, _, data) => {
29 if let [field] = data.fields() {
30 Ok(field.clone())
31 } else {
32 let guar = cx.dcx().emit_err(diagnostics::DeriveFromWrongFieldCount {
33 span: err_span(),
34 multiple_fields: data.fields().len() > 1,
35 });
36 Err(guar)
37 }
38 }
39 ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => {
40 let guar = cx.dcx().emit_err(diagnostics::DeriveFromWrongTarget {
41 span: err_span(),
42 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()),
43 });
44 Err(guar)
45 }
46 _ => cx.dcx().bug("Invalid derive(From) ADT input"),
47 };
48
49 let from_type = match field {
50 Ok(ref field) => field.ty.clone(),
51 Err(guar) => cx.ty(span, ast::TyKind::Err(guar)),
52 };
53
54 let path = new_path(cx, span, { &[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(),
[from_type.clone()]))vec![from_type.clone()]);
55
56 let from_trait_def = TraitDef {
67 span,
68 path,
69 skip_path_as_bound: true,
70 needs_copy_as_bound_if_packed: false,
71 additional_bounds: SmallVec::new(),
72 supports_unions: false,
73 methods: {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(MethodDef {
name: sym::from,
generics: cx.empty_generics(span),
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)])))
}
},
has_other_selflike_arg: false,
ret_ty: cx.ty_self(span),
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 {
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_sym(span, sym::value)));
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_sym(span, sym::value));
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: cx.empty_generics(span),
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)])))
}
},
has_other_selflike_arg: false,
ret_ty: cx.ty_self(span),
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 {
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_sym(span, sym::value)));
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_sym(span, sym::value));
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 {
74 name: sym::from,
75 generics: cx.empty_generics(span),
76 explicit_self: false,
77 nonself_args: smallvec![(from_type, sym::value)],
78 has_other_selflike_arg: false,
79 ret_ty: cx.ty_self(span),
80 attributes: thin_vec![cx.attr_word(sym::inline, span)],
81 fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
82 combine_substructure: combine_substructure(|cx, span, substructure| {
83 let field = match field {
84 Ok(ref field) => field,
85 Err(guar) => {
86 return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(guar)));
87 }
88 };
89
90 let self_kw = Ident::new(kw::SelfUpper, span);
91 let expr: Box<ast::Expr> = match substructure.fields {
92 StaticStruct(variant) => match variant {
93 VariantData::Struct { .. } => cx.expr_struct_ident(
95 span,
96 self_kw,
97 thin_vec![cx.field_imm(
98 span,
99 field.ident.unwrap(),
100 cx.expr_ident_sym(span, sym::value)
101 )],
102 ),
103 VariantData::Tuple(_, _) => cx.expr_call_ident(
105 span,
106 self_kw,
107 thin_vec![cx.expr_ident_sym(span, sym::value)],
108 ),
109 variant => {
110 cx.dcx().bug(format!("Invalid derive(From) ADT variant: {variant:?}"));
111 }
112 },
113 _ => cx.dcx().bug("Invalid derive(From) ADT input"),
114 };
115 BlockOrExpr::new_expr(expr)
116 }),
117 }],
118 is_const,
119 safety: Safety::Default,
120 document: true,
121 };
122
123 from_trait_def.expand(cx, item, push);
124}