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::*;
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 = new_path(cx, span, { &[sym::convert, sym::From] }pathvec!(convert::From), &[from_type.clone()]);
56
57 let from_trait_def = TraitDef {
68 span,
69 path,
70 skip_path_as_bound: true,
71 needs_copy_as_bound_if_packed: false,
72 additional_bounds: SmallVec::new(),
73 supports_unions: false,
74 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 {
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 {
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 {
75 name: sym::from,
76 generics: cx.empty_generics(span),
77 explicit_self: false,
78 nonself_args: smallvec![(from_type, sym::value)],
79 ret_ty: Ty::Self_,
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 {
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(span, Ident::new(sym::value, span))
101 )],
102 ),
103 VariantData::Tuple(_, _) => cx.expr_call_ident(
105 span,
106 self_kw,
107 thin_vec![cx.expr_ident(span, Ident::new(sym::value, span))],
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 associated_types: SmallVec::new(),
119 is_const,
120 safety: Safety::Default,
121 document: true,
122 };
123
124 from_trait_def.expand(cx, item, push);
125}