|
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