1
Fork 0

Treat projections with infer as placeholder during fast reject in new solver

This commit is contained in:
Michael Goulet 2023-03-07 04:39:17 +00:00
parent f1b1ed7e18
commit c32527fb92
15 changed files with 186 additions and 68 deletions

View file

@ -11,7 +11,7 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; 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_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
use rustc_span::symbol::sym; 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); self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
} else { } else {
bug!("unexpected self type: {:?}", self_ty); 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); self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
} else { } else {
bug!("unexpected primitive type: {:?}", ty); bug!("unexpected primitive type: {:?}", ty);

View file

@ -15,6 +15,7 @@ use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::middle::stability; 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::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::AssocItem; use rustc_middle::ty::AssocItem;
use rustc_middle::ty::GenericParamDefKind; 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>) { 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) bug!("unexpected incoherent type: {:?}", self_ty)
}; };
for &impl_def_id in self.tcx.incoherent_impls(simp) { for &impl_def_id in self.tcx.incoherent_impls(simp) {

View file

@ -25,6 +25,7 @@ use rustc_infer::infer::{
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::traits::util::supertraits; use rustc_middle::traits::util::supertraits;
use rustc_middle::ty::fast_reject::DeepRejectCtxt; 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::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths}; use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
@ -1516,7 +1517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.into_iter() .into_iter()
.any(|info| self.associated_value(info.def_id, item_name).is_some()); .any(|info| self.associated_value(info.def_id, item_name).is_some());
let found_assoc = |ty: Ty<'tcx>| { let found_assoc = |ty: Ty<'tcx>| {
simplify_type(tcx, ty, TreatParams::AsInfer) simplify_type(tcx, ty, TreatParams::AsInfer, TreatProjections::DefaultCandidate)
.and_then(|simp| { .and_then(|simp| {
tcx.incoherent_impls(simp) tcx.incoherent_impls(simp)
.iter() .iter()
@ -2645,9 +2646,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// FIXME: Even though negative bounds are not implemented, we could maybe handle // FIXME: Even though negative bounds are not implemented, we could maybe handle
// cases where a positive bound implies a negative impl. // cases where a positive bound implies a negative impl.
(candidates, Vec::new()) (candidates, Vec::new())
} else if let Some(simp_rcvr_ty) = } else if let Some(simp_rcvr_ty) = simplify_type(
simplify_type(self.tcx, rcvr_ty, TreatParams::AsPlaceholder) self.tcx,
{ rcvr_ty,
TreatParams::AsPlaceholder,
TreatProjections::DefaultLookup,
) {
let mut potential_candidates = Vec::new(); let mut potential_candidates = Vec::new();
let mut explicitly_negative = Vec::new(); let mut explicitly_negative = Vec::new();
for candidate in candidates { for candidate in candidates {
@ -2660,8 +2664,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}) })
.any(|imp_did| { .any(|imp_did| {
let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity(); let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
let imp_simp = let imp_simp = simplify_type(
simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder); self.tcx,
imp.self_ty(),
TreatParams::AsPlaceholder,
TreatProjections::DefaultLookup,
);
imp_simp.map_or(false, |s| s == simp_rcvr_ty) imp_simp.map_or(false, |s| s == simp_rcvr_ty)
}) })
{ {

View file

@ -26,7 +26,7 @@ use rustc_middle::middle::exported_symbols::{
use rustc_middle::mir::interpret; use rustc_middle::mir::interpret;
use rustc_middle::traits::specialization_graph; use rustc_middle::traits::specialization_graph;
use rustc_middle::ty::codec::TyEncoder; 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::query::Providers;
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
use rustc_middle::util::common::to_readable_str; use rustc_middle::util::common::to_readable_str;
@ -1859,6 +1859,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.tcx, self.tcx,
trait_ref.self_ty(), trait_ref.self_ty(),
TreatParams::AsInfer, TreatParams::AsInfer,
TreatProjections::DefaultCandidate,
); );
fx_hash_map fx_hash_map

View file

@ -52,16 +52,33 @@ pub enum SimplifiedType {
#[derive(PartialEq, Eq, Debug, Clone, Copy)] #[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum TreatParams { pub enum TreatParams {
/// Treat parameters as placeholders in the given environment. /// 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, AsPlaceholder,
AsInfer, 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. /// 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 /// **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>, tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
treat_params: TreatParams, treat_params: TreatParams,
treat_projections: TreatProjections,
) -> Option<SimplifiedType> { ) -> Option<SimplifiedType> {
match *ty.kind() { match *ty.kind() {
ty::Bool => Some(BoolSimplifiedType), ty::Bool => Some(BoolSimplifiedType),
@ -118,16 +136,10 @@ pub fn simplify_type<'tcx>(
TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType), TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType),
TreatParams::AsInfer => None, TreatParams::AsInfer => None,
}, },
ty::Alias(..) => match treat_params { ty::Alias(..) => match treat_projections {
// When treating `ty::Param` as a placeholder, projections also TreatProjections::DefaultLookup if !ty.needs_infer() => Some(PlaceholderSimplifiedType),
// don't unify with anything else as long as they are fully normalized. TreatProjections::NextSolverLookup => Some(PlaceholderSimplifiedType),
// TreatProjections::DefaultCandidate | TreatProjections::DefaultLookup => None,
// 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::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)), ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,

View file

@ -1,5 +1,5 @@
use crate::traits::specialization_graph; 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::visit::TypeVisitableExt;
use crate::ty::{Ident, Ty, TyCtxt}; use crate::ty::{Ident, Ty, TyCtxt};
use hir::def_id::LOCAL_CRATE; 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`. /// Iterate over every impl that could possibly match the self type `self_ty`.
/// ///
/// `trait_def_id` MUST BE the `DefId` of a trait. /// `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, self,
trait_def_id: DefId, trait_def_id: DefId,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
mut f: F, f: impl FnMut(DefId),
) { ) {
let _: Option<()> = self.find_map_relevant_impl(trait_def_id, self_ty, |did| { self.for_each_relevant_impl_treating_projections(
f(did); trait_def_id,
None 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. /// `trait_def_id` MUST BE the `DefId` of a trait.
@ -137,7 +153,12 @@ impl<'tcx> TyCtxt<'tcx> {
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
) -> impl Iterator<Item = DefId> + 'tcx { ) -> impl Iterator<Item = DefId> + 'tcx {
let impls = self.trait_impls_of(trait_def_id); 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) { if let Some(impls) = impls.non_blanket_impls.get(&simp) {
return impls.iter().copied(); return impls.iter().copied();
} }
@ -150,11 +171,12 @@ impl<'tcx> TyCtxt<'tcx> {
/// the first non-none value. /// the first non-none value.
/// ///
/// `trait_def_id` MUST BE the `DefId` of a trait. /// `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, self,
trait_def_id: DefId, trait_def_id: DefId,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
mut f: F, treat_projections: TreatProjections,
mut f: impl FnMut(DefId) -> Option<T>,
) -> Option<T> { ) -> Option<T> {
// FIXME: This depends on the set of all impls for the trait. That is // FIXME: This depends on the set of all impls for the trait. That is
// unfortunate wrt. incremental compilation. // 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 // 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 // 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 // `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. // 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) { if let Some(impls) = impls.non_blanket_impls.get(&simp) {
for &impl_def_id in impls { for &impl_def_id in impls {
if let result @ Some(_) = f(impl_def_id) { 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; continue;
} }
if let Some(simplified_self_ty) = if let Some(simplified_self_ty) = fast_reject::simplify_type(
fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsInfer) tcx,
{ impl_self_ty,
TreatParams::AsInfer,
TreatProjections::DefaultCandidate,
) {
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
} else { } else {
impls.blanket_impls.push(impl_def_id); impls.blanket_impls.push(impl_def_id);

View file

@ -2,6 +2,7 @@
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir; use crate::mir;
use crate::ty::fast_reject::TreatProjections;
use crate::ty::layout::IntegerExt; use crate::ty::layout::IntegerExt;
use crate::ty::{ use crate::ty::{
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
@ -363,14 +364,20 @@ impl<'tcx> TyCtxt<'tcx> {
self.ensure().coherent_trait(drop_trait); self.ensure().coherent_trait(drop_trait);
let ty = self.type_of(adt_did).subst_identity(); let ty = self.type_of(adt_did).subst_identity();
let (did, constness) = self.find_map_relevant_impl(drop_trait, ty, |impl_did| { let (did, constness) = self.find_map_relevant_impl(
if let Some(item_id) = self.associated_item_def_ids(impl_did).first() { drop_trait,
if validate(self, impl_did).is_ok() { ty,
return Some((*item_id, self.constness(impl_did))); // 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 }) Some(ty::Destructor { did, constness })
} }

View file

@ -8,6 +8,7 @@ use rustc_hir::def_id::DefId;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::util::elaborate_predicates; use rustc_infer::traits::util::elaborate_predicates;
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult}; 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::TypeFoldable;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use std::fmt::Debug; use std::fmt::Debug;
@ -299,9 +300,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
candidates: &mut Vec<Candidate<'tcx>>, candidates: &mut Vec<Candidate<'tcx>>,
) { ) {
let tcx = self.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.trait_def_id(tcx),
goal.predicate.self_ty(), goal.predicate.self_ty(),
TreatProjections::NextSolverLookup,
|impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) { |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) {
Ok(result) => candidates Ok(result) => candidates
.push(Candidate { source: CandidateSource::Impl(impl_def_id), result }), .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),

View file

@ -8,7 +8,7 @@ use rustc_hir::LangItem;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::util::supertraits; use rustc_infer::traits::util::supertraits;
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult}; 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::{self, ToPredicate, Ty, TyCtxt};
use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
use rustc_span::DUMMY_SP; 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 // currently instead lint patterns which can be used to
// exploit this unsoundness on stable, see #93367 for // exploit this unsoundness on stable, see #93367 for
// more details. // 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( if let Some(def_id) = ecx.tcx().find_map_relevant_impl(
goal.predicate.def_id(), goal.predicate.def_id(),
goal.predicate.self_ty(), goal.predicate.self_ty(),
TreatProjections::NextSolverLookup,
Some, Some,
) { ) {
debug!(?def_id, ?goal, "disqualified auto-trait implementation"); debug!(?def_id, ?goal, "disqualified auto-trait implementation");

View file

@ -32,6 +32,7 @@ use rustc_infer::infer::{InferOk, TypeTrace};
use rustc_middle::traits::select::OverflowError; use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; 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::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print}; use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
use rustc_middle::ty::{ use rustc_middle::ty::{
@ -1799,12 +1800,17 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}) })
.and_then(|(trait_assoc_item, id)| { .and_then(|(trait_assoc_item, id)| {
let trait_assoc_ident = trait_assoc_item.ident(self.tcx); 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.find_map_relevant_impl(
self.tcx id,
.associated_items(did) proj.projection_ty.self_ty(),
.in_definition_order() TreatProjections::DefaultLookup,
.find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident) |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) { .and_then(|item| match self.tcx.hir().get_if_local(item.def_id) {
Some( Some(
@ -2176,7 +2182,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
trait_ref: &ty::PolyTraitRef<'tcx>, trait_ref: &ty::PolyTraitRef<'tcx>,
) -> bool { ) -> bool {
let get_trait_impl = |trait_def_id| { 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 required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
let traits_with_same_path: std::collections::BTreeSet<_> = self let traits_with_same_path: std::collections::BTreeSet<_> = self

View file

@ -9,6 +9,7 @@ use hir::LangItem;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_infer::traits::ObligationCause; use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
use rustc_middle::ty::fast_reject::TreatProjections;
use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_target::spec::abi::Abi; 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( let relevant_impl = self.tcx().find_map_relevant_impl(
self.tcx().require_lang_item(LangItem::Drop, None), self.tcx().require_lang_item(LangItem::Drop, None),
obligation.predicate.skip_binder().trait_ref.self_ty(), obligation.predicate.skip_binder().trait_ref.self_ty(),
TreatProjections::DefaultLookup,
Some, Some,
); );

View file

@ -3,7 +3,7 @@ use super::OverlapError;
use crate::traits; use crate::traits;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId; 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}; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
pub use rustc_middle::traits::specialization_graph::*; 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. /// 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) { 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(); 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); debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
self.non_blanket_impls.entry(st).or_default().push(impl_def_id) self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
} else { } else {
@ -65,8 +69,12 @@ impl<'tcx> ChildrenExt<'tcx> for Children {
fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { 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 trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
let vec: &mut Vec<DefId>; 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); debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
vec = self.non_blanket_impls.get_mut(&st).unwrap(); vec = self.non_blanket_impls.get_mut(&st).unwrap();
} else { } else {
@ -302,7 +310,12 @@ impl<'tcx> GraphExt<'tcx> for Graph {
let mut parent = trait_def_id; let mut parent = trait_def_id;
let mut last_lint = None; 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. // Descend the specialization tree, where `parent` is the current parent node.
loop { loop {

View file

@ -13,7 +13,7 @@ use rustc_hir::def::Namespace::*;
use rustc_hir::def::{DefKind, Namespace, PerNS}; use rustc_hir::def::{DefKind, Namespace, PerNS};
use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_hir::Mutability; 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_middle::{bug, ty};
use rustc_resolve::rustdoc::MalformedGenerics; use rustc_resolve::rustdoc::MalformedGenerics;
use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, strip_generics_from_path}; 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_); trace!("considering explicit impl for trait {:?}", trait_);
// Look at each trait implementation to see if it's an impl for `did` // 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"); let trait_ref = tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
// Check if these are the same type. // Check if these are the same type.
let impl_type = trait_ref.skip_binder().self_ty(); let impl_type = trait_ref.skip_binder().self_ty();

View file

@ -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
}

View file

@ -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`.