Skip to content

Commit ad7cda0

Browse files
committed
Use trait_object_dummy_self more & heavily fix+update related docs
1 parent b954122 commit ad7cda0

5 files changed

Lines changed: 93 additions & 99 deletions

File tree

compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs

Lines changed: 42 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@ use tracing::debug;
88
use super::explicit::ExplicitPredicatesMap;
99
use super::utils::*;
1010

11-
/// Infer predicates for the items in the crate.
12-
///
13-
/// `global_inferred_outlives`: this is initially the empty map that
14-
/// was generated by walking the items in the crate. This will
15-
/// now be filled with inferred predicates.
11+
/// Infer outlives-predicates for the items in the local crate.
1612
pub(super) fn infer_predicates(
1713
tcx: TyCtxt<'_>,
1814
) -> FxIndexMap<DefId, ty::EarlyBinder<'_, RequiredPredicates<'_>>> {
@@ -154,7 +150,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
154150
args,
155151
required_predicates,
156152
explicit_map,
157-
None,
153+
IgnorePredicatesReferencingSelf::No,
158154
);
159155
}
160156

@@ -175,31 +171,35 @@ fn insert_required_predicates_to_be_wf<'tcx>(
175171
args,
176172
required_predicates,
177173
explicit_map,
178-
None,
174+
IgnorePredicatesReferencingSelf::No,
179175
);
180176
}
181177

182178
ty::Dynamic(obj, ..) => {
183179
// This corresponds to `dyn Trait<..>`. In this case, we should
184180
// use the explicit predicates as well.
185181
debug!("Dynamic");
186-
if let Some(ex_trait_ref) = obj.principal() {
187-
// Here, we are passing the type `usize` as a
188-
// placeholder value with the function
189-
// `with_self_ty`, since there is no concrete type
190-
// `Self` for a `dyn Trait` at this
191-
// stage. Therefore when checking explicit
192-
// predicates in `check_explicit_predicates` we
193-
// need to ignore checking the explicit_map for
194-
// Self type.
195-
let args = ex_trait_ref.with_self_ty(tcx, tcx.types.usize).skip_binder().args;
182+
if let Some(trait_ref) = obj.principal() {
183+
let args = trait_ref
184+
.with_self_ty(tcx, tcx.types.trait_object_dummy_self)
185+
.skip_binder()
186+
.args;
187+
// We skip predicates that reference the `Self` type parameter since we don't
188+
// want to leak the dummy Self to the predicates map.
189+
//
190+
// While filtering out bounds like `Self: 'a` as in `trait Trait<'a, T>: 'a {}`
191+
// doesn't matter since they can't affect the lifetime / type parameters anyway,
192+
// for bounds like `Self::AssocTy: 'b` which we of course currently also ignore
193+
// (see also #54467) it might conceivably be better to extract the binding
194+
// `AssocTy = U` from the trait object type (which must exist) and thus infer
195+
// an outlives requirement that `U: 'b`.
196196
check_explicit_predicates(
197197
tcx,
198-
ex_trait_ref.skip_binder().def_id,
198+
trait_ref.def_id(),
199199
args,
200200
required_predicates,
201201
explicit_map,
202-
Some(tcx.types.self_param),
202+
IgnorePredicatesReferencingSelf::Yes,
203203
);
204204
}
205205
}
@@ -215,7 +215,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
215215
args,
216216
required_predicates,
217217
explicit_map,
218-
None,
218+
IgnorePredicatesReferencingSelf::No,
219219
);
220220
}
221221

@@ -244,77 +244,44 @@ fn insert_required_predicates_to_be_wf<'tcx>(
244244
/// will give us `U: 'static` and `U: Outer`. The latter we
245245
/// can ignore, but we will want to process `U: 'static`,
246246
/// applying the instantiation as above.
247+
#[tracing::instrument(level = "debug", skip(tcx))]
247248
fn check_explicit_predicates<'tcx>(
248249
tcx: TyCtxt<'tcx>,
249250
def_id: DefId,
250251
args: &[GenericArg<'tcx>],
251252
required_predicates: &mut RequiredPredicates<'tcx>,
252253
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
253-
ignored_self_ty: Option<Ty<'tcx>>,
254+
ignore_preds_refing_self: IgnorePredicatesReferencingSelf,
254255
) {
255-
debug!(
256-
"check_explicit_predicates(def_id={:?}, \
257-
args={:?}, \
258-
explicit_map={:?}, \
259-
required_predicates={:?}, \
260-
ignored_self_ty={:?})",
261-
def_id, args, explicit_map, required_predicates, ignored_self_ty,
262-
);
263256
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id);
264257

265-
for (outlives_predicate, &span) in explicit_predicates.as_ref().skip_binder() {
266-
debug!("outlives_predicate = {outlives_predicate:?}");
267-
268-
// Careful: If we are inferring the effects of a `dyn Trait<..>`
269-
// type, then when we look up the predicates for `Trait`,
270-
// we may find some that reference `Self`. e.g., perhaps the
271-
// definition of `Trait` was:
272-
//
273-
// ```
274-
// trait Trait<'a, T> where Self: 'a { .. }
275-
// ```
276-
//
277-
// we want to ignore such predicates here, because
278-
// there is no type parameter for them to affect. Consider
279-
// a struct containing `dyn Trait`:
280-
//
281-
// ```
282-
// struct MyStruct<'x, X> { field: Box<dyn Trait<'x, X>> }
283-
// ```
284-
//
285-
// The `where Self: 'a` predicate refers to the *existential, hidden type*
286-
// that is represented by the `dyn Trait`, not to the `X` type parameter
287-
// (or any other generic parameter) declared on `MyStruct`.
288-
//
289-
// Note that we do this check for self **before** applying `args`. In the
290-
// case that `args` come from a `dyn Trait` type, our caller will have
291-
// included `Self = usize` as the value for `Self`. If we were
292-
// to apply the args, and not filter this predicate, we might then falsely
293-
// conclude that e.g., `X: 'x` was a reasonable inferred requirement.
294-
//
295-
// Another similar case is where we have an inferred
296-
// requirement like `<Self as Trait>::Foo: 'b`. We presently
297-
// ignore such requirements as well (cc #54467)-- though
298-
// conceivably it might be better if we could extract the `Foo
299-
// = X` binding from the object type (there must be such a
300-
// binding) and thus infer an outlives requirement that `X:
301-
// 'b`.
302-
if let Some(self_ty) = ignored_self_ty
303-
&& let GenericArgKind::Type(ty) = outlives_predicate.0.kind()
304-
&& ty.walk().any(|arg| arg == self_ty.into())
258+
for (&predicate @ ty::OutlivesPredicate(arg, _), &span) in
259+
explicit_predicates.as_ref().skip_binder()
260+
{
261+
debug!(?predicate);
262+
263+
if let IgnorePredicatesReferencingSelf::Yes = ignore_preds_refing_self
264+
&& arg.walk().any(|arg| arg == tcx.types.self_param.into())
305265
{
306-
debug!("skipping self ty = {ty:?}");
266+
debug!("ignoring predicate since it references `Self`");
307267
continue;
308268
}
309269

310-
let predicate =
311-
explicit_predicates.rebind(*outlives_predicate).instantiate(tcx, args).skip_norm_wip();
312-
debug!("predicate = {predicate:?}");
313-
insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates);
270+
let predicate @ ty::OutlivesPredicate(arg, region) =
271+
explicit_predicates.rebind(predicate).instantiate(tcx, args).skip_norm_wip();
272+
debug!(?predicate);
273+
274+
insert_outlives_predicate(tcx, arg, region, span, required_predicates);
314275
}
315276
}
316277

317-
/// Check the inferred predicates declared on the type.
278+
#[derive(Debug)]
279+
enum IgnorePredicatesReferencingSelf {
280+
Yes,
281+
No,
282+
}
283+
284+
/// Check the inferred predicates of the type.
318285
///
319286
/// ### Example
320287
///

compiler/rustc_middle/src/ty/context.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -324,10 +324,32 @@ pub struct CommonTypes<'tcx> {
324324
pub never: Ty<'tcx>,
325325
pub self_param: Ty<'tcx>,
326326

327-
/// Dummy type used for the `Self` of a `TraitRef` created for converting
328-
/// a trait object, and which gets removed in `ExistentialTraitRef`.
329-
/// This type must not appear anywhere in other converted types.
330-
/// `Infer(ty::FreshTy(0))` does the job.
327+
/// A dummy type that can be used as the self type of trait object types outside of
328+
/// [`ty::ExistentialTraitRef`], [`ty::ExistentialProjection`], etc.
329+
///
330+
/// This is most useful or even necessary when you want to manipulate existential predicates
331+
/// together with normal predicates or if you want to pass them to an API that only expects
332+
/// normal predicates.
333+
///
334+
/// Indeed, you can sometimes use the trait object type itself as the self type instead of this
335+
/// dummy type. However, that's not always correct: For example, if said trait object type can
336+
/// also appear "naturally" in whatever type system entity you're working with (like predicates)
337+
/// but you still need to be able to identify the erased self type later on.
338+
/// That's when this dummy type comes in handy.
339+
///
340+
/// HIR ty lowering guarantees / has to guarantee that this dummy type doesn't appear in the
341+
/// lowered types, so you can "freely" use it (see warning below).
342+
///
343+
/// <div class="warning">
344+
///
345+
/// Under the hood, this type is just `ty::Infer(ty::FreshTy(0))`. Consequently, you must be
346+
/// sure that fresh types cannot appear by other means in whatever type system entity you're
347+
/// working with.
348+
///
349+
/// Keep uses of this dummy type as local as possible and try not to leak it to subsequent
350+
/// passes!
351+
///
352+
/// </div>
331353
pub trait_object_dummy_self: Ty<'tcx>,
332354

333355
/// Pre-interned `Infer(ty::TyVar(n))` for small values of `n`.

compiler/rustc_middle/src/ty/print/pretty.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3265,9 +3265,9 @@ define_print! {
32653265
}
32663266

32673267
ty::ExistentialTraitRef<'tcx> {
3268-
// Use a type that can't appear in defaults of type parameters.
3269-
let dummy_self = Ty::new_fresh(p.tcx(), 0);
3270-
let trait_ref = self.with_self_ty(p.tcx(), dummy_self);
3268+
// Dummy Self is safe to use as it can't appear in generic param defaults which is important
3269+
// later on for correctly eliding generic args that coincide with their default.
3270+
let trait_ref = self.with_self_ty(p.tcx(), p.tcx().types.trait_object_dummy_self);
32713271
trait_ref.print_only_trait_path().print(p)?;
32723272
}
32733273

compiler/rustc_symbol_mangling/src/v0.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -646,9 +646,11 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
646646
// could have different bound vars *anyways*.
647647
match predicate.as_ref().skip_binder() {
648648
ty::ExistentialPredicate::Trait(trait_ref) => {
649-
// Use a type that can't appear in defaults of type parameters.
650-
let dummy_self = Ty::new_fresh(p.tcx, 0);
651-
let trait_ref = trait_ref.with_self_ty(p.tcx, dummy_self);
649+
// Dummy Self is safe to use as it can't appear in generic param defaults
650+
// which is important later on for correctly eliding generic args that
651+
// coincide with their default.
652+
let trait_ref =
653+
trait_ref.with_self_ty(p.tcx, p.tcx.types.trait_object_dummy_self);
652654
p.print_def_path(trait_ref.def_id, trait_ref.args)?;
653655
}
654656
ty::ExistentialPredicate::Projection(projection) => {

compiler/rustc_type_ir/src/predicate.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -388,14 +388,13 @@ impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
388388
}
389389
}
390390

391-
/// An existential reference to a trait, where `Self` is erased.
391+
/// An existential reference to a trait where the self type `Self` is erased.
392392
///
393-
/// For example, the trait object `Trait<'a, 'b, X, Y>` is:
393+
/// For example, the trait object type `Trait<'a, T, N>` can be understood as:
394394
/// ```ignore (illustrative)
395-
/// exists T. T: Trait<'a, 'b, X, Y>
395+
/// exists<X> X: Trait<'a, T, N>
396396
/// ```
397-
/// The generic parameters don't include the erased `Self`, only trait
398-
/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
397+
/// The generic arguments don't include the erased self type (so it's only `['a, T, N]`).
399398
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
400399
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
401400
#[cfg_attr(
@@ -438,13 +437,18 @@ impl<I: Interner> ExistentialTraitRef<I> {
438437
}
439438
}
440439

441-
/// Object types don't have a self type specified. Therefore, when
442-
/// we convert the principal trait-ref into a normal trait-ref,
443-
/// you must give *some* self type. A common choice is `mk_err()`
444-
/// or some placeholder type.
440+
/// Convert the *existential* trait ref into a normal one by providing a self type.
441+
///
442+
/// Existential trait refs don't contain a self type, it's erased.
443+
/// Therefore, you must specify *some* self type to perform the conversion.
444+
/// A common choice is the trait object type itself or some kind of dummy type.
445445
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> TraitRef<I> {
446+
// FIXME(#157122): This assertion was accidentally commented out in refactoring PR #53816
447+
// back in 2018 but nowadays it can actually trigger. Either remove this
448+
// comment entirely if the assertion is incorrect or uncomment it and fix
449+
// the fallout!
446450
// otherwise the escaping vars would be captured by the binder
447-
// debug_assert!(!self_ty.has_escaping_bound_vars());
451+
//debug_assert!(!self_ty.has_escaping_bound_vars());
448452

449453
TraitRef::new(interner, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter()))
450454
}
@@ -455,10 +459,9 @@ impl<I: Interner> ty::Binder<I, ExistentialTraitRef<I>> {
455459
self.skip_binder().def_id
456460
}
457461

458-
/// Object types don't have a self type specified. Therefore, when
459-
/// we convert the principal trait-ref into a normal trait-ref,
460-
/// you must give *some* self type. A common choice is `mk_err()`
461-
/// or some placeholder type.
462+
/// Convert the *existential* polymorphic trait ref into a normal one by providing a self type.
463+
///
464+
/// See also [`ExistentialTraitRef::with_self_ty`].
462465
pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder<I, TraitRef<I>> {
463466
self.map_bound(|trait_ref| trait_ref.with_self_ty(cx, self_ty))
464467
}

0 commit comments

Comments
 (0)