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::new_path(cx, span, { &[sym::hash, sym::Hash] }, &[])path_std!(cx, span, hash::Hash);
18
19 let typaram = Ident::new(sym::__H, span);
20
21 let arg = cx.path_ident(span, typaram);
22
23 let param = {
24 let path = generic::ty::new_path(cx, span, { &[sym::hash, sym::Hasher] }, &[])path_std!(cx, span, hash::Hasher);
25 cx.typaram(span, typaram, {
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 call_hash = |span, expr| {
62 let strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]);
63 let hash_path = cx.expr_path(cx.path_global(span, strs));
64 let expr = cx.expr_call(
65 span,
66 hash_path,
67 {
let len = [(), ()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(expr);
vec.push(cx.expr_ident(span, Ident::new(sym::state, span)));
vec
}thin_vec![expr, cx.expr_ident(span, Ident::new(sym::state, span))],
68 );
69 cx.stmt_expr(expr)
70 };
71
72 let (stmts, match_expr) = match substr {
73 Struct(_, fields) | EnumMatching(.., fields) => {
74 let stmts =
75 fields.into_iter().map(|field| call_hash(field.span, field.self_expr)).collect();
76 (stmts, None)
77 }
78 EnumDiscr(discr_field, match_expr) => {
79 if !discr_field.other_selflike_expr.is_none() {
::core::panicking::panic("assertion failed: discr_field.other_selflike_expr.is_none()")
};assert!(discr_field.other_selflike_expr.is_none());
80 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)];
81 (stmts, match_expr)
82 }
83 _ => cx.dcx().span_bug(trait_span, "unexpected substructure in `derive(Hash)`"),
84 };
85
86 BlockOrExpr::new_mixed(stmts, match_expr)
87}