Allow the elaborator to only filter to real supertraits
This commit is contained in:
parent
4560b61cd1
commit
7ec72efe10
7 changed files with 106 additions and 47 deletions
|
@ -1663,7 +1663,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
|
let existential_projections = projection_bounds
|
||||||
|
.iter()
|
||||||
|
// We filter out traits that don't have `Self` as their self type above,
|
||||||
|
// we need to do the same for projections.
|
||||||
|
.filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self)
|
||||||
|
.map(|(bound, _)| {
|
||||||
bound.map_bound(|mut b| {
|
bound.map_bound(|mut b| {
|
||||||
assert_eq!(b.projection_ty.self_ty(), dummy_self);
|
assert_eq!(b.projection_ty.self_ty(), dummy_self);
|
||||||
|
|
||||||
|
@ -1676,9 +1681,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
false
|
false
|
||||||
});
|
});
|
||||||
if references_self {
|
if references_self {
|
||||||
let guar = tcx
|
let guar = tcx.sess.delay_span_bug(
|
||||||
.sess
|
span,
|
||||||
.delay_span_bug(span, "trait object projection bounds reference `Self`");
|
"trait object projection bounds reference `Self`",
|
||||||
|
);
|
||||||
let substs: Vec<_> = b
|
let substs: Vec<_> = b
|
||||||
.projection_ty
|
.projection_ty
|
||||||
.substs
|
.substs
|
||||||
|
|
|
@ -210,7 +210,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// and we want to keep inference generally in the same order of
|
// and we want to keep inference generally in the same order of
|
||||||
// the registered obligations.
|
// the registered obligations.
|
||||||
predicates.rev(),
|
predicates.rev(),
|
||||||
) {
|
)
|
||||||
|
// We only care about self bounds
|
||||||
|
.filter_only_self()
|
||||||
|
{
|
||||||
debug!(?pred);
|
debug!(?pred);
|
||||||
let bound_predicate = pred.kind();
|
let bound_predicate = pred.kind();
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ impl<'tcx> Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
|
||||||
pub struct Elaborator<'tcx, O> {
|
pub struct Elaborator<'tcx, O> {
|
||||||
stack: Vec<O>,
|
stack: Vec<O>,
|
||||||
visited: PredicateSet<'tcx>,
|
visited: PredicateSet<'tcx>,
|
||||||
|
only_self: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes how to elaborate an obligation into a sub-obligation.
|
/// Describes how to elaborate an obligation into a sub-obligation.
|
||||||
|
@ -170,7 +171,8 @@ pub fn elaborate<'tcx, O: Elaboratable<'tcx>>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
obligations: impl IntoIterator<Item = O>,
|
obligations: impl IntoIterator<Item = O>,
|
||||||
) -> Elaborator<'tcx, O> {
|
) -> Elaborator<'tcx, O> {
|
||||||
let mut elaborator = Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx) };
|
let mut elaborator =
|
||||||
|
Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), only_self: false };
|
||||||
elaborator.extend_deduped(obligations);
|
elaborator.extend_deduped(obligations);
|
||||||
elaborator
|
elaborator
|
||||||
}
|
}
|
||||||
|
@ -185,14 +187,25 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
||||||
self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate())));
|
self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Filter to only the supertraits of trait predicates, i.e. only the predicates
|
||||||
|
/// that have `Self` as their self type, instead of all implied predicates.
|
||||||
|
pub fn filter_only_self(mut self) -> Self {
|
||||||
|
self.only_self = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn elaborate(&mut self, elaboratable: &O) {
|
fn elaborate(&mut self, elaboratable: &O) {
|
||||||
let tcx = self.visited.tcx;
|
let tcx = self.visited.tcx;
|
||||||
|
|
||||||
let bound_predicate = elaboratable.predicate().kind();
|
let bound_predicate = elaboratable.predicate().kind();
|
||||||
match bound_predicate.skip_binder() {
|
match bound_predicate.skip_binder() {
|
||||||
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
|
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
|
||||||
// Get predicates declared on the trait.
|
// Get predicates implied by the trait, or only super predicates if we only care about self predicates.
|
||||||
let predicates = tcx.implied_predicates_of(data.def_id());
|
let predicates = if self.only_self {
|
||||||
|
tcx.super_predicates_of(data.def_id())
|
||||||
|
} else {
|
||||||
|
tcx.implied_predicates_of(data.def_id())
|
||||||
|
};
|
||||||
|
|
||||||
let obligations =
|
let obligations =
|
||||||
predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| {
|
predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| {
|
||||||
|
@ -350,18 +363,16 @@ pub fn supertraits<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
|
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
|
||||||
let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx);
|
elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits()
|
||||||
FilterToTraits::new(elaborate(tcx, [pred]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transitive_bounds<'tcx>(
|
pub fn transitive_bounds<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||||
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
|
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
|
||||||
FilterToTraits::new(elaborate(
|
elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
|
||||||
tcx,
|
.filter_only_self()
|
||||||
trait_refs.map(|trait_ref| -> ty::Predicate<'tcx> { trait_ref.to_predicate(tcx) }),
|
.filter_to_traits()
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A specialized variant of `elaborate` that only elaborates trait references that may
|
/// 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>(
|
||||||
// Other
|
// Other
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl<'tcx> Elaborator<'tcx, ty::Predicate<'tcx>> {
|
||||||
|
fn filter_to_traits(self) -> FilterToTraits<Self> {
|
||||||
|
FilterToTraits { base_iterator: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A filter around an iterator of predicates that makes it yield up
|
/// A filter around an iterator of predicates that makes it yield up
|
||||||
/// just trait references.
|
/// just trait references.
|
||||||
pub struct FilterToTraits<I> {
|
pub struct FilterToTraits<I> {
|
||||||
base_iterator: I,
|
base_iterator: I,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> FilterToTraits<I> {
|
|
||||||
fn new(base: I) -> FilterToTraits<I> {
|
|
||||||
FilterToTraits { base_iterator: base }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
|
impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
|
||||||
type Item = ty::PolyTraitRef<'tcx>;
|
type Item = ty::PolyTraitRef<'tcx>;
|
||||||
|
|
||||||
|
|
|
@ -255,6 +255,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||||
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
|
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
|
||||||
elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned())
|
elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned())
|
||||||
|
// We only care about self bounds for the impl-trait
|
||||||
|
.filter_only_self()
|
||||||
.find_map(|(pred, _span)| {
|
.find_map(|(pred, _span)| {
|
||||||
// We only look at the `DefId`, so it is safe to skip the binder here.
|
// We only look at the `DefId`, so it is safe to skip the binder here.
|
||||||
if let ty::PredicateKind::Clause(ty::Clause::Trait(
|
if let ty::PredicateKind::Clause(ty::Clause::Trait(
|
||||||
|
|
|
@ -498,7 +498,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let own_bounds: FxIndexSet<_> =
|
let own_bounds: FxIndexSet<_> =
|
||||||
bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect();
|
bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect();
|
||||||
for assumption in elaborate(tcx, own_bounds.iter().copied()) {
|
for assumption in elaborate(tcx, own_bounds.iter().copied())
|
||||||
|
// we only care about bounds that match the `Self` type
|
||||||
|
.filter_only_self()
|
||||||
|
{
|
||||||
// FIXME: Predicates are fully elaborated in the object type's existential bounds
|
// FIXME: Predicates are fully elaborated in the object type's existential bounds
|
||||||
// list. We want to only consider these pre-elaborated projections, and not other
|
// list. We want to only consider these pre-elaborated projections, and not other
|
||||||
// projection predicates that we reach by elaborating the principal trait ref,
|
// projection predicates that we reach by elaborating the principal trait ref,
|
||||||
|
|
20
tests/ui/traits/alias/dont-elaborate-non-self.stderr
Normal file
20
tests/ui/traits/alias/dont-elaborate-non-self.stderr
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
error[E0277]: the size for values of type `(dyn Fn() -> Fut + 'static)` cannot be known at compilation time
|
||||||
|
--> $DIR/dont-elaborate-non-self.rs:7:11
|
||||||
|
|
|
||||||
|
LL | fn f<Fut>(a: dyn F<Fut>) {}
|
||||||
|
| ^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `(dyn Fn() -> Fut + 'static)`
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: you can use `impl Trait` as the argument type
|
||||||
|
|
|
||||||
|
LL | fn f<Fut>(a: impl F<Fut>) {}
|
||||||
|
| ~~~~
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn f<Fut>(a: &dyn F<Fut>) {}
|
||||||
|
| +
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/alias-where-clause-isnt-supertrait.rs:27:5
|
||||||
|
|
|
||||||
|
LL | fn test(x: &dyn C) -> &dyn B {
|
||||||
|
| ------ expected `&dyn B` because of return type
|
||||||
|
LL | x
|
||||||
|
| ^ expected trait `B`, found trait `C`
|
||||||
|
|
|
||||||
|
= note: expected reference `&dyn B`
|
||||||
|
found reference `&dyn C`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue