Skip to content

Commit 023b565

Browse files
committed
add some comments
1 parent 992efa6 commit 023b565

File tree

3 files changed

+41
-32
lines changed

3 files changed

+41
-32
lines changed

compiler/rustc_middle/src/ty/fast_reject.rs

+22-8
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,29 @@ pub enum StripReferences {
6060
No,
6161
}
6262

63-
/// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc.
64-
/// The idea is to get something simple that we can use to quickly decide if two types could unify
65-
/// during method lookup.
63+
/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
6664
///
67-
/// If `can_simplify_params` is false, then we will fail to simplify type parameters entirely. This
68-
/// is useful when those type parameters would be instantiated with fresh type variables, since
69-
/// then we can't say much about whether two types would unify. Put another way,
70-
/// `can_simplify_params` should be true if type parameters appear free in `ty` and `false` if they
71-
/// are to be considered bound.
65+
/// The idea is to get something simple that we can use to quickly decide if two types could unify,
66+
/// for example during method lookup.
67+
///
68+
/// A special case here are parameters and projections. Projections can be normalized to
69+
/// a different type, meaning that `<T as Trait>::Assoc` and `u8` can be unified, even though
70+
/// their outermost layer is different while parameters like `T` of impls are later replaced
71+
/// with an inference variable, which then also allows unification with other types.
72+
///
73+
/// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections²,
74+
/// the reasoning for this can be seen at the places doing this.
75+
///
76+
/// For diagnostics we strip references with `StripReferences::Yes`. This is currently the best
77+
/// way to skip some unhelpful suggestions.
78+
///
79+
/// ¹ meaning that if two outermost layers are different, then the whole types are also different.
80+
/// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during
81+
/// candidate selection. We do not consider non blanket impls for `<_ as Trait>::Assoc` even
82+
/// though `_` can be inferred to a concrete type later at which point a concrete impl
83+
/// could actually apply. After experimenting for about an hour I wasn't able to cause any issues
84+
/// this way so I am not going to change this until we actually find an issue as I am really
85+
/// interesting in getting an actual test for this.
7286
pub fn simplify_type(
7387
tcx: TyCtxt<'_>,
7488
ty: Ty<'_>,

compiler/rustc_middle/src/ty/trait_def.rs

+11-24
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ impl<'tcx> TyCtxt<'tcx> {
146146
self_ty: Ty<'tcx>,
147147
mut f: F,
148148
) -> Option<T> {
149+
// FIXME: This depends on the set of all impls for the trait. That is
150+
// unfortunate wrt. incremental compilation.
151+
//
152+
// If we want to be faster, we could have separate queries for
153+
// blanket and non-blanket impls, and compare them separately.
149154
let impls = self.trait_impls_of(def_id);
150155

151156
for &impl_def_id in impls.blanket_impls.iter() {
@@ -154,31 +159,13 @@ impl<'tcx> TyCtxt<'tcx> {
154159
}
155160
}
156161

157-
// simplify_type(.., false) basically replaces type parameters and
158-
// projections with infer-variables. This is, of course, done on
159-
// the impl trait-ref when it is instantiated, but not on the
160-
// predicate trait-ref which is passed here.
161-
//
162-
// for example, if we match `S: Copy` against an impl like
163-
// `impl<T:Copy> Copy for Option<T>`, we replace the type variable
164-
// in `Option<T>` with an infer variable, to `Option<_>` (this
165-
// doesn't actually change fast_reject output), but we don't
166-
// replace `S` with anything - this impl of course can't be
167-
// selected, and as there are hundreds of similar impls,
168-
// considering them would significantly harm performance.
169-
170-
// This depends on the set of all impls for the trait. That is
171-
// unfortunate. When we get red-green recompilation, we would like
172-
// to have a way of knowing whether the set of relevant impls
173-
// changed. The most naive
174-
// way would be to compute the Vec of relevant impls and see whether
175-
// it differs between compilations. That shouldn't be too slow by
176-
// itself - we do quite a bit of work for each relevant impl anyway.
177-
//
178-
// If we want to be faster, we could have separate queries for
179-
// blanket and non-blanket impls, and compare them separately.
162+
// Note that we're using `SimplifyParams::Yes` to query `non_blanket_impls` while using
163+
// `SimplifyParams::No` while actually adding them.
180164
//
181-
// I think we'll cross that bridge when we get to it.
165+
// This way, when searching for some impl for `T: Trait`, we do not look at any impls
166+
// whose outer level is not a parameter or projection. Especially for things like
167+
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
168+
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
182169
if let Some(simp) =
183170
fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes, StripReferences::No)
184171
{

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,14 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
14401440
&self,
14411441
trait_ref: ty::PolyTraitRef<'tcx>,
14421442
) -> Vec<ty::TraitRef<'tcx>> {
1443+
// We simplify params and strip references here.
1444+
//
1445+
// This both removes a lot of unhelpful suggestions, e.g.
1446+
// when searching for `&Foo: Trait` it doesn't suggestion `impl Trait for &Bar`,
1447+
// while also suggesting impls for `&Foo` when we're looking for `Foo: Trait`.
1448+
//
1449+
// The second thing isn't necessarily always a good thing, but
1450+
// any other simple setup results in a far worse output, so 🤷
14431451
let simp = fast_reject::simplify_type(
14441452
self.tcx,
14451453
trait_ref.skip_binder().self_ty(),

0 commit comments

Comments
 (0)