rustc_builtin_macros/deriving/
hash.rs1use rustc_ast::{Mutability, Safety};
2use rustc_expand::base::ExtCtxt;
3use rustc_span::{Ident, Span, sym};
4use thin_vec::{ThinVec, thin_vec};
5
6use crate::deriving::generic::ty::*;
7use crate::deriving::generic::*;
8use crate::deriving::path_std;
9
10pub(crate) fn expand_deriving_hash(
11 cx: &ExtCtxt<'_>,
12 span: Span,
13 item: &ast::Item,
14 push: &mut dyn FnMut(Box<ast::Item>),
15 is_const: bool,
16) {
17 let path = generic::ty::Path::new({
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[sym::hash, sym::Hash]))
})path_std!(hash::Hash);
18
19 let typaram = sym::__H;
20
21 let arg = Path::new_local(typaram);
22
23 let param = {
24 let path = cx.path_all(span, false, cx.std_path(&[sym::hash, sym::Hasher]), Vec::new());
25 cx.typaram(span, Ident::new(typaram, span), {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(cx.trait_bound(path, false));
vec
}thin_vec![cx.trait_bound(path, false)], None)
26 };
27
28 let generics = ast::Generics {
29 params: {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(param);
vec
}thin_vec![param],
30 where_clause: ast::WhereClause { has_where_token: false, predicates: ThinVec::new(), span },
31 span,
32 };
33
34 let hash_trait_def = TraitDef {
35 span,
36 path,
37 skip_path_as_bound: false,
38 needs_copy_as_bound_if_packed: true,
39 additional_bounds: SmallVec::new(),
40 supports_unions: false,
41 methods: {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(MethodDef {
name: sym::hash,
generics,
explicit_self: true,
nonself_args: {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push((Ref(Box::new(Path(arg)), Mutability::Mut),
sym::state));
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(),
[(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)])))
}
},
ret_ty: Unit,
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::Unify,
combine_substructure: combine_substructure(hash_substructure),
});
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::hash,
generics,
explicit_self: true,
nonself_args: {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push((Ref(Box::new(Path(arg)), Mutability::Mut),
sym::state));
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(),
[(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)])))
}
},
ret_ty: Unit,
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::Unify,
combine_substructure: combine_substructure(hash_substructure),
}])))
}
}smallvec![MethodDef {
42 name: sym::hash,
43 generics,
44 explicit_self: true,
45 nonself_args: smallvec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
46 ret_ty: Unit,
47 attributes: thin_vec![cx.attr_word(sym::inline, span)],
48 fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
49 combine_substructure: combine_substructure(hash_substructure),
50 }],
51 associated_types: SmallVec::new(),
52 is_const,
53 safety: Safety::Default,
54 document: true,
55 };
56
57 hash_trait_def.expand(cx, item, push);
58}
59
60fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: Substructure<'_>) -> BlockOrExpr {
61 let [state_expr] = substr.nonselflike_args else {
62 cx.dcx().span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
63 };
64 let call_hash = |span, expr| {
65 let strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]);
66 let hash_path = cx.expr_path(cx.path_global(span, strs));
67 let expr = cx.expr_call(span, hash_path, {
let len = [(), ()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(expr);
vec.push(state_expr.clone());
vec
}thin_vec![expr, state_expr.clone()]);
68 cx.stmt_expr(expr)
69 };
70
71 let (stmts, match_expr) = match substr.fields {
72 Struct(_, fields) | EnumMatching(.., fields) => {
73 let stmts =
74 fields.into_iter().map(|field| call_hash(field.span, field.self_expr)).collect();
75 (stmts, None)
76 }
77 EnumDiscr(discr_field, match_expr) => {
78 if !discr_field.other_selflike_exprs.is_empty() {
::core::panicking::panic("assertion failed: discr_field.other_selflike_exprs.is_empty()")
};assert!(discr_field.other_selflike_exprs.is_empty());
79 let stmts = {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(call_hash(discr_field.span, discr_field.self_expr));
vec
}thin_vec![call_hash(discr_field.span, discr_field.self_expr)];
80 (stmts, match_expr)
81 }
82 _ => cx.dcx().span_bug(trait_span, "unexpected substructure in `derive(Hash)`"),
83 };
84
85 BlockOrExpr::new_mixed(stmts, match_expr)
86}