1 use crate::deriving
::generic
::ty
::*;
2 use crate::deriving
::generic
::*;
3 use crate::deriving
::{path_std, pathvec_std}
;
5 use rustc_ast
::{AttrVec, MetaItem, Mutability}
;
6 use rustc_expand
::base
::{Annotatable, ExtCtxt}
;
7 use rustc_span
::symbol
::sym
;
10 pub fn expand_deriving_hash(
15 push
: &mut dyn FnMut(Annotatable
),
17 let path
= Path
::new_(pathvec_std
!(hash
::Hash
), vec
![], PathKind
::Std
);
19 let typaram
= sym
::__H
;
21 let arg
= Path
::new_local(typaram
);
22 let hash_trait_def
= TraitDef
{
25 additional_bounds
: Vec
::new(),
26 generics
: Bounds
::empty(),
27 supports_unions
: false,
28 methods
: vec
![MethodDef
{
30 generics
: Bounds { bounds: vec![(typaram, vec![path_std!(hash::Hasher)])] }
,
32 nonself_args
: vec
![(Ref(Box
::new(Path(arg
)), Mutability
::Mut
), sym
::state
)],
34 attributes
: AttrVec
::new(),
35 unify_fieldless_variants
: true,
36 combine_substructure
: combine_substructure(Box
::new(|a
, b
, c
| {
37 hash_substructure(a
, b
, c
)
40 associated_types
: Vec
::new(),
43 hash_trait_def
.expand(cx
, mitem
, item
, push
);
49 substr
: &Substructure
<'_
>,
51 let [state_expr
] = substr
.nonselflike_args
else {
52 cx
.span_bug(trait_span
, "incorrect number of arguments in `derive(Hash)`");
54 let call_hash
= |span
, expr
| {
56 let strs
= cx
.std_path(&[sym
::hash
, sym
::Hash
, sym
::hash
]);
58 cx
.expr_path(cx
.path_global(span
, strs
))
60 let expr
= cx
.expr_call(span
, hash_path
, vec
![expr
, state_expr
.clone()]);
64 let (stmts
, match_expr
) = match substr
.fields
{
65 Struct(_
, fields
) | EnumMatching(.., fields
) => {
67 fields
.iter().map(|field
| call_hash(field
.span
, field
.self_expr
.clone())).collect();
70 EnumTag(tag_field
, match_expr
) => {
71 assert
!(tag_field
.other_selflike_exprs
.is_empty());
72 let stmts
= vec
![call_hash(tag_field
.span
, tag_field
.self_expr
.clone())];
73 (stmts
, match_expr
.clone())
75 _
=> cx
.span_bug(trait_span
, "impossible substructure in `derive(Hash)`"),
78 BlockOrExpr
::new_mixed(stmts
, match_expr
)