Skip to content

Commit 1e39dc2

Browse files
Elaborate only supertraits that share the same self type as the predicate
1 parent 6172aa8 commit 1e39dc2

File tree

3 files changed

+69
-12
lines changed

3 files changed

+69
-12
lines changed

compiler/rustc_infer/src/traits/util.rs

+22-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use smallvec::smallvec;
33
use crate::infer::outlives::components::{push_outlives_components, Component};
44
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
55
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
6-
use rustc_middle::ty::{self, ToPredicate, TyCtxt};
6+
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
77
use rustc_span::symbol::Ident;
88
use rustc_span::Span;
99

@@ -132,8 +132,11 @@ fn predicate_obligation<'tcx>(
132132
}
133133

134134
impl<'tcx> Elaborator<'tcx> {
135-
pub fn filter_to_traits(self) -> FilterToTraits<Self> {
136-
FilterToTraits::new(self)
135+
pub fn filter_to_traits(
136+
self,
137+
filter_self_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
138+
) -> FilterToTraits<'tcx, Self> {
139+
FilterToTraits::new(self, filter_self_ty)
137140
}
138141

139142
fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
@@ -312,20 +315,20 @@ impl<'tcx> Iterator for Elaborator<'tcx> {
312315
// Supertrait iterator
313316
///////////////////////////////////////////////////////////////////////////
314317

315-
pub type Supertraits<'tcx> = FilterToTraits<Elaborator<'tcx>>;
318+
pub type Supertraits<'tcx> = FilterToTraits<'tcx, Elaborator<'tcx>>;
316319

317320
pub fn supertraits<'tcx>(
318321
tcx: TyCtxt<'tcx>,
319322
trait_ref: ty::PolyTraitRef<'tcx>,
320323
) -> Supertraits<'tcx> {
321-
elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
324+
elaborate_trait_ref(tcx, trait_ref).filter_to_traits(Some(trait_ref.self_ty()))
322325
}
323326

324327
pub fn transitive_bounds<'tcx>(
325328
tcx: TyCtxt<'tcx>,
326329
bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
327330
) -> Supertraits<'tcx> {
328-
elaborate_trait_refs(tcx, bounds).filter_to_traits()
331+
elaborate_trait_refs(tcx, bounds).filter_to_traits(None)
329332
}
330333

331334
/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may
@@ -370,22 +373,29 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
370373

371374
/// A filter around an iterator of predicates that makes it yield up
372375
/// just trait references.
373-
pub struct FilterToTraits<I> {
376+
pub struct FilterToTraits<'tcx, I> {
374377
base_iterator: I,
378+
filter_self_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
375379
}
376380

377-
impl<I> FilterToTraits<I> {
378-
fn new(base: I) -> FilterToTraits<I> {
379-
FilterToTraits { base_iterator: base }
381+
impl<'tcx, I> FilterToTraits<'tcx, I> {
382+
fn new(base: I, filter_self_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>) -> FilterToTraits<'tcx, I> {
383+
FilterToTraits { base_iterator: base, filter_self_ty }
380384
}
381385
}
382386

383-
impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToTraits<I> {
387+
impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToTraits<'tcx, I> {
384388
type Item = ty::PolyTraitRef<'tcx>;
385389

386390
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
387391
while let Some(obligation) = self.base_iterator.next() {
388-
if let Some(data) = obligation.predicate.to_opt_poly_trait_pred() {
392+
if let Some(data) = obligation.predicate.to_opt_poly_trait_pred()
393+
// A note on binders: Elaboration means that the output predicates
394+
// may have more bound variables than the inputs. However, since we
395+
// only append variables to the bound vars list, it is fine to
396+
// compare self types outside of the binders.
397+
&& self.filter_self_ty.map_or(true, |filter_self_ty| filter_self_ty.skip_binder() == data.skip_binder().self_ty())
398+
{
389399
return Some(data.map_bound(|t| t.trait_ref));
390400
}
391401
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#![feature(trait_upcasting)]
2+
#![feature(trait_alias)]
3+
4+
// Although we *elaborate* `T: Alias` to `i32: B`, we should
5+
// not consider `B` to be a supertrait of the type.
6+
trait Alias = A where i32: B;
7+
8+
trait A {}
9+
10+
trait B {
11+
fn test(&self);
12+
}
13+
14+
trait C: Alias {}
15+
16+
impl A for () {}
17+
18+
impl C for () {}
19+
20+
impl B for i32 {
21+
fn test(&self) {
22+
println!("hi {self}");
23+
}
24+
}
25+
26+
fn test(x: &dyn C) -> &dyn B {
27+
x
28+
//~^ ERROR mismatched types
29+
}
30+
31+
fn main() {
32+
let x: &dyn C = &();
33+
}
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)