diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
3 files changed, 74 insertions, 58 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 596f794568c..5c489a55aec 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2419,6 +2419,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &mut vec![], &mut Default::default(), ); + self.suggest_swapping_lhs_and_rhs( + err, + obligation.predicate, + obligation.param_env, + obligation.cause.code(), + ); self.suggest_unsized_bound_if_applicable(err, obligation); if let Some(span) = err.span.primary_span() && let Some(mut diag) = diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 0ff00e752a2..b85c18c5312 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4914,6 +4914,53 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); true } + pub(crate) fn suggest_swapping_lhs_and_rhs<T>( + &self, + err: &mut Diag<'_>, + predicate: T, + param_env: ty::ParamEnv<'tcx>, + cause_code: &ObligationCauseCode<'tcx>, + ) where + T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>, + { + let tcx = self.tcx; + let predicate = predicate.upcast(tcx); + match *cause_code { + ObligationCauseCode::BinOp { + lhs_hir_id, + rhs_hir_id: Some(rhs_hir_id), + rhs_span: Some(rhs_span), + .. + } if let Some(typeck_results) = &self.typeck_results + && let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id) + && let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id) + && let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs) + && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) => + { + if let Some(pred) = predicate.as_trait_clause() + && tcx.is_lang_item(pred.def_id(), LangItem::PartialEq) + && self + .infcx + .type_implements_trait(pred.def_id(), [rhs_ty, lhs_ty], param_env) + .must_apply_modulo_regions() + { + let lhs_span = tcx.hir().span(lhs_hir_id); + let sm = tcx.sess.source_map(); + if let Ok(rhs_snippet) = sm.span_to_snippet(rhs_span) + && let Ok(lhs_snippet) = sm.span_to_snippet(lhs_span) + { + err.note(format!("`{rhs_ty}` implements `PartialEq<{lhs_ty}>`")); + err.multipart_suggestion( + "consider swapping the equality", + vec![(lhs_span, rhs_snippet), (rhs_span, lhs_snippet)], + Applicability::MaybeIncorrect, + ); + } + } + } + _ => {} + } + } } /// Add a hint to add a missing borrow or remove an unnecessary one. diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a4ee1cbb853..120e6f6e2ce 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -9,7 +9,7 @@ use std::ops::ControlFlow; use std::{cmp, iter}; use hir::def::DefKind; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; @@ -25,7 +25,6 @@ use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds}; pub use rustc_middle::traits::select::*; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::TypeErrorToStringExt; -use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, @@ -2205,8 +2204,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::CoroutineWitness(def_id, args) => { - let hidden_types = bind_coroutine_hidden_types_above( - self.infcx, + let hidden_types = rebind_coroutine_witness_types( + self.infcx.tcx, def_id, args, obligation.predicate.bound_vars(), @@ -2354,7 +2353,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::CoroutineWitness(def_id, args) => { - bind_coroutine_hidden_types_above(self.infcx, def_id, args, t.bound_vars()) + rebind_coroutine_witness_types(self.infcx.tcx, def_id, args, t.bound_vars()) } // For `PhantomData<T>`, we pass `T`. @@ -2849,6 +2848,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } +fn rebind_coroutine_witness_types<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + bound_vars: &'tcx ty::List<ty::BoundVariableKind>, +) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { + let bound_coroutine_types = tcx.coroutine_hidden_types(def_id).skip_binder(); + let shifted_coroutine_types = + tcx.shift_bound_var_indices(bound_vars.len(), bound_coroutine_types.skip_binder()); + ty::Binder::bind_with_vars( + ty::EarlyBinder::bind(shifted_coroutine_types.to_vec()).instantiate(tcx, args), + tcx.mk_bound_variable_kinds_from_iter( + bound_vars.iter().chain(bound_coroutine_types.bound_vars()), + ), + ) +} + impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> { TraitObligationStackList::with(self) @@ -3157,56 +3173,3 @@ pub(crate) enum ProjectionMatchesProjection { Ambiguous, No, } - -/// Replace all regions inside the coroutine interior with late bound regions. -/// Note that each region slot in the types gets a new fresh late bound region, which means that -/// none of the regions inside relate to any other, even if typeck had previously found constraints -/// that would cause them to be related. -#[instrument(level = "trace", skip(infcx), ret)] -fn bind_coroutine_hidden_types_above<'tcx>( - infcx: &InferCtxt<'tcx>, - def_id: DefId, - args: ty::GenericArgsRef<'tcx>, - bound_vars: &ty::List<ty::BoundVariableKind>, -) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { - let tcx = infcx.tcx; - let mut seen_tys = FxHashSet::default(); - - let considering_regions = infcx.considering_regions; - - let num_bound_variables = bound_vars.len() as u32; - let mut counter = num_bound_variables; - - let hidden_types: Vec<_> = tcx - .coroutine_hidden_types(def_id) - // Deduplicate tys to avoid repeated work. - .filter(|bty| seen_tys.insert(*bty)) - .map(|mut bty| { - // Only remap erased regions if we use them. - if considering_regions { - bty = bty.map_bound(|ty| { - fold_regions(tcx, ty, |r, current_depth| match r.kind() { - ty::ReErased => { - let br = ty::BoundRegion { - var: ty::BoundVar::from_u32(counter), - kind: ty::BoundRegionKind::Anon, - }; - counter += 1; - ty::Region::new_bound(tcx, current_depth, br) - } - r => bug!("unexpected region: {r:?}"), - }) - }) - } - - bty.instantiate(tcx, args) - }) - .collect(); - let bound_vars = tcx.mk_bound_variable_kinds_from_iter( - bound_vars.iter().chain( - (num_bound_variables..counter) - .map(|_| ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)), - ), - ); - ty::Binder::bind_with_vars(hidden_types, bound_vars) -} |
