Skip to content

Commit 7017c2c

Browse files
committed
Auto merge of #159836 - adwinwhite:unify-methods, r=<try>
Unify two `for_each_relevant_impl` methods
2 parents 83709ee + 4a7503c commit 7017c2c

4 files changed

Lines changed: 140 additions & 154 deletions

File tree

compiler/rustc_middle/src/ty/context/impl_interner.rs

Lines changed: 9 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -539,135 +539,19 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
539539
.map(|assoc_item| assoc_item.def_id)
540540
}
541541

542-
// This implementation is a bit different from `TyCtxt::for_each_relevant_impl`,
543-
// since we want to skip over blanket impls for non-rigid aliases, and also we
544-
// only want to consider types that *actually* unify with float/int vars.
542+
// This signature is a bit different from `TyCtxt::for_each_relevant_impl`.
543+
// While rustc only needs self_ty, rust-analyzer's impl needs to use all the args.
545544
fn for_each_relevant_impl<R: VisitorResult>(
546545
self,
547546
trait_ref: ty::TraitRef<'tcx>,
548-
mut f: impl FnMut(DefId) -> R,
547+
f: impl FnMut(DefId) -> R,
549548
) -> R {
550-
macro_rules! ret {
551-
($e: expr) => {
552-
match $e.branch() {
553-
ControlFlow::Break(b) => return R::from_residual(b),
554-
ControlFlow::Continue(()) => {}
555-
}
556-
};
557-
}
558-
559-
let trait_def_id = trait_ref.def_id;
560-
let self_ty = trait_ref.self_ty();
561-
let tcx = self;
562-
let trait_impls = tcx.trait_impls_of(trait_def_id);
563-
let mut consider_impls_for_simplified_type = |simp| {
564-
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
565-
for &impl_def_id in impls_for_type {
566-
ret!(f(impl_def_id))
567-
}
568-
}
569-
570-
R::output()
571-
};
572-
573-
match self_ty.kind() {
574-
ty::Bool
575-
| ty::Char
576-
| ty::Int(_)
577-
| ty::Uint(_)
578-
| ty::Float(_)
579-
| ty::Adt(_, _)
580-
| ty::Foreign(_)
581-
| ty::Str
582-
| ty::Array(_, _)
583-
| ty::Pat(_, _)
584-
| ty::Slice(_)
585-
| ty::RawPtr(_, _)
586-
| ty::Ref(_, _, _)
587-
| ty::FnDef(_, _)
588-
| ty::FnPtr(..)
589-
| ty::Dynamic(_, _)
590-
| ty::Closure(..)
591-
| ty::CoroutineClosure(..)
592-
| ty::Coroutine(_, _)
593-
| ty::Never
594-
| ty::Tuple(_)
595-
| ty::UnsafeBinder(_) => {
596-
if let Some(simp) = ty::fast_reject::simplify_type(
597-
tcx,
598-
self_ty,
599-
ty::fast_reject::TreatParams::AsRigid,
600-
) {
601-
ret!(consider_impls_for_simplified_type(simp));
602-
}
603-
}
604-
605-
// HACK: For integer and float variables we have to manually look at all impls
606-
// which have some integer or float as a self type.
607-
ty::Infer(ty::IntVar(_)) => {
608-
use ty::IntTy::*;
609-
use ty::UintTy::*;
610-
// This causes a compiler error if any new integer kinds are added.
611-
let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy;
612-
let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy;
613-
let possible_integers = [
614-
// signed integers
615-
ty::SimplifiedType::Int(I8),
616-
ty::SimplifiedType::Int(I16),
617-
ty::SimplifiedType::Int(I32),
618-
ty::SimplifiedType::Int(I64),
619-
ty::SimplifiedType::Int(I128),
620-
ty::SimplifiedType::Int(Isize),
621-
// unsigned integers
622-
ty::SimplifiedType::Uint(U8),
623-
ty::SimplifiedType::Uint(U16),
624-
ty::SimplifiedType::Uint(U32),
625-
ty::SimplifiedType::Uint(U64),
626-
ty::SimplifiedType::Uint(U128),
627-
ty::SimplifiedType::Uint(Usize),
628-
];
629-
for simp in possible_integers {
630-
ret!(consider_impls_for_simplified_type(simp));
631-
}
632-
}
633-
634-
ty::Infer(ty::FloatVar(_)) => {
635-
// This causes a compiler error if any new float kinds are added.
636-
let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128);
637-
let possible_floats = [
638-
ty::SimplifiedType::Float(ty::FloatTy::F16),
639-
ty::SimplifiedType::Float(ty::FloatTy::F32),
640-
ty::SimplifiedType::Float(ty::FloatTy::F64),
641-
ty::SimplifiedType::Float(ty::FloatTy::F128),
642-
];
643-
644-
for simp in possible_floats {
645-
ret!(consider_impls_for_simplified_type(simp));
646-
}
647-
}
648-
649-
// The only traits applying to aliases and placeholders are blanket impls.
650-
//
651-
// Impls which apply to an alias after normalization are handled by
652-
// `assemble_candidates_after_normalizing_self_ty`.
653-
ty::Alias(ty::IsRigid::Yes, _) | ty::Placeholder(..) | ty::Error(_) => (),
654-
// FIXME(-Znext-solver=no): Need to support aliases not marked as
655-
// rigid for the old solver.
656-
ty::Alias(ty::IsRigid::No, _) => (),
657-
658-
// FIXME: These should ideally not exist as a self type. It would be nice for
659-
// the builtin auto trait impls of coroutines to instead directly recurse
660-
// into the witness.
661-
ty::CoroutineWitness(..) => (),
662-
663-
// These variants should not exist as a self type.
664-
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
665-
| ty::Param(_)
666-
| ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
667-
}
668-
669-
#[allow(rustc::usage_of_type_ir_traits)]
670-
self.for_each_blanket_impl(trait_def_id, f)
549+
let self_ty = trait_ref.args.type_at(0);
550+
debug_assert!(
551+
!matches!(self_ty.kind(), ty::Infer(ty::TyVar(_)) | ty::Param(_) | ty::Bound(_)),
552+
"we should not have them as self ty in the next solver"
553+
);
554+
TyCtxt::for_each_relevant_impl(self, trait_ref.def_id, self_ty, f)
671555
}
672556
fn for_each_blanket_impl<R: VisitorResult>(
673557
self,

compiler/rustc_middle/src/ty/trait_def.rs

Lines changed: 128 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::iter;
2+
use std::ops::ControlFlow;
23

34
use rustc_data_structures::fx::FxIndexMap;
45
use rustc_errors::ErrorGuaranteed;
@@ -13,7 +14,7 @@ use crate::query::LocalCrate;
1314
use crate::traits::specialization_graph;
1415
use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
1516
use crate::ty::print::{with_crate_prefix, with_no_trimmed_paths};
16-
use crate::ty::{Ident, Ty, TyCtxt};
17+
use crate::ty::{self, Ident, Interner, Ty, TyCtxt, VisitorResult};
1718

1819
/// A trait's definition with type information.
1920
#[derive(StableHash, Encodable, Decodable)]
@@ -182,40 +183,141 @@ impl<'tcx> TyCtxt<'tcx> {
182183
/// Iterate over every impl that could possibly match the self type `self_ty`.
183184
///
184185
/// `trait_def_id` MUST BE the `DefId` of a trait.
185-
pub fn for_each_relevant_impl(
186+
pub fn for_each_relevant_impl<R: VisitorResult>(
186187
self,
187188
trait_def_id: DefId,
188189
self_ty: Ty<'tcx>,
189-
mut f: impl FnMut(DefId),
190-
) {
191-
// FIXME: This depends on the set of all impls for the trait. That is
192-
// unfortunate wrt. incremental compilation.
193-
//
194-
// If we want to be faster, we could have separate queries for
195-
// blanket and non-blanket impls, and compare them separately.
196-
let impls = self.trait_impls_of(trait_def_id);
197-
198-
for &impl_def_id in impls.blanket_impls.iter() {
199-
f(impl_def_id);
190+
mut f: impl FnMut(DefId) -> R,
191+
) -> R {
192+
macro_rules! ret {
193+
($e: expr) => {
194+
match $e.branch() {
195+
ControlFlow::Break(b) => return R::from_residual(b),
196+
ControlFlow::Continue(()) => {}
197+
}
198+
};
200199
}
201200

202-
// This way, when searching for some impl for `T: Trait`, we do not look at any impls
203-
// whose outer level is not a parameter or projection. Especially for things like
204-
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
205-
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
206-
// Note that we're using `TreatParams::AsRigid` to query `non_blanket_impls` while using
207-
// `TreatParams::InstantiateWithInfer` while actually adding them.
208-
if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsRigid) {
209-
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
210-
for &impl_def_id in impls {
211-
f(impl_def_id);
201+
let tcx = self;
202+
let trait_impls = tcx.trait_impls_of(trait_def_id);
203+
let mut consider_impls_for_simplified_type = |simp| {
204+
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
205+
for &impl_def_id in impls_for_type {
206+
ret!(f(impl_def_id))
212207
}
213208
}
214-
} else {
215-
for &impl_def_id in impls.non_blanket_impls.values().flatten() {
216-
f(impl_def_id);
209+
210+
R::output()
211+
};
212+
213+
match self_ty.kind() {
214+
ty::Bool
215+
| ty::Char
216+
| ty::Int(_)
217+
| ty::Uint(_)
218+
| ty::Float(_)
219+
| ty::Adt(_, _)
220+
| ty::Foreign(_)
221+
| ty::Str
222+
| ty::Array(_, _)
223+
| ty::Pat(_, _)
224+
| ty::Slice(_)
225+
| ty::RawPtr(_, _)
226+
| ty::Ref(_, _, _)
227+
| ty::FnDef(_, _)
228+
| ty::FnPtr(..)
229+
| ty::Dynamic(_, _)
230+
| ty::Closure(..)
231+
| ty::CoroutineClosure(..)
232+
| ty::Coroutine(_, _)
233+
| ty::Never
234+
| ty::Tuple(_)
235+
| ty::UnsafeBinder(_) => {
236+
let simp = ty::fast_reject::simplify_type(
237+
tcx,
238+
self_ty,
239+
ty::fast_reject::TreatParams::AsRigid,
240+
)
241+
.unwrap();
242+
ret!(consider_impls_for_simplified_type(simp));
243+
}
244+
245+
// HACK: For integer and float variables we have to manually look at all impls
246+
// which have some integer or float as a self type.
247+
ty::Infer(ty::IntVar(_)) => {
248+
use ty::IntTy::*;
249+
use ty::UintTy::*;
250+
// This causes a compiler error if any new integer kinds are added.
251+
let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy;
252+
let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy;
253+
let possible_integers = [
254+
// signed integers
255+
ty::SimplifiedType::Int(I8),
256+
ty::SimplifiedType::Int(I16),
257+
ty::SimplifiedType::Int(I32),
258+
ty::SimplifiedType::Int(I64),
259+
ty::SimplifiedType::Int(I128),
260+
ty::SimplifiedType::Int(Isize),
261+
// unsigned integers
262+
ty::SimplifiedType::Uint(U8),
263+
ty::SimplifiedType::Uint(U16),
264+
ty::SimplifiedType::Uint(U32),
265+
ty::SimplifiedType::Uint(U64),
266+
ty::SimplifiedType::Uint(U128),
267+
ty::SimplifiedType::Uint(Usize),
268+
];
269+
for simp in possible_integers {
270+
ret!(consider_impls_for_simplified_type(simp));
271+
}
272+
}
273+
274+
ty::Infer(ty::FloatVar(_)) => {
275+
// This causes a compiler error if any new float kinds are added.
276+
let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128);
277+
let possible_floats = [
278+
ty::SimplifiedType::Float(ty::FloatTy::F16),
279+
ty::SimplifiedType::Float(ty::FloatTy::F32),
280+
ty::SimplifiedType::Float(ty::FloatTy::F64),
281+
ty::SimplifiedType::Float(ty::FloatTy::F128),
282+
];
283+
284+
for simp in possible_floats {
285+
ret!(consider_impls_for_simplified_type(simp));
286+
}
287+
}
288+
289+
// This is only for diagnostics and normally ty vars should be handled by the callers.
290+
ty::Infer(ty::TyVar(_)) => {
291+
for &impl_def_id in trait_impls.non_blanket_impls().values().flatten() {
292+
ret!(f(impl_def_id));
293+
}
294+
}
295+
296+
// The only traits applying to aliases and placeholders are blanket impls.
297+
//
298+
// Impls which apply to an alias after normalization are handled by
299+
// `assemble_candidates_after_normalizing_self_ty`.
300+
ty::Alias(ty::IsRigid::Yes, _) | ty::Placeholder(..) | ty::Error(_) => (),
301+
// FIXME(-Znext-solver=no): Need to support aliases not marked as
302+
// rigid for the old solver.
303+
ty::Alias(ty::IsRigid::No, _) => (),
304+
305+
// FIXME: These should ideally not exist as a self type. It would be nice for
306+
// the builtin auto trait impls of coroutines to instead directly recurse
307+
// into the witness.
308+
ty::CoroutineWitness(..) => (),
309+
310+
// These are used in diagnostics or in the old solver.
311+
ty::Param(_) | ty::Bound(_, _) => (),
312+
313+
// These variants should not exist as a self type.
314+
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
315+
bug!("unexpected self type: {self_ty:?}");
217316
}
218317
}
318+
319+
#[allow(rustc::usage_of_type_ir_traits)]
320+
self.for_each_blanket_impl(trait_def_id, f)
219321
}
220322

221323
/// `trait_def_id` MUST BE the `DefId` of a trait.

tests/ui/methods/inherent-bound-in-probe.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ where
4141

4242
fn into_iter(self) -> Self::IntoIter {
4343
Helper::new(&self.0)
44-
//~^ ERROR overflow evaluating the requirement `&_: IntoIterator`
44+
//~^ ERROR: overflow evaluating the requirement `&HashMap<_, _, _, _>: IntoIterator`
4545
}
4646
}
4747

tests/ui/methods/inherent-bound-in-probe.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ LL | struct Helper<'a, T>
1212
note: required by a bound in `std::iter::IntoIterator::IntoIter`
1313
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
1414

15-
error[E0275]: overflow evaluating the requirement `&_: IntoIterator`
15+
error[E0275]: overflow evaluating the requirement `&HashMap<_, _, _, _>: IntoIterator`
1616
--> $DIR/inherent-bound-in-probe.rs:43:9
1717
|
1818
LL | Helper::new(&self.0)
1919
| ^^^^^^
2020
|
2121
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_bound_in_probe`)
22-
note: required for `&BitReaderWrapper<_>` to implement `IntoIterator`
22+
note: required for `&BitReaderWrapper<HashMap<_, _, _, _>>` to implement `IntoIterator`
2323
--> $DIR/inherent-bound-in-probe.rs:33:13
2424
|
2525
LL | impl<'a, T> IntoIterator for &'a BitReaderWrapper<T>

0 commit comments

Comments
 (0)