about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-03-07 04:39:17 +0000
committerMichael Goulet <michael@errs.io>2023-03-13 16:34:16 +0000
commitc32527fb92218ea999ebf82357838fabf4ee7bc4 (patch)
treefe810b8c2aff62d8949f054670a98e8960c4ce13
parentf1b1ed7e18f1fbe5226a96626827c625985f8285 (diff)
downloadrust-c32527fb92218ea999ebf82357838fabf4ee7bc4.tar.gz
rust-c32527fb92218ea999ebf82357838fabf4ee7bc4.zip
Treat projections with infer as placeholder during fast reject in new solver
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs20
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs3
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs44
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs58
-rw-r--r--compiler/rustc_middle/src/ty/util.rs21
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs25
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs25
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs4
-rw-r--r--tests/ui/traits/new-solver/runaway-impl-candidate-selection.rs15
-rw-r--r--tests/ui/traits/new-solver/runaway-impl-candidate-selection.stderr9
15 files changed, 186 insertions, 68 deletions
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 02f3eeee0e7..068e5a5eb77 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -11,7 +11,7 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
-use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
+use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams, TreatProjections};
 use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 
@@ -99,7 +99,12 @@ impl<'tcx> InherentCollect<'tcx> {
                 }
             }
 
-            if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) {
+            if let Some(simp) = simplify_type(
+                self.tcx,
+                self_ty,
+                TreatParams::AsInfer,
+                TreatProjections::DefaultCandidate,
+            ) {
                 self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
             } else {
                 bug!("unexpected self type: {:?}", self_ty);
@@ -159,7 +164,9 @@ impl<'tcx> InherentCollect<'tcx> {
             }
         }
 
-        if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsInfer) {
+        if let Some(simp) =
+            simplify_type(self.tcx, ty, TreatParams::AsInfer, TreatProjections::DefaultCandidate)
+        {
             self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
         } else {
             bug!("unexpected primitive type: {:?}", ty);
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 57805f7c800..e9d4f9282a3 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -15,6 +15,7 @@ use rustc_infer::infer::canonical::OriginalQueryValues;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
 use rustc_middle::middle::stability;
+use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::AssocItem;
 use rustc_middle::ty::GenericParamDefKind;
@@ -699,7 +700,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     }
 
     fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
-        let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) else {
+        let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer, TreatProjections::DefaultCandidate) else {
             bug!("unexpected incoherent type: {:?}", self_ty)
         };
         for &impl_def_id in self.tcx.incoherent_impls(simp) {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 4b15e48bd27..da0d180987a 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -25,6 +25,7 @@ use rustc_infer::infer::{
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::traits::util::supertraits;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
+use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
 use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
@@ -1516,7 +1517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .into_iter()
             .any(|info| self.associated_value(info.def_id, item_name).is_some());
         let found_assoc = |ty: Ty<'tcx>| {
-            simplify_type(tcx, ty, TreatParams::AsInfer)
+            simplify_type(tcx, ty, TreatParams::AsInfer, TreatProjections::DefaultCandidate)
                 .and_then(|simp| {
                     tcx.incoherent_impls(simp)
                         .iter()
@@ -2645,9 +2646,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // FIXME: Even though negative bounds are not implemented, we could maybe handle
                 // cases where a positive bound implies a negative impl.
                 (candidates, Vec::new())
-            } else if let Some(simp_rcvr_ty) =
-                simplify_type(self.tcx, rcvr_ty, TreatParams::AsPlaceholder)
-            {
+            } else if let Some(simp_rcvr_ty) = simplify_type(
+                self.tcx,
+                rcvr_ty,
+                TreatParams::AsPlaceholder,
+                TreatProjections::DefaultLookup,
+            ) {
                 let mut potential_candidates = Vec::new();
                 let mut explicitly_negative = Vec::new();
                 for candidate in candidates {
@@ -2660,8 +2664,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         })
                         .any(|imp_did| {
                             let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
-                            let imp_simp =
-                                simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
+                            let imp_simp = simplify_type(
+                                self.tcx,
+                                imp.self_ty(),
+                                TreatParams::AsPlaceholder,
+                                TreatProjections::DefaultLookup,
+                            );
                             imp_simp.map_or(false, |s| s == simp_rcvr_ty)
                         })
                     {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 16306bef42e..ccadb0bada2 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -26,7 +26,7 @@ use rustc_middle::middle::exported_symbols::{
 use rustc_middle::mir::interpret;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
 use rustc_middle::util::common::to_readable_str;
@@ -1859,6 +1859,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                         self.tcx,
                         trait_ref.self_ty(),
                         TreatParams::AsInfer,
+                        TreatProjections::DefaultCandidate,
                     );
 
                     fx_hash_map
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 59deade0a07..d672c6cc803 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -52,16 +52,33 @@ pub enum SimplifiedType {
 #[derive(PartialEq, Eq, Debug, Clone, Copy)]
 pub enum TreatParams {
     /// Treat parameters as placeholders in the given environment.
-    ///
-    /// Note that this also causes us to treat projections as if they were
-    /// placeholders. This is only correct if the given projection cannot
-    /// be normalized in the current context. Even if normalization fails,
-    /// it may still succeed later if the projection contains any inference
-    /// variables.
     AsPlaceholder,
     AsInfer,
 }
 
+/// During fast-rejection, we have the choice of treating projection types
+/// as either simplifyable or not, depending on whether we expect the projection
+/// to be normalized/rigid.
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
+pub enum TreatProjections {
+    /// In candidates, we may be able to normalize the projection
+    /// after instantiating the candidate and equating it with a goal.
+    ///
+    /// We must assume that the `impl<T> Trait<T> for <T as Id>::This`
+    /// can apply to all self types so we don't return a simplified type
+    /// for `<T as Id>::This`.
+    DefaultCandidate,
+    /// In the old solver we don't try to normalize projections
+    /// when looking up impls and only access them by using the
+    /// current self type. This means that if the self type is
+    /// a projection which could later be normalized, we must not
+    /// treat it as rigid.
+    DefaultLookup,
+    /// We can treat projections in the self type as opaque as
+    /// we separately look up impls for the normalized self type.
+    NextSolverLookup,
+}
+
 /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
 ///
 /// **This function should only be used if you need to store or retrieve the type from some
@@ -87,6 +104,7 @@ pub fn simplify_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     treat_params: TreatParams,
+    treat_projections: TreatProjections,
 ) -> Option<SimplifiedType> {
     match *ty.kind() {
         ty::Bool => Some(BoolSimplifiedType),
@@ -118,16 +136,10 @@ pub fn simplify_type<'tcx>(
             TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType),
             TreatParams::AsInfer => None,
         },
-        ty::Alias(..) => match treat_params {
-            // When treating `ty::Param` as a placeholder, projections also
-            // don't unify with anything else as long as they are fully normalized.
-            //
-            // We will have to be careful with lazy normalization here.
-            TreatParams::AsPlaceholder if !ty.has_non_region_infer() => {
-                debug!("treating `{}` as a placeholder", ty);
-                Some(PlaceholderSimplifiedType)
-            }
-            TreatParams::AsPlaceholder | TreatParams::AsInfer => None,
+        ty::Alias(..) => match treat_projections {
+            TreatProjections::DefaultLookup if !ty.needs_infer() => Some(PlaceholderSimplifiedType),
+            TreatProjections::NextSolverLookup => Some(PlaceholderSimplifiedType),
+            TreatProjections::DefaultCandidate | TreatProjections::DefaultLookup => None,
         },
         ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
         ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 649a58c9170..dec6011fe38 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,5 +1,5 @@
 use crate::traits::specialization_graph;
-use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
+use crate::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections};
 use crate::ty::visit::TypeVisitableExt;
 use crate::ty::{Ident, Ty, TyCtxt};
 use hir::def_id::LOCAL_CRATE;
@@ -118,16 +118,32 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Iterate over every impl that could possibly match the self type `self_ty`.
     ///
     /// `trait_def_id` MUST BE the `DefId` of a trait.
-    pub fn for_each_relevant_impl<F: FnMut(DefId)>(
+    pub fn for_each_relevant_impl(
         self,
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
-        mut f: F,
+        f: impl FnMut(DefId),
     ) {
-        let _: Option<()> = self.find_map_relevant_impl(trait_def_id, self_ty, |did| {
-            f(did);
-            None
-        });
+        self.for_each_relevant_impl_treating_projections(
+            trait_def_id,
+            self_ty,
+            TreatProjections::DefaultLookup,
+            f,
+        )
+    }
+
+    pub fn for_each_relevant_impl_treating_projections(
+        self,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+        treat_projections: TreatProjections,
+        mut f: impl FnMut(DefId),
+    ) {
+        let _: Option<()> =
+            self.find_map_relevant_impl(trait_def_id, self_ty, treat_projections, |did| {
+                f(did);
+                None
+            });
     }
 
     /// `trait_def_id` MUST BE the `DefId` of a trait.
@@ -137,7 +153,12 @@ impl<'tcx> TyCtxt<'tcx> {
         self_ty: Ty<'tcx>,
     ) -> impl Iterator<Item = DefId> + 'tcx {
         let impls = self.trait_impls_of(trait_def_id);
-        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsInfer) {
+        if let Some(simp) = fast_reject::simplify_type(
+            self,
+            self_ty,
+            TreatParams::AsInfer,
+            TreatProjections::DefaultCandidate,
+        ) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 return impls.iter().copied();
             }
@@ -150,11 +171,12 @@ impl<'tcx> TyCtxt<'tcx> {
     /// the first non-none value.
     ///
     /// `trait_def_id` MUST BE the `DefId` of a trait.
-    pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
+    pub fn find_map_relevant_impl<T>(
         self,
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
-        mut f: F,
+        treat_projections: TreatProjections,
+        mut f: impl FnMut(DefId) -> Option<T>,
     ) -> Option<T> {
         // FIXME: This depends on the set of all impls for the trait. That is
         // unfortunate wrt. incremental compilation.
@@ -169,14 +191,13 @@ impl<'tcx> TyCtxt<'tcx> {
             }
         }
 
-        // Note that we're using `TreatParams::AsPlaceholder` to query `non_blanket_impls` while using
-        // `TreatParams::AsInfer` while actually adding them.
-        //
         // This way, when searching for some impl for `T: Trait`, we do not look at any impls
         // whose outer level is not a parameter or projection. Especially for things like
         // `T: Clone` this is incredibly useful as we would otherwise look at all the impls
         // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
-        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholder) {
+        if let Some(simp) =
+            fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholder, treat_projections)
+        {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 for &impl_def_id in impls {
                     if let result @ Some(_) = f(impl_def_id) {
@@ -237,9 +258,12 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
             continue;
         }
 
-        if let Some(simplified_self_ty) =
-            fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsInfer)
-        {
+        if let Some(simplified_self_ty) = fast_reject::simplify_type(
+            tcx,
+            impl_self_ty,
+            TreatParams::AsInfer,
+            TreatProjections::DefaultCandidate,
+        ) {
             impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
         } else {
             impls.blanket_impls.push(impl_def_id);
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 8b5469743da..e3e8a57caf1 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -2,6 +2,7 @@
 
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir;
+use crate::ty::fast_reject::TreatProjections;
 use crate::ty::layout::IntegerExt;
 use crate::ty::{
     self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
@@ -363,14 +364,20 @@ impl<'tcx> TyCtxt<'tcx> {
         self.ensure().coherent_trait(drop_trait);
 
         let ty = self.type_of(adt_did).subst_identity();
-        let (did, constness) = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
-            if let Some(item_id) = self.associated_item_def_ids(impl_did).first() {
-                if validate(self, impl_did).is_ok() {
-                    return Some((*item_id, self.constness(impl_did)));
+        let (did, constness) = self.find_map_relevant_impl(
+            drop_trait,
+            ty,
+            // FIXME: This could also be some other mode, like "unexpected"
+            TreatProjections::DefaultLookup,
+            |impl_did| {
+                if let Some(item_id) = self.associated_item_def_ids(impl_did).first() {
+                    if validate(self, impl_did).is_ok() {
+                        return Some((*item_id, self.constness(impl_did)));
+                    }
                 }
-            }
-            None
-        })?;
+                None
+            },
+        )?;
 
         Some(ty::Destructor { did, constness })
     }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index 72b1b35e79b..891ea0cdebe 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -8,6 +8,7 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::util::elaborate_predicates;
 use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
+use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use std::fmt::Debug;
@@ -299,9 +300,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
         let tcx = self.tcx();
-        tcx.for_each_relevant_impl(
+        tcx.for_each_relevant_impl_treating_projections(
             goal.predicate.trait_def_id(tcx),
             goal.predicate.self_ty(),
+            TreatProjections::NextSolverLookup,
             |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) {
                 Ok(result) => candidates
                     .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 0669975d638..e8696c7d0f5 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -8,7 +8,7 @@ use rustc_hir::LangItem;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::util::supertraits;
 use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
 use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
 use rustc_span::DUMMY_SP;
@@ -135,9 +135,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         // currently instead lint patterns which can be used to
         // exploit this unsoundness on stable, see #93367 for
         // more details.
+        //
+        // Using `TreatProjections::NextSolverLookup` is fine here because
+        // `instantiate_constituent_tys_for_auto_trait` returns nothing for
+        // projection types anyways. So it doesn't really matter what we do
+        // here, and this is faster.
         if let Some(def_id) = ecx.tcx().find_map_relevant_impl(
             goal.predicate.def_id(),
             goal.predicate.self_ty(),
+            TreatProjections::NextSolverLookup,
             Some,
         ) {
             debug!(?def_id, ?goal, "disqualified auto-trait implementation");
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 704b0d0bd1c..4ceec0d6a57 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -32,6 +32,7 @@ use rustc_infer::infer::{InferOk, TypeTrace};
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
 use rustc_middle::ty::{
@@ -1799,12 +1800,17 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     })
                     .and_then(|(trait_assoc_item, id)| {
                         let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
-                        self.tcx.find_map_relevant_impl(id, proj.projection_ty.self_ty(), |did| {
-                            self.tcx
-                                .associated_items(did)
-                                .in_definition_order()
-                                .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
-                        })
+                        self.tcx.find_map_relevant_impl(
+                            id,
+                            proj.projection_ty.self_ty(),
+                            TreatProjections::DefaultLookup,
+                            |did| {
+                                self.tcx
+                                    .associated_items(did)
+                                    .in_definition_order()
+                                    .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
+                            },
+                        )
                     })
                     .and_then(|item| match self.tcx.hir().get_if_local(item.def_id) {
                         Some(
@@ -2176,7 +2182,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         trait_ref: &ty::PolyTraitRef<'tcx>,
     ) -> bool {
         let get_trait_impl = |trait_def_id| {
-            self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some)
+            self.tcx.find_map_relevant_impl(
+                trait_def_id,
+                trait_ref.skip_binder().self_ty(),
+                TreatProjections::DefaultLookup,
+                Some,
+            )
         };
         let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
         let traits_with_same_path: std::collections::BTreeSet<_> = self
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index e91057356a2..4305171aa80 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -9,6 +9,7 @@ use hir::LangItem;
 use rustc_hir as hir;
 use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
+use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_target::spec::abi::Abi;
 
@@ -783,6 +784,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let relevant_impl = self.tcx().find_map_relevant_impl(
                     self.tcx().require_lang_item(LangItem::Drop, None),
                     obligation.predicate.skip_binder().trait_ref.self_ty(),
+                    TreatProjections::DefaultLookup,
                     Some,
                 );
 
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 61ed9ef2ec1..bebaa885cf7 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -3,7 +3,7 @@ use super::OverlapError;
 use crate::traits;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections};
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 
 pub use rustc_middle::traits::specialization_graph::*;
@@ -49,8 +49,12 @@ impl<'tcx> ChildrenExt<'tcx> for Children {
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
-        if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
-        {
+        if let Some(st) = fast_reject::simplify_type(
+            tcx,
+            trait_ref.self_ty(),
+            TreatParams::AsInfer,
+            fast_reject::TreatProjections::DefaultCandidate,
+        ) {
             debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
             self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
         } else {
@@ -65,8 +69,12 @@ impl<'tcx> ChildrenExt<'tcx> for Children {
     fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
         let vec: &mut Vec<DefId>;
-        if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
-        {
+        if let Some(st) = fast_reject::simplify_type(
+            tcx,
+            trait_ref.self_ty(),
+            TreatParams::AsInfer,
+            TreatProjections::DefaultCandidate,
+        ) {
             debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
             vec = self.non_blanket_impls.get_mut(&st).unwrap();
         } else {
@@ -302,7 +310,12 @@ impl<'tcx> GraphExt<'tcx> for Graph {
 
         let mut parent = trait_def_id;
         let mut last_lint = None;
-        let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer);
+        let simplified = fast_reject::simplify_type(
+            tcx,
+            trait_ref.self_ty(),
+            TreatParams::AsInfer,
+            TreatProjections::DefaultCandidate,
+        );
 
         // Descend the specialization tree, where `parent` is the current parent node.
         loop {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index bcb69d1a4ca..bd5e05770fe 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -13,7 +13,7 @@ use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{DefKind, Namespace, PerNS};
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::Mutability;
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{fast_reject::TreatProjections, Ty, TyCtxt};
 use rustc_middle::{bug, ty};
 use rustc_resolve::rustdoc::MalformedGenerics;
 use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, strip_generics_from_path};
@@ -735,7 +735,7 @@ fn trait_impls_for<'a>(
         trace!("considering explicit impl for trait {:?}", trait_);
 
         // Look at each trait implementation to see if it's an impl for `did`
-        tcx.find_map_relevant_impl(trait_, ty, |impl_| {
+        tcx.find_map_relevant_impl(trait_, ty, TreatProjections::DefaultLookup, |impl_| {
             let trait_ref = tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
             // Check if these are the same type.
             let impl_type = trait_ref.skip_binder().self_ty();
diff --git a/tests/ui/traits/new-solver/runaway-impl-candidate-selection.rs b/tests/ui/traits/new-solver/runaway-impl-candidate-selection.rs
new file mode 100644
index 00000000000..1dca86d3630
--- /dev/null
+++ b/tests/ui/traits/new-solver/runaway-impl-candidate-selection.rs
@@ -0,0 +1,15 @@
+// compile-flags: -Ztrait-solver=next
+
+// In the new solver, we are trying to select `<?0 as Iterator>::Item: Debug`,
+// which, naively can be unified with every impl of `Debug` if we're not careful.
+// This test makes sure that we treat projections with inference var substs as
+// placeholders during fast reject.
+
+fn iter<T: Iterator>() -> <T as Iterator>::Item {
+    todo!()
+}
+
+fn main() {
+    println!("{:?}", iter::<_>());
+    //~^ ERROR type annotations needed
+}
diff --git a/tests/ui/traits/new-solver/runaway-impl-candidate-selection.stderr b/tests/ui/traits/new-solver/runaway-impl-candidate-selection.stderr
new file mode 100644
index 00000000000..47004821ad7
--- /dev/null
+++ b/tests/ui/traits/new-solver/runaway-impl-candidate-selection.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/runaway-impl-candidate-selection.rs:13:22
+   |
+LL |     println!("{:?}", iter::<_>());
+   |                      ^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `iter`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.