|
1 | 1 | use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; |
2 | 2 | use clippy_utils::paths; |
3 | | -use clippy_utils::ty::{implements_trait, is_copy}; |
| 3 | +use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; |
4 | 4 | use clippy_utils::{is_lint_allowed, match_def_path}; |
5 | 5 | use if_chain::if_chain; |
6 | 6 | use rustc_errors::Applicability; |
7 | 7 | use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; |
8 | 8 | use rustc_hir::{ |
9 | | - BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety, |
| 9 | + self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, UnsafeSource, Unsafety, |
10 | 10 | }; |
11 | 11 | use rustc_lint::{LateContext, LateLintPass}; |
12 | 12 | use rustc_middle::hir::nested_filter; |
13 | | -use rustc_middle::ty::{self, Ty}; |
| 13 | +use rustc_middle::ty::subst::GenericArg; |
| 14 | +use rustc_middle::ty::{self, BoundConstness, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, TraitRef, Ty}; |
14 | 15 | use rustc_session::{declare_lint_pass, declare_tool_lint}; |
15 | 16 | use rustc_span::source_map::Span; |
16 | 17 | use rustc_span::sym; |
@@ -224,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { |
224 | 225 | fn check_hash_peq<'tcx>( |
225 | 226 | cx: &LateContext<'tcx>, |
226 | 227 | span: Span, |
227 | | - trait_ref: &TraitRef<'_>, |
| 228 | + trait_ref: &hir::TraitRef<'_>, |
228 | 229 | ty: Ty<'tcx>, |
229 | 230 | hash_is_automatically_derived: bool, |
230 | 231 | ) { |
@@ -277,7 +278,7 @@ fn check_hash_peq<'tcx>( |
277 | 278 | fn check_ord_partial_ord<'tcx>( |
278 | 279 | cx: &LateContext<'tcx>, |
279 | 280 | span: Span, |
280 | | - trait_ref: &TraitRef<'_>, |
| 281 | + trait_ref: &hir::TraitRef<'_>, |
281 | 282 | ty: Ty<'tcx>, |
282 | 283 | ord_is_automatically_derived: bool, |
283 | 284 | ) { |
@@ -328,7 +329,7 @@ fn check_ord_partial_ord<'tcx>( |
328 | 329 | } |
329 | 330 |
|
330 | 331 | /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint. |
331 | | -fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) { |
| 332 | +fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) { |
332 | 333 | let clone_id = match cx.tcx.lang_items().clone_trait() { |
333 | 334 | Some(id) if trait_ref.trait_def_id() == Some(id) => id, |
334 | 335 | _ => return, |
@@ -378,7 +379,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &T |
378 | 379 | fn check_unsafe_derive_deserialize<'tcx>( |
379 | 380 | cx: &LateContext<'tcx>, |
380 | 381 | item: &Item<'_>, |
381 | | - trait_ref: &TraitRef<'_>, |
| 382 | + trait_ref: &hir::TraitRef<'_>, |
382 | 383 | ty: Ty<'tcx>, |
383 | 384 | ) { |
384 | 385 | fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool { |
@@ -455,13 +456,41 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { |
455 | 456 | } |
456 | 457 |
|
457 | 458 | /// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint. |
458 | | -fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) { |
| 459 | +fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) { |
459 | 460 | if_chain! { |
460 | 461 | if let ty::Adt(adt, substs) = ty.kind(); |
461 | 462 | if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq); |
| 463 | + if let Some(peq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::PartialEq); |
462 | 464 | if let Some(def_id) = trait_ref.trait_def_id(); |
463 | 465 | if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id); |
464 | | - if !implements_trait(cx, ty, eq_trait_def_id, substs); |
| 466 | + // New `ParamEnv` replacing `T: PartialEq` with `T: Eq` |
| 467 | + let param_env = ParamEnv::new( |
| 468 | + cx.tcx.mk_predicates(cx.param_env.caller_bounds().iter().map(|p| { |
| 469 | + let kind = p.kind(); |
| 470 | + match kind.skip_binder() { |
| 471 | + PredicateKind::Trait(p) |
| 472 | + if p.trait_ref.def_id == peq_trait_def_id |
| 473 | + && p.trait_ref.substs.get(0) == p.trait_ref.substs.get(1) |
| 474 | + && matches!(p.trait_ref.self_ty().kind(), ty::Param(_)) |
| 475 | + && p.constness == BoundConstness::NotConst |
| 476 | + && p.polarity == ImplPolarity::Positive => |
| 477 | + { |
| 478 | + cx.tcx.mk_predicate(kind.rebind(PredicateKind::Trait(TraitPredicate { |
| 479 | + trait_ref: TraitRef::new( |
| 480 | + eq_trait_def_id, |
| 481 | + cx.tcx.mk_substs([GenericArg::from(p.trait_ref.self_ty())].into_iter()), |
| 482 | + ), |
| 483 | + constness: BoundConstness::NotConst, |
| 484 | + polarity: ImplPolarity::Positive, |
| 485 | + }))) |
| 486 | + }, |
| 487 | + _ => p, |
| 488 | + } |
| 489 | + })), |
| 490 | + cx.param_env.reveal(), |
| 491 | + cx.param_env.constness(), |
| 492 | + ); |
| 493 | + if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, substs); |
465 | 494 | then { |
466 | 495 | // If all of our fields implement `Eq`, we can implement `Eq` too |
467 | 496 | for variant in adt.variants() { |
|
0 commit comments