rustc_builtin_macros/deriving/
from.rs1use rustc_ast as ast;
2use rustc_ast::{ItemKind, 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::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 = cx.std_path_all(
55 span,
56 { &[sym::convert, sym::From] }pathvec!(convert::From),
57 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[ast::GenericArg::Type(from_type.clone())]))vec![ast::GenericArg::Type(from_type.clone())],
58 );
59
60 let from_trait_def = TraitDef {
71 span,
72 path,
73 skip_path_as_bound: true,
74 needs_copy_as_bound_if_packed: false,
75 additional_bounds: SmallVec::new(),
76 supports_unions: false,
77 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.generated_attr(span,
ast::GeneratedAttr::Inline));
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 {
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_name(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_name(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.generated_attr(span,
ast::GeneratedAttr::Inline));
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 {
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_name(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_name(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 {
78 name: sym::from,
79 generics: cx.empty_generics(span),
80 explicit_self: false,
81 nonself_args: smallvec![(from_type, sym::value)],
82 has_other_selflike_arg: false,
83 ret_ty: cx.ty_self(span),
84 attributes: thin_vec![cx.generated_attr(span, ast::GeneratedAttr::Inline)],
85 fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
86 combine_substructure: combine_substructure(|cx, span, substructure| {
87 let field = match field {
88 Ok(ref field) => field,
89 Err(guar) => {
90 return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(guar)));
91 }
92 };
93
94 let self_kw = Ident::new(kw::SelfUpper, span);
95 let expr: Box<ast::Expr> = match substructure {
96 StaticStruct(variant) => match variant {
97 VariantData::Struct { .. } => cx.expr_struct_ident(
99 span,
100 self_kw,
101 thin_vec![cx.field_imm(
102 span,
103 field.ident.unwrap(),
104 cx.expr_name(span, sym::value)
105 )],
106 ),
107 VariantData::Tuple(_, _) => cx.expr_call_ident(
109 span,
110 self_kw,
111 thin_vec![cx.expr_name(span, sym::value)],
112 ),
113 variant => {
114 cx.dcx().bug(format!("Invalid derive(From) ADT variant: {variant:?}"));
115 }
116 },
117 _ => cx.dcx().bug("Invalid derive(From) ADT input"),
118 };
119 BlockOrExpr::new_expr(expr)
120 }),
121 }],
122 is_const,
123 ..
124 };
125
126 from_trait_def.expand(cx, item, push);
127}