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::ty::{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 item: &ast::Item,
19 push: &mut dyn FnMut(Box<ast::Item>),
20 is_const: bool,
21) {
22 let err_span = || {
23 let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span);
24 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])
25 };
26
27 let field = match &item.kind {
29 ItemKind::Struct(_, _, data) => {
30 if let [field] = data.fields() {
31 Ok(field.clone())
32 } else {
33 let guar = cx.dcx().emit_err(diagnostics::DeriveFromWrongFieldCount {
34 span: err_span(),
35 multiple_fields: data.fields().len() > 1,
36 });
37 Err(guar)
38 }
39 }
40 ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => {
41 let guar = cx.dcx().emit_err(diagnostics::DeriveFromWrongTarget {
42 span: err_span(),
43 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()),
44 });
45 Err(guar)
46 }
47 _ => cx.dcx().bug("Invalid derive(From) ADT input"),
48 };
49
50 let from_type = Ty::AstTy(match field {
51 Ok(ref field) => field.ty.clone(),
52 Err(guar) => cx.ty(span, ast::TyKind::Err(guar)),
53 });
54
55 let path =
56 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);
57
58 let from_trait_def = TraitDef {
69 span,
70 path,
71 skip_path_as_bound: true,
72 needs_copy_as_bound_if_packed: false,
73 additional_bounds: SmallVec::new(),
74 supports_unions: false,
75 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)])))
}
},
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: 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)])))
}
},
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 {
76 name: sym::from,
77 generics: cx.empty_generics(span),
78 explicit_self: false,
79 nonself_args: smallvec![(from_type, sym::value)],
80 ret_ty: Ty::Self_,
81 attributes: thin_vec![cx.attr_word(sym::inline, span)],
82 fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
83 combine_substructure: combine_substructure(|cx, span, substructure| {
84 let field = match field {
85 Ok(ref field) => field,
86 Err(guar) => {
87 return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(guar)));
88 }
89 };
90
91 let self_kw = Ident::new(kw::SelfUpper, span);
92 let expr: Box<ast::Expr> = match substructure.fields {
93 SubstructureFields::StaticStruct(variant) => match variant {
94 VariantData::Struct { .. } => cx.expr_struct_ident(
96 span,
97 self_kw,
98 thin_vec![cx.field_imm(
99 span,
100 field.ident.unwrap(),
101 cx.expr_ident(span, Ident::new(sym::value, span))
102 )],
103 ),
104 VariantData::Tuple(_, _) => cx.expr_call_ident(
106 span,
107 self_kw,
108 thin_vec![cx.expr_ident(span, Ident::new(sym::value, span))],
109 ),
110 variant => {
111 cx.dcx().bug(format!("Invalid derive(From) ADT variant: {variant:?}"));
112 }
113 },
114 _ => cx.dcx().bug("Invalid derive(From) ADT input"),
115 };
116 BlockOrExpr::new_expr(expr)
117 }),
118 }],
119 associated_types: SmallVec::new(),
120 is_const,
121 safety: Safety::Default,
122 document: true,
123 };
124
125 from_trait_def.expand(cx, item, push);
126}