Skip to content

Commit c32527f

Browse files
Treat projections with infer as placeholder during fast reject in new solver
1 parent f1b1ed7 commit c32527f

File tree

15 files changed

+186
-68
lines changed

15 files changed

+186
-68
lines changed

compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_errors::struct_span_err;
1111
use rustc_hir as hir;
1212
use rustc_hir::def::DefKind;
1313
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
14-
use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
14+
use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams, TreatProjections};
1515
use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
1616
use rustc_span::symbol::sym;
1717

@@ -99,7 +99,12 @@ impl<'tcx> InherentCollect<'tcx> {
9999
}
100100
}
101101

102-
if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) {
102+
if let Some(simp) = simplify_type(
103+
self.tcx,
104+
self_ty,
105+
TreatParams::AsInfer,
106+
TreatProjections::DefaultCandidate,
107+
) {
103108
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
104109
} else {
105110
bug!("unexpected self type: {:?}", self_ty);
@@ -159,7 +164,9 @@ impl<'tcx> InherentCollect<'tcx> {
159164
}
160165
}
161166

162-
if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsInfer) {
167+
if let Some(simp) =
168+
simplify_type(self.tcx, ty, TreatParams::AsInfer, TreatProjections::DefaultCandidate)
169+
{
163170
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
164171
} else {
165172
bug!("unexpected primitive type: {:?}", ty);

compiler/rustc_hir_typeck/src/method/probe.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_infer::infer::canonical::OriginalQueryValues;
1515
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
1616
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
1717
use rustc_middle::middle::stability;
18+
use rustc_middle::ty::fast_reject::TreatProjections;
1819
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
1920
use rustc_middle::ty::AssocItem;
2021
use rustc_middle::ty::GenericParamDefKind;
@@ -699,7 +700,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
699700
}
700701

701702
fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
702-
let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) else {
703+
let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer, TreatProjections::DefaultCandidate) else {
703704
bug!("unexpected incoherent type: {:?}", self_ty)
704705
};
705706
for &impl_def_id in self.tcx.incoherent_impls(simp) {

compiler/rustc_hir_typeck/src/method/suggest.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use rustc_infer::infer::{
2525
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
2626
use rustc_middle::traits::util::supertraits;
2727
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
28+
use rustc_middle::ty::fast_reject::TreatProjections;
2829
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
2930
use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
3031
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
@@ -1516,7 +1517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15161517
.into_iter()
15171518
.any(|info| self.associated_value(info.def_id, item_name).is_some());
15181519
let found_assoc = |ty: Ty<'tcx>| {
1519-
simplify_type(tcx, ty, TreatParams::AsInfer)
1520+
simplify_type(tcx, ty, TreatParams::AsInfer, TreatProjections::DefaultCandidate)
15201521
.and_then(|simp| {
15211522
tcx.incoherent_impls(simp)
15221523
.iter()
@@ -2645,9 +2646,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26452646
// FIXME: Even though negative bounds are not implemented, we could maybe handle
26462647
// cases where a positive bound implies a negative impl.
26472648
(candidates, Vec::new())
2648-
} else if let Some(simp_rcvr_ty) =
2649-
simplify_type(self.tcx, rcvr_ty, TreatParams::AsPlaceholder)
2650-
{
2649+
} else if let Some(simp_rcvr_ty) = simplify_type(
2650+
self.tcx,
2651+
rcvr_ty,
2652+
TreatParams::AsPlaceholder,
2653+
TreatProjections::DefaultLookup,
2654+
) {
26512655
let mut potential_candidates = Vec::new();
26522656
let mut explicitly_negative = Vec::new();
26532657
for candidate in candidates {
@@ -2660,8 +2664,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26602664
})
26612665
.any(|imp_did| {
26622666
let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
2663-
let imp_simp =
2664-
simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
2667+
let imp_simp = simplify_type(
2668+
self.tcx,
2669+
imp.self_ty(),
2670+
TreatParams::AsPlaceholder,
2671+
TreatProjections::DefaultLookup,
2672+
);
26652673
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
26662674
})
26672675
{

compiler/rustc_metadata/src/rmeta/encoder.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_middle::middle::exported_symbols::{
2626
use rustc_middle::mir::interpret;
2727
use rustc_middle::traits::specialization_graph;
2828
use rustc_middle::ty::codec::TyEncoder;
29-
use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
29+
use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections};
3030
use rustc_middle::ty::query::Providers;
3131
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
3232
use rustc_middle::util::common::to_readable_str;
@@ -1859,6 +1859,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
18591859
self.tcx,
18601860
trait_ref.self_ty(),
18611861
TreatParams::AsInfer,
1862+
TreatProjections::DefaultCandidate,
18621863
);
18631864

18641865
fx_hash_map

compiler/rustc_middle/src/ty/fast_reject.rs

+28-16
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,33 @@ pub enum SimplifiedType {
5252
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
5353
pub enum TreatParams {
5454
/// Treat parameters as placeholders in the given environment.
55-
///
56-
/// Note that this also causes us to treat projections as if they were
57-
/// placeholders. This is only correct if the given projection cannot
58-
/// be normalized in the current context. Even if normalization fails,
59-
/// it may still succeed later if the projection contains any inference
60-
/// variables.
6155
AsPlaceholder,
6256
AsInfer,
6357
}
6458

59+
/// During fast-rejection, we have the choice of treating projection types
60+
/// as either simplifyable or not, depending on whether we expect the projection
61+
/// to be normalized/rigid.
62+
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
63+
pub enum TreatProjections {
64+
/// In candidates, we may be able to normalize the projection
65+
/// after instantiating the candidate and equating it with a goal.
66+
///
67+
/// We must assume that the `impl<T> Trait<T> for <T as Id>::This`
68+
/// can apply to all self types so we don't return a simplified type
69+
/// for `<T as Id>::This`.
70+
DefaultCandidate,
71+
/// In the old solver we don't try to normalize projections
72+
/// when looking up impls and only access them by using the
73+
/// current self type. This means that if the self type is
74+
/// a projection which could later be normalized, we must not
75+
/// treat it as rigid.
76+
DefaultLookup,
77+
/// We can treat projections in the self type as opaque as
78+
/// we separately look up impls for the normalized self type.
79+
NextSolverLookup,
80+
}
81+
6582
/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
6683
///
6784
/// **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>(
87104
tcx: TyCtxt<'tcx>,
88105
ty: Ty<'tcx>,
89106
treat_params: TreatParams,
107+
treat_projections: TreatProjections,
90108
) -> Option<SimplifiedType> {
91109
match *ty.kind() {
92110
ty::Bool => Some(BoolSimplifiedType),
@@ -118,16 +136,10 @@ pub fn simplify_type<'tcx>(
118136
TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType),
119137
TreatParams::AsInfer => None,
120138
},
121-
ty::Alias(..) => match treat_params {
122-
// When treating `ty::Param` as a placeholder, projections also
123-
// don't unify with anything else as long as they are fully normalized.
124-
//
125-
// We will have to be careful with lazy normalization here.
126-
TreatParams::AsPlaceholder if !ty.has_non_region_infer() => {
127-
debug!("treating `{}` as a placeholder", ty);
128-
Some(PlaceholderSimplifiedType)
129-
}
130-
TreatParams::AsPlaceholder | TreatParams::AsInfer => None,
139+
ty::Alias(..) => match treat_projections {
140+
TreatProjections::DefaultLookup if !ty.needs_infer() => Some(PlaceholderSimplifiedType),
141+
TreatProjections::NextSolverLookup => Some(PlaceholderSimplifiedType),
142+
TreatProjections::DefaultCandidate | TreatProjections::DefaultLookup => None,
131143
},
132144
ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
133145
ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,

compiler/rustc_middle/src/ty/trait_def.rs

+41-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::traits::specialization_graph;
2-
use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
2+
use crate::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections};
33
use crate::ty::visit::TypeVisitableExt;
44
use crate::ty::{Ident, Ty, TyCtxt};
55
use hir::def_id::LOCAL_CRATE;
@@ -118,16 +118,32 @@ impl<'tcx> TyCtxt<'tcx> {
118118
/// Iterate over every impl that could possibly match the self type `self_ty`.
119119
///
120120
/// `trait_def_id` MUST BE the `DefId` of a trait.
121-
pub fn for_each_relevant_impl<F: FnMut(DefId)>(
121+
pub fn for_each_relevant_impl(
122122
self,
123123
trait_def_id: DefId,
124124
self_ty: Ty<'tcx>,
125-
mut f: F,
125+
f: impl FnMut(DefId),
126126
) {
127-
let _: Option<()> = self.find_map_relevant_impl(trait_def_id, self_ty, |did| {
128-
f(did);
129-
None
130-
});
127+
self.for_each_relevant_impl_treating_projections(
128+
trait_def_id,
129+
self_ty,
130+
TreatProjections::DefaultLookup,
131+
f,
132+
)
133+
}
134+
135+
pub fn for_each_relevant_impl_treating_projections(
136+
self,
137+
trait_def_id: DefId,
138+
self_ty: Ty<'tcx>,
139+
treat_projections: TreatProjections,
140+
mut f: impl FnMut(DefId),
141+
) {
142+
let _: Option<()> =
143+
self.find_map_relevant_impl(trait_def_id, self_ty, treat_projections, |did| {
144+
f(did);
145+
None
146+
});
131147
}
132148

133149
/// `trait_def_id` MUST BE the `DefId` of a trait.
@@ -137,7 +153,12 @@ impl<'tcx> TyCtxt<'tcx> {
137153
self_ty: Ty<'tcx>,
138154
) -> impl Iterator<Item = DefId> + 'tcx {
139155
let impls = self.trait_impls_of(trait_def_id);
140-
if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsInfer) {
156+
if let Some(simp) = fast_reject::simplify_type(
157+
self,
158+
self_ty,
159+
TreatParams::AsInfer,
160+
TreatProjections::DefaultCandidate,
161+
) {
141162
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
142163
return impls.iter().copied();
143164
}
@@ -150,11 +171,12 @@ impl<'tcx> TyCtxt<'tcx> {
150171
/// the first non-none value.
151172
///
152173
/// `trait_def_id` MUST BE the `DefId` of a trait.
153-
pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
174+
pub fn find_map_relevant_impl<T>(
154175
self,
155176
trait_def_id: DefId,
156177
self_ty: Ty<'tcx>,
157-
mut f: F,
178+
treat_projections: TreatProjections,
179+
mut f: impl FnMut(DefId) -> Option<T>,
158180
) -> Option<T> {
159181
// FIXME: This depends on the set of all impls for the trait. That is
160182
// unfortunate wrt. incremental compilation.
@@ -169,14 +191,13 @@ impl<'tcx> TyCtxt<'tcx> {
169191
}
170192
}
171193

172-
// Note that we're using `TreatParams::AsPlaceholder` to query `non_blanket_impls` while using
173-
// `TreatParams::AsInfer` while actually adding them.
174-
//
175194
// This way, when searching for some impl for `T: Trait`, we do not look at any impls
176195
// whose outer level is not a parameter or projection. Especially for things like
177196
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
178197
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
179-
if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholder) {
198+
if let Some(simp) =
199+
fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholder, treat_projections)
200+
{
180201
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
181202
for &impl_def_id in impls {
182203
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
237258
continue;
238259
}
239260

240-
if let Some(simplified_self_ty) =
241-
fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsInfer)
242-
{
261+
if let Some(simplified_self_ty) = fast_reject::simplify_type(
262+
tcx,
263+
impl_self_ty,
264+
TreatParams::AsInfer,
265+
TreatProjections::DefaultCandidate,
266+
) {
243267
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
244268
} else {
245269
impls.blanket_impls.push(impl_def_id);

compiler/rustc_middle/src/ty/util.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
44
use crate::mir;
5+
use crate::ty::fast_reject::TreatProjections;
56
use crate::ty::layout::IntegerExt;
67
use crate::ty::{
78
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
@@ -363,14 +364,20 @@ impl<'tcx> TyCtxt<'tcx> {
363364
self.ensure().coherent_trait(drop_trait);
364365

365366
let ty = self.type_of(adt_did).subst_identity();
366-
let (did, constness) = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
367-
if let Some(item_id) = self.associated_item_def_ids(impl_did).first() {
368-
if validate(self, impl_did).is_ok() {
369-
return Some((*item_id, self.constness(impl_did)));
367+
let (did, constness) = self.find_map_relevant_impl(
368+
drop_trait,
369+
ty,
370+
// FIXME: This could also be some other mode, like "unexpected"
371+
TreatProjections::DefaultLookup,
372+
|impl_did| {
373+
if let Some(item_id) = self.associated_item_def_ids(impl_did).first() {
374+
if validate(self, impl_did).is_ok() {
375+
return Some((*item_id, self.constness(impl_did)));
376+
}
370377
}
371-
}
372-
None
373-
})?;
378+
None
379+
},
380+
)?;
374381

375382
Some(ty::Destructor { did, constness })
376383
}

compiler/rustc_trait_selection/src/solve/assembly.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_hir::def_id::DefId;
88
use rustc_infer::traits::query::NoSolution;
99
use rustc_infer::traits::util::elaborate_predicates;
1010
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
11+
use rustc_middle::ty::fast_reject::TreatProjections;
1112
use rustc_middle::ty::TypeFoldable;
1213
use rustc_middle::ty::{self, Ty, TyCtxt};
1314
use std::fmt::Debug;
@@ -299,9 +300,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
299300
candidates: &mut Vec<Candidate<'tcx>>,
300301
) {
301302
let tcx = self.tcx();
302-
tcx.for_each_relevant_impl(
303+
tcx.for_each_relevant_impl_treating_projections(
303304
goal.predicate.trait_def_id(tcx),
304305
goal.predicate.self_ty(),
306+
TreatProjections::NextSolverLookup,
305307
|impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) {
306308
Ok(result) => candidates
307309
.push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_hir::LangItem;
88
use rustc_infer::traits::query::NoSolution;
99
use rustc_infer::traits::util::supertraits;
1010
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
11-
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
11+
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
1212
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
1313
use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
1414
use rustc_span::DUMMY_SP;
@@ -135,9 +135,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
135135
// currently instead lint patterns which can be used to
136136
// exploit this unsoundness on stable, see #93367 for
137137
// more details.
138+
//
139+
// Using `TreatProjections::NextSolverLookup` is fine here because
140+
// `instantiate_constituent_tys_for_auto_trait` returns nothing for
141+
// projection types anyways. So it doesn't really matter what we do
142+
// here, and this is faster.
138143
if let Some(def_id) = ecx.tcx().find_map_relevant_impl(
139144
goal.predicate.def_id(),
140145
goal.predicate.self_ty(),
146+
TreatProjections::NextSolverLookup,
141147
Some,
142148
) {
143149
debug!(?def_id, ?goal, "disqualified auto-trait implementation");

0 commit comments

Comments
 (0)