Skip to content

Commit 7ec72ef

Browse files
Allow the elaborator to only filter to real supertraits
1 parent 4560b61 commit 7ec72ef

File tree

7 files changed

+107
-48
lines changed

7 files changed

+107
-48
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

+37-31
Original file line numberDiff line numberDiff line change
@@ -1663,39 +1663,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16631663
})
16641664
});
16651665

1666-
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
1667-
bound.map_bound(|mut b| {
1668-
assert_eq!(b.projection_ty.self_ty(), dummy_self);
1669-
1670-
// Like for trait refs, verify that `dummy_self` did not leak inside default type
1671-
// parameters.
1672-
let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
1673-
if arg.walk().any(|arg| arg == dummy_self.into()) {
1674-
return true;
1666+
let existential_projections = projection_bounds
1667+
.iter()
1668+
// We filter out traits that don't have `Self` as their self type above,
1669+
// we need to do the same for projections.
1670+
.filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self)
1671+
.map(|(bound, _)| {
1672+
bound.map_bound(|mut b| {
1673+
assert_eq!(b.projection_ty.self_ty(), dummy_self);
1674+
1675+
// Like for trait refs, verify that `dummy_self` did not leak inside default type
1676+
// parameters.
1677+
let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
1678+
if arg.walk().any(|arg| arg == dummy_self.into()) {
1679+
return true;
1680+
}
1681+
false
1682+
});
1683+
if references_self {
1684+
let guar = tcx.sess.delay_span_bug(
1685+
span,
1686+
"trait object projection bounds reference `Self`",
1687+
);
1688+
let substs: Vec<_> = b
1689+
.projection_ty
1690+
.substs
1691+
.iter()
1692+
.map(|arg| {
1693+
if arg.walk().any(|arg| arg == dummy_self.into()) {
1694+
return tcx.ty_error(guar).into();
1695+
}
1696+
arg
1697+
})
1698+
.collect();
1699+
b.projection_ty.substs = tcx.mk_substs(&substs);
16751700
}
1676-
false
1677-
});
1678-
if references_self {
1679-
let guar = tcx
1680-
.sess
1681-
.delay_span_bug(span, "trait object projection bounds reference `Self`");
1682-
let substs: Vec<_> = b
1683-
.projection_ty
1684-
.substs
1685-
.iter()
1686-
.map(|arg| {
1687-
if arg.walk().any(|arg| arg == dummy_self.into()) {
1688-
return tcx.ty_error(guar).into();
1689-
}
1690-
arg
1691-
})
1692-
.collect();
1693-
b.projection_ty.substs = tcx.mk_substs(&substs);
1694-
}
16951701

1696-
ty::ExistentialProjection::erase_self_ty(tcx, b)
1697-
})
1698-
});
1702+
ty::ExistentialProjection::erase_self_ty(tcx, b)
1703+
})
1704+
});
16991705

17001706
let regular_trait_predicates = existential_trait_refs
17011707
.map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));

compiler/rustc_hir_typeck/src/closure.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
210210
// and we want to keep inference generally in the same order of
211211
// the registered obligations.
212212
predicates.rev(),
213-
) {
213+
)
214+
// We only care about self bounds
215+
.filter_only_self()
216+
{
214217
debug!(?pred);
215218
let bound_predicate = pred.kind();
216219

compiler/rustc_infer/src/traits/util.rs

+26-15
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ impl<'tcx> Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
6969
pub struct Elaborator<'tcx, O> {
7070
stack: Vec<O>,
7171
visited: PredicateSet<'tcx>,
72+
only_self: bool,
7273
}
7374

7475
/// Describes how to elaborate an obligation into a sub-obligation.
@@ -170,7 +171,8 @@ pub fn elaborate<'tcx, O: Elaboratable<'tcx>>(
170171
tcx: TyCtxt<'tcx>,
171172
obligations: impl IntoIterator<Item = O>,
172173
) -> Elaborator<'tcx, O> {
173-
let mut elaborator = Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx) };
174+
let mut elaborator =
175+
Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), only_self: false };
174176
elaborator.extend_deduped(obligations);
175177
elaborator
176178
}
@@ -185,14 +187,25 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
185187
self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate())));
186188
}
187189

190+
/// Filter to only the supertraits of trait predicates, i.e. only the predicates
191+
/// that have `Self` as their self type, instead of all implied predicates.
192+
pub fn filter_only_self(mut self) -> Self {
193+
self.only_self = true;
194+
self
195+
}
196+
188197
fn elaborate(&mut self, elaboratable: &O) {
189198
let tcx = self.visited.tcx;
190199

191200
let bound_predicate = elaboratable.predicate().kind();
192201
match bound_predicate.skip_binder() {
193202
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
194-
// Get predicates declared on the trait.
195-
let predicates = tcx.implied_predicates_of(data.def_id());
203+
// Get predicates implied by the trait, or only super predicates if we only care about self predicates.
204+
let predicates = if self.only_self {
205+
tcx.super_predicates_of(data.def_id())
206+
} else {
207+
tcx.implied_predicates_of(data.def_id())
208+
};
196209

197210
let obligations =
198211
predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| {
@@ -350,18 +363,16 @@ pub fn supertraits<'tcx>(
350363
tcx: TyCtxt<'tcx>,
351364
trait_ref: ty::PolyTraitRef<'tcx>,
352365
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
353-
let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx);
354-
FilterToTraits::new(elaborate(tcx, [pred]))
366+
elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits()
355367
}
356368

357369
pub fn transitive_bounds<'tcx>(
358370
tcx: TyCtxt<'tcx>,
359371
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
360372
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
361-
FilterToTraits::new(elaborate(
362-
tcx,
363-
trait_refs.map(|trait_ref| -> ty::Predicate<'tcx> { trait_ref.to_predicate(tcx) }),
364-
))
373+
elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
374+
.filter_only_self()
375+
.filter_to_traits()
365376
}
366377

367378
/// A specialized variant of `elaborate` that only elaborates trait references that may
@@ -402,18 +413,18 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
402413
// Other
403414
///////////////////////////////////////////////////////////////////////////
404415

416+
impl<'tcx> Elaborator<'tcx, ty::Predicate<'tcx>> {
417+
fn filter_to_traits(self) -> FilterToTraits<Self> {
418+
FilterToTraits { base_iterator: self }
419+
}
420+
}
421+
405422
/// A filter around an iterator of predicates that makes it yield up
406423
/// just trait references.
407424
pub struct FilterToTraits<I> {
408425
base_iterator: I,
409426
}
410427

411-
impl<I> FilterToTraits<I> {
412-
fn new(base: I) -> FilterToTraits<I> {
413-
FilterToTraits { base_iterator: base }
414-
}
415-
}
416-
417428
impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
418429
type Item = ty::PolyTraitRef<'tcx>;
419430

compiler/rustc_lint/src/unused.rs

+2
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
255255
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
256256
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
257257
elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned())
258+
// We only care about self bounds for the impl-trait
259+
.filter_only_self()
258260
.find_map(|(pred, _span)| {
259261
// We only look at the `DefId`, so it is safe to skip the binder here.
260262
if let ty::PredicateKind::Clause(ty::Clause::Trait(

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
498498
let tcx = self.tcx();
499499
let own_bounds: FxIndexSet<_> =
500500
bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect();
501-
for assumption in elaborate(tcx, own_bounds.iter().copied()) {
501+
for assumption in elaborate(tcx, own_bounds.iter().copied())
502+
// we only care about bounds that match the `Self` type
503+
.filter_only_self()
504+
{
502505
// FIXME: Predicates are fully elaborated in the object type's existential bounds
503506
// list. We want to only consider these pre-elaborated projections, and not other
504507
// projection predicates that we reach by elaborating the principal trait ref,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0277]: the size for values of type `(dyn Fn() -> Fut + 'static)` cannot be known at compilation time
2+
--> $DIR/dont-elaborate-non-self.rs:7:11
3+
|
4+
LL | fn f<Fut>(a: dyn F<Fut>) {}
5+
| ^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `Sized` is not implemented for `(dyn Fn() -> Fut + 'static)`
8+
= help: unsized fn params are gated as an unstable feature
9+
help: you can use `impl Trait` as the argument type
10+
|
11+
LL | fn f<Fut>(a: impl F<Fut>) {}
12+
| ~~~~
13+
help: function arguments must have a statically known size, borrowed types always have a known size
14+
|
15+
LL | fn f<Fut>(a: &dyn F<Fut>) {}
16+
| +
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/alias-where-clause-isnt-supertrait.rs:27:5
3+
|
4+
LL | fn test(x: &dyn C) -> &dyn B {
5+
| ------ expected `&dyn B` because of return type
6+
LL | x
7+
| ^ expected trait `B`, found trait `C`
8+
|
9+
= note: expected reference `&dyn B`
10+
found reference `&dyn C`
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)