diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl index 26cdf8a58f3fb..41f458f6c1785 100644 --- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl +++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl @@ -120,3 +120,7 @@ hir_analysis_self_in_impl_self = hir_analysis_linkage_type = invalid type for variable with `#[linkage]` attribute + +hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}` + .label = deref recursion limit reached + .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) diff --git a/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl index 004e0ab189694..14eb4a5502d5c 100644 --- a/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl +++ b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl @@ -2,10 +2,6 @@ trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entri trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated} -trait_selection_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}` - .label = deref recursion limit reached - .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) - trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` .label = empty on-clause here diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs similarity index 98% rename from compiler/rustc_trait_selection/src/autoderef.rs rename to compiler/rustc_hir_analysis/src/autoderef.rs index e988c77a064f6..730560cc68686 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -178,6 +178,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { self.state.obligations } + pub fn current_obligations(&self) -> Vec> { + self.state.obligations.clone() + } + pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] { &self.state.steps } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e9baab594530e..d1f4dbc8d8454 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1,4 +1,6 @@ +use crate::autoderef::Autoderef; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; + use hir::def::DefKind; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; @@ -22,7 +24,6 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::autoderef::Autoderef; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index d383fcacb3a9c..04f5f3f62765a 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -300,3 +300,15 @@ pub(crate) struct LinkageType { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[help] +#[diag(hir_analysis_auto_deref_reached_recursion_limit, code = "E0055")] +pub struct AutoDerefReachedRecursionLimit<'a> { + #[primary_span] + #[label] + pub span: Span, + pub ty: Ty<'a>, + pub suggested_limit: rustc_session::Limit, + pub crate_name: Symbol, +} diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 2058832d5fdc1..65c1d7f373a34 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -84,6 +84,7 @@ extern crate rustc_middle; pub mod check; pub mod astconv; +pub mod autoderef; mod bounds; mod check_unused; mod coherence; diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index 41b52a4c4a9fc..7873257c4e3d1 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -2,11 +2,11 @@ use super::method::MethodCallee; use super::{FnCtxt, PlaceOp}; +use rustc_hir_analysis::autoderef::{Autoderef, AutoderefKind}; use rustc_infer::infer::InferOk; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; -use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind}; use std::iter; diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 3b664363d232f..8d417290407ed 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -8,6 +8,7 @@ use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, Namespace, Res}; use rustc_hir::def_id::DefId; +use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::{ infer, traits::{self, Obligation}, @@ -25,7 +26,6 @@ use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_target::spec::abi; -use rustc_trait_selection::autoderef::Autoderef; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::DefIdOrName; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 6347b9a69a007..27db4d27b6094 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitable}; use rustc_session::Session; use rustc_span::symbol::Ident; -use rustc_span::{self, Span}; +use rustc_span::{self, Span, DUMMY_SP}; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; use std::cell::{Cell, RefCell}; @@ -175,6 +175,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_sig }) }), + autoderef_steps: Box::new(|ty| { + let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors(); + let mut steps = vec![]; + while let Some((ty, _)) = autoderef.next() { + steps.push((ty, autoderef.current_obligations())); + } + steps + }), } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 5d8383170f0dc..ba9c0c8d15e7c 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -9,6 +9,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::DefKind; +use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -29,7 +30,6 @@ use rustc_span::lev_distance::{ }; use rustc_span::symbol::sym; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; -use rustc_trait_selection::autoderef::{self, Autoderef}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; use rustc_trait_selection::traits::query::method_autoderef::{ diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index a0f048fc09b9b..ae0df5aa8f1cf 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -3,6 +3,7 @@ use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp}; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast}; @@ -10,7 +11,6 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; -use rustc_trait_selection::autoderef::Autoderef; use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 66db1a2f92890..0223979263d85 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -55,6 +55,7 @@ use crate::infer::ExpectedFound; use crate::traits::error_reporting::report_object_safety_error; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, + PredicateObligation, }; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -91,8 +92,12 @@ pub mod nice_region_error; pub struct TypeErrCtxt<'a, 'tcx> { pub infcx: &'a InferCtxt<'tcx>, pub typeck_results: Option>>, - pub normalize_fn_sig: Box) -> ty::PolyFnSig<'tcx> + 'a>, pub fallback_has_occurred: bool, + + pub normalize_fn_sig: Box) -> ty::PolyFnSig<'tcx> + 'a>, + + pub autoderef_steps: + Box) -> Vec<(Ty<'tcx>, Vec>)> + 'a>, } impl TypeErrCtxt<'_, '_> { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 6bef3f000a5ac..8825b5e12c3d9 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -688,6 +688,10 @@ impl<'tcx> InferCtxt<'tcx> { typeck_results: None, fallback_has_occurred: false, normalize_fn_sig: Box::new(|fn_sig| fn_sig), + autoderef_steps: Box::new(|ty| { + debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck"); + vec![(ty, vec![])] + }), } } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 19f404cb5b788..4405537c645a9 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,7 +1,6 @@ use rustc_errors::{fluent, ErrorGuaranteed, Handler, IntoDiagnostic}; use rustc_macros::Diagnostic; use rustc_middle::ty::{self, PolyTraitRef, Ty}; -use rustc_session::Limit; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] @@ -21,18 +20,6 @@ pub struct UnableToConstructConstantValue<'a> { pub unevaluated: ty::UnevaluatedConst<'a>, } -#[derive(Diagnostic)] -#[help] -#[diag(trait_selection_auto_deref_reached_recursion_limit, code = "E0055")] -pub struct AutoDerefReachedRecursionLimit<'a> { - #[primary_span] - #[label] - pub span: Span, - pub ty: Ty<'a>, - pub suggested_limit: Limit, - pub crate_name: Symbol, -} - #[derive(Diagnostic)] #[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = "E0232")] pub struct EmptyOnClauseInOnUnimplemented { diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index a30d1df4ede52..081ac966c6961 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -35,7 +35,6 @@ extern crate rustc_middle; #[macro_use] extern crate smallvec; -pub mod autoderef; pub mod errors; pub mod infer; pub mod solve; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 53769742c47a7..48694bac3bca2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -5,7 +5,6 @@ use super::{ PredicateObligation, }; -use crate::autoderef::Autoderef; use crate::infer::InferCtxt; use crate::traits::{NormalizeExt, ObligationCtxt}; @@ -750,26 +749,30 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } if let ty::Ref(region, base_ty, mutbl) = *real_ty.skip_binder().kind() { - let mut autoderef = Autoderef::new( - self, - obligation.param_env, - obligation.cause.body_id, - span, - base_ty, - ); - if let Some(steps) = autoderef.find_map(|(ty, steps)| { - // Re-add the `&` - let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); - - // Remapping bound vars here - let real_trait_pred_and_ty = - real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty)); - let obligation = self.mk_trait_obligation_with_new_self_ty( - obligation.param_env, - real_trait_pred_and_ty, - ); - Some(steps).filter(|_| self.predicate_may_hold(&obligation)) - }) { + let autoderef = (self.autoderef_steps)(base_ty); + if let Some(steps) = + autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| { + // Re-add the `&` + let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); + + // Remapping bound vars here + let real_trait_pred_and_ty = + real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty)); + let obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + real_trait_pred_and_ty, + ); + if obligations + .iter() + .chain([&obligation]) + .all(|obligation| self.predicate_may_hold(obligation)) + { + Some(steps) + } else { + None + } + }) + { if steps > 0 { // Don't care about `&mut` because `DerefMut` is used less // often and user will not expect autoderef happens.