mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Rollup merge of #108830 - compiler-errors:new-solver-fast-reject-faster, r=lcnr
Treat projections with infer as placeholder during fast reject in new solver r? ``@lcnr`` Kind of a shame that we need to change all of the call sites for `for_each_relevant_impl`, etc. to pass an extra parameter. I guess I could have the "default" fn which calls a configurable fn?
This commit is contained in:
commit
6cec8cb5c2
@ -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::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
) {
|
||||
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
|
||||
} else {
|
||||
bug!("unexpected self type: {:?}", self_ty);
|
||||
@ -159,7 +164,12 @@ 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::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
) {
|
||||
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
|
||||
} else {
|
||||
bug!("unexpected primitive type: {:?}", ty);
|
||||
|
@ -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::AsCandidateKey, TreatProjections::AsCandidateKey) else {
|
||||
bug!("unexpected incoherent type: {:?}", self_ty)
|
||||
};
|
||||
for &impl_def_id in self.tcx.incoherent_impls(simp) {
|
||||
|
@ -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};
|
||||
@ -1257,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let target_ty = self
|
||||
.autoderef(sugg_span, rcvr_ty)
|
||||
.find(|(rcvr_ty, _)| {
|
||||
DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }
|
||||
DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey }
|
||||
.types_may_unify(*rcvr_ty, impl_ty)
|
||||
})
|
||||
.map_or(impl_ty, |(ty, _)| ty)
|
||||
@ -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::AsCandidateKey, TreatProjections::AsCandidateKey)
|
||||
.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::ForLookup,
|
||||
TreatProjections::ForLookup,
|
||||
) {
|
||||
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::ForLookup,
|
||||
TreatProjections::ForLookup,
|
||||
);
|
||||
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
|
||||
})
|
||||
{
|
||||
|
@ -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;
|
||||
@ -1858,7 +1858,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
let simplified_self_ty = fast_reject::simplify_type(
|
||||
self.tcx,
|
||||
trait_ref.self_ty(),
|
||||
TreatParams::AsInfer,
|
||||
TreatParams::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
);
|
||||
|
||||
fx_hash_map
|
||||
|
@ -51,15 +51,35 @@ pub enum SimplifiedType {
|
||||
/// generic parameters as if they were inference variables in that case.
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum TreatParams {
|
||||
/// Treat parameters as placeholders in the given environment.
|
||||
/// Treat parameters as infer vars. This is the correct mode for caching
|
||||
/// an impl's type for lookup.
|
||||
AsCandidateKey,
|
||||
/// Treat parameters as placeholders in the given environment. This is the
|
||||
/// correct mode for *lookup*, as during candidate selection.
|
||||
ForLookup,
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// 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,
|
||||
/// 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`.
|
||||
AsCandidateKey,
|
||||
/// 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.
|
||||
ForLookup,
|
||||
/// 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.
|
||||
@ -87,6 +107,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),
|
||||
@ -115,19 +136,13 @@ pub fn simplify_type<'tcx>(
|
||||
ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
|
||||
ty::Placeholder(..) => Some(PlaceholderSimplifiedType),
|
||||
ty::Param(_) => match treat_params {
|
||||
TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType),
|
||||
TreatParams::AsInfer => None,
|
||||
TreatParams::ForLookup => Some(PlaceholderSimplifiedType),
|
||||
TreatParams::AsCandidateKey => 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::ForLookup if !ty.needs_infer() => Some(PlaceholderSimplifiedType),
|
||||
TreatProjections::NextSolverLookup => Some(PlaceholderSimplifiedType),
|
||||
TreatProjections::AsCandidateKey | TreatProjections::ForLookup => None,
|
||||
},
|
||||
ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
|
||||
ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
|
||||
@ -295,8 +310,8 @@ impl DeepRejectCtxt {
|
||||
// Depending on the value of `treat_obligation_params`, we either
|
||||
// treat generic parameters like placeholders or like inference variables.
|
||||
ty::Param(_) => match self.treat_obligation_params {
|
||||
TreatParams::AsPlaceholder => false,
|
||||
TreatParams::AsInfer => true,
|
||||
TreatParams::ForLookup => false,
|
||||
TreatParams::AsCandidateKey => true,
|
||||
},
|
||||
|
||||
ty::Infer(_) => true,
|
||||
@ -333,8 +348,8 @@ impl DeepRejectCtxt {
|
||||
let k = impl_ct.kind();
|
||||
match obligation_ct.kind() {
|
||||
ty::ConstKind::Param(_) => match self.treat_obligation_params {
|
||||
TreatParams::AsPlaceholder => false,
|
||||
TreatParams::AsInfer => true,
|
||||
TreatParams::ForLookup => false,
|
||||
TreatParams::AsCandidateKey => true,
|
||||
},
|
||||
|
||||
// As we don't necessarily eagerly evaluate constants,
|
||||
|
@ -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::ForLookup,
|
||||
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::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
) {
|
||||
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::ForLookup, 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::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
) {
|
||||
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
|
||||
} else {
|
||||
impls.blanket_impls.push(impl_def_id);
|
||||
|
@ -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::ForLookup,
|
||||
|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 })
|
||||
}
|
||||
|
@ -2215,7 +2215,7 @@ impl CheckAttrVisitor<'_> {
|
||||
// `fn(TokenStream) -> TokenStream` after some substitution of generic arguments.
|
||||
//
|
||||
// Properly checking this means pulling in additional `rustc` crates, so we don't.
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer };
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey };
|
||||
|
||||
if sig.abi != Abi::Rust {
|
||||
tcx.sess.emit_err(errors::ProcMacroInvalidAbi {
|
||||
|
@ -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 }),
|
||||
|
@ -184,7 +184,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||
|
||||
let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
|
||||
if iter::zip(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs)
|
||||
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
|
||||
{
|
||||
|
@ -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;
|
||||
@ -36,7 +36,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
let tcx = ecx.tcx();
|
||||
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
|
||||
if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs)
|
||||
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
|
||||
{
|
||||
@ -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");
|
||||
|
@ -75,7 +75,7 @@ pub fn overlapping_impls(
|
||||
// Before doing expensive operations like entering an inference context, do
|
||||
// a quick check via fast_reject to tell if the impl headers could possibly
|
||||
// unify.
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer };
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey };
|
||||
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
|
||||
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
|
||||
let may_overlap = match (impl1_ref, impl2_ref) {
|
||||
|
@ -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::ForLookup,
|
||||
|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::ForLookup,
|
||||
Some,
|
||||
)
|
||||
};
|
||||
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
|
||||
let traits_with_same_path: std::collections::BTreeSet<_> = self
|
||||
|
@ -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::ForLookup,
|
||||
Some,
|
||||
);
|
||||
|
||||
|
@ -2558,7 +2558,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
// We can avoid creating type variables and doing the full
|
||||
// substitution if we find that any of the input types, when
|
||||
// simplified, do not match.
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
|
||||
iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs)
|
||||
.any(|(obl, imp)| !drcx.generic_args_may_unify(obl, imp))
|
||||
}
|
||||
|
@ -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::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
) {
|
||||
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::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
) {
|
||||
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::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
);
|
||||
|
||||
// Descend the specialization tree, where `parent` is the current parent node.
|
||||
loop {
|
||||
|
@ -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::ForLookup, |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();
|
||||
|
@ -0,0 +1,43 @@
|
||||
// check-pass
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
// Issue 96230
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
trait Classic {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Gat {
|
||||
type Assoc<'a>;
|
||||
}
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Classic for Foo {
|
||||
type Assoc = ();
|
||||
}
|
||||
|
||||
impl Gat for Foo {
|
||||
type Assoc<'i> = ();
|
||||
}
|
||||
|
||||
fn classic_debug<T: Classic>(_: T)
|
||||
where
|
||||
T::Assoc: Debug,
|
||||
{
|
||||
}
|
||||
|
||||
fn gat_debug<T: Gat>(_: T)
|
||||
where
|
||||
for<'a> T::Assoc<'a>: Debug,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
classic_debug::<Foo>(Foo); // fine
|
||||
classic_debug(Foo); // fine
|
||||
|
||||
gat_debug::<Foo>(Foo); // fine
|
||||
gat_debug(Foo); // boom
|
||||
}
|
@ -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
|
||||
}
|
@ -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`.
|
Loading…
Reference in New Issue
Block a user