| use crate::deriving::generic::ty::*; |
| use crate::deriving::generic::*; |
| use crate::deriving::{path_local, path_std}; |
| use rustc_ast::ptr::P; |
| use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability}; |
| use rustc_expand::base::{Annotatable, ExtCtxt}; |
| use rustc_span::symbol::sym; |
| use rustc_span::Span; |
| use thin_vec::thin_vec; |
| |
| pub fn expand_deriving_partial_eq( |
| cx: &mut ExtCtxt<'_>, |
| span: Span, |
| mitem: &MetaItem, |
| item: &Annotatable, |
| push: &mut dyn FnMut(Annotatable), |
| is_const: bool, |
| ) { |
| fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { |
| let base = true; |
| let expr = cs_fold( |
| true, // use foldl |
| cx, |
| span, |
| substr, |
| |cx, fold| match fold { |
| CsFold::Single(field) => { |
| let [other_expr] = &field.other_selflike_exprs[..] else { |
| cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); |
| }; |
| |
| // We received `&T` arguments. Convert them to `T` by |
| // stripping `&` or adding `*`. This isn't necessary for |
| // type checking, but it results in much better error |
| // messages if something goes wrong. |
| let convert = |expr: &P<Expr>| { |
| if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = |
| &expr.kind |
| { |
| inner.clone() |
| } else { |
| cx.expr_deref(field.span, expr.clone()) |
| } |
| }; |
| cx.expr_binary( |
| field.span, |
| BinOpKind::Eq, |
| convert(&field.self_expr), |
| convert(other_expr), |
| ) |
| } |
| CsFold::Combine(span, expr1, expr2) => { |
| cx.expr_binary(span, BinOpKind::And, expr1, expr2) |
| } |
| CsFold::Fieldless => cx.expr_bool(span, base), |
| }, |
| ); |
| BlockOrExpr::new_expr(expr) |
| } |
| |
| super::inject_impl_of_structural_trait( |
| cx, |
| span, |
| item, |
| path_std!(marker::StructuralPartialEq), |
| push, |
| ); |
| |
| // No need to generate `ne`, the default suffices, and not generating it is |
| // faster. |
| let attrs = thin_vec![cx.attr_word(sym::inline, span)]; |
| let methods = vec![MethodDef { |
| name: sym::eq, |
| generics: Bounds::empty(), |
| explicit_self: true, |
| nonself_args: vec![(self_ref(), sym::other)], |
| ret_ty: Path(path_local!(bool)), |
| attributes: attrs, |
| unify_fieldless_variants: true, |
| combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))), |
| }]; |
| |
| let trait_def = TraitDef { |
| span, |
| path: path_std!(cmp::PartialEq), |
| skip_path_as_bound: false, |
| additional_bounds: Vec::new(), |
| supports_unions: false, |
| methods, |
| associated_types: Vec::new(), |
| is_const, |
| }; |
| trait_def.expand(cx, mitem, item, push) |
| } |