Rework collapse method to work correctly with more complex supertrait graphs
This commit is contained in:
parent
f8c51d3002
commit
18a3cc5c2c
9 changed files with 266 additions and 22 deletions
|
@ -2112,34 +2112,59 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
probes: &[(&Candidate<'tcx>, ProbeResult)],
|
probes: &[(&Candidate<'tcx>, ProbeResult)],
|
||||||
) -> Option<Pick<'tcx>> {
|
) -> Option<Pick<'tcx>> {
|
||||||
let mut child_pick = probes[0].0;
|
let mut child_candidate = probes[0].0;
|
||||||
let mut supertraits: SsoHashSet<_> =
|
let mut child_trait = child_candidate.item.trait_container(self.tcx)?;
|
||||||
supertrait_def_ids(self.tcx, child_pick.item.trait_container(self.tcx)?).collect();
|
let mut supertraits: SsoHashSet<_> = supertrait_def_ids(self.tcx, child_trait).collect();
|
||||||
|
|
||||||
// All other picks should be a supertrait of the `child_pick`.
|
let mut remaining_candidates: Vec<_> = probes[1..].iter().map(|&(p, _)| p).collect();
|
||||||
// If it's not, then we update the `child_pick` and the `supertraits`
|
while !remaining_candidates.is_empty() {
|
||||||
// list.
|
let mut made_progress = false;
|
||||||
for (p, _) in &probes[1..] {
|
let mut next_round = vec![];
|
||||||
let p_container = p.item.trait_container(self.tcx)?;
|
|
||||||
if !supertraits.contains(&p_container) {
|
for remaining_candidate in remaining_candidates {
|
||||||
// This pick is not a supertrait of the `child_pick`.
|
let remaining_trait = remaining_candidate.item.trait_container(self.tcx)?;
|
||||||
// Check if it's a subtrait of the `child_pick`, which
|
if supertraits.contains(&remaining_trait) {
|
||||||
// is sufficient to imply that all of the previous picks
|
made_progress = true;
|
||||||
// are also supertraits of this pick.
|
continue;
|
||||||
supertraits = supertrait_def_ids(self.tcx, p_container).collect();
|
|
||||||
if supertraits.contains(&child_pick.item.trait_container(self.tcx).unwrap()) {
|
|
||||||
child_pick = *p;
|
|
||||||
} else {
|
|
||||||
// `child_pick` is not a supertrait of this pick. Bail.
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This pick is not a supertrait of the `child_pick`.
|
||||||
|
// Check if it's a subtrait of the `child_pick`, instead.
|
||||||
|
// If it is, then it must have been a subtrait of every
|
||||||
|
// other pick we've eliminated at this point. It will
|
||||||
|
// take over at this point.
|
||||||
|
let remaining_trait_supertraits: SsoHashSet<_> =
|
||||||
|
supertrait_def_ids(self.tcx, remaining_trait).collect();
|
||||||
|
if remaining_trait_supertraits.contains(&child_trait) {
|
||||||
|
child_candidate = remaining_candidate;
|
||||||
|
child_trait = remaining_trait;
|
||||||
|
supertraits = remaining_trait_supertraits;
|
||||||
|
made_progress = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `child_pick` is not a supertrait of this pick.
|
||||||
|
// Don't bail here, since we may be comparing two supertraits
|
||||||
|
// of a common subtrait. These two supertraits won't be related
|
||||||
|
// at all, but we will pick them up next round when we find their
|
||||||
|
// child as we continue iterating in this round.
|
||||||
|
next_round.push(remaining_candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if made_progress {
|
||||||
|
// If we've made progress, iterate again.
|
||||||
|
remaining_candidates = next_round;
|
||||||
|
} else {
|
||||||
|
// Otherwise, we must have at least two candidates which
|
||||||
|
// are not related to each other at all.
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Pick {
|
Some(Pick {
|
||||||
item: child_pick.item,
|
item: child_candidate.item,
|
||||||
kind: TraitPick,
|
kind: TraitPick,
|
||||||
import_ids: child_pick.import_ids.clone(),
|
import_ids: child_candidate.import_ids.clone(),
|
||||||
autoderefs: 0,
|
autoderefs: 0,
|
||||||
autoref_or_ptr_adjustment: None,
|
autoref_or_ptr_adjustment: None,
|
||||||
self_ty,
|
self_ty,
|
||||||
|
@ -2147,7 +2172,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
shadowed_candidates: probes
|
shadowed_candidates: probes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(c, _)| c.item)
|
.map(|(c, _)| c.item)
|
||||||
.filter(|item| item.def_id != child_pick.item.def_id)
|
.filter(|item| item.def_id != child_candidate.item.def_id)
|
||||||
.collect(),
|
.collect(),
|
||||||
receiver_steps: None,
|
receiver_steps: None,
|
||||||
})
|
})
|
||||||
|
|
32
tests/ui/methods/supertrait-shadowing/common-ancestor-2.rs
Normal file
32
tests/ui/methods/supertrait-shadowing/common-ancestor-2.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//@ run-pass
|
||||||
|
//@ check-run-results
|
||||||
|
|
||||||
|
#![feature(supertrait_item_shadowing)]
|
||||||
|
#![warn(supertrait_item_shadowing_usage)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
trait A {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("A");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> A for T {}
|
||||||
|
|
||||||
|
trait B {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("B");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> B for T {}
|
||||||
|
|
||||||
|
trait C: A + B {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("C");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> C for T {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
().hello();
|
||||||
|
//~^ WARN trait item `hello` from `C` shadows identically named item from supertrait
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
C
|
|
@ -0,0 +1,27 @@
|
||||||
|
warning: trait item `hello` from `C` shadows identically named item from supertrait
|
||||||
|
--> $DIR/common-ancestor-2.rs:30:8
|
||||||
|
|
|
||||||
|
LL | ().hello();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
note: item from `C` shadows a supertrait item
|
||||||
|
--> $DIR/common-ancestor-2.rs:23:5
|
||||||
|
|
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
note: items from several supertraits are shadowed: `A` and `B`
|
||||||
|
--> $DIR/common-ancestor-2.rs:9:5
|
||||||
|
|
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/common-ancestor-2.rs:5:9
|
||||||
|
|
|
||||||
|
LL | #![warn(supertrait_item_shadowing_usage)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
41
tests/ui/methods/supertrait-shadowing/common-ancestor-3.rs
Normal file
41
tests/ui/methods/supertrait-shadowing/common-ancestor-3.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
//@ run-pass
|
||||||
|
//@ check-run-results
|
||||||
|
|
||||||
|
#![feature(supertrait_item_shadowing)]
|
||||||
|
#![warn(supertrait_item_shadowing_usage)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
trait A {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("A");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> A for T {}
|
||||||
|
|
||||||
|
trait B {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("B");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> B for T {}
|
||||||
|
|
||||||
|
trait C: A + B {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("C");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> C for T {}
|
||||||
|
|
||||||
|
// `D` extends `C` which extends `B` and `A`
|
||||||
|
|
||||||
|
trait D: C {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("D");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> D for T {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
().hello();
|
||||||
|
//~^ WARN trait item `hello` from `D` shadows identically named item from supertrait
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
D
|
|
@ -0,0 +1,30 @@
|
||||||
|
warning: trait item `hello` from `D` shadows identically named item from supertrait
|
||||||
|
--> $DIR/common-ancestor-3.rs:39:8
|
||||||
|
|
|
||||||
|
LL | ().hello();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
note: item from `D` shadows a supertrait item
|
||||||
|
--> $DIR/common-ancestor-3.rs:32:5
|
||||||
|
|
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
note: items from several supertraits are shadowed: `A`, `B`, and `C`
|
||||||
|
--> $DIR/common-ancestor-3.rs:9:5
|
||||||
|
|
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/common-ancestor-3.rs:5:9
|
||||||
|
|
|
||||||
|
LL | #![warn(supertrait_item_shadowing_usage)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
#![feature(supertrait_item_shadowing)]
|
||||||
|
|
||||||
|
trait A {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("A");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> A for T {}
|
||||||
|
|
||||||
|
trait B {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("B");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> B for T {}
|
||||||
|
|
||||||
|
trait C: A + B {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("C");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> C for T {}
|
||||||
|
|
||||||
|
// Since `D` is not a subtrait of `C`,
|
||||||
|
// we have no obvious lower bound.
|
||||||
|
|
||||||
|
trait D: B {
|
||||||
|
fn hello(&self) {
|
||||||
|
println!("D");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> D for T {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
().hello();
|
||||||
|
//~^ ERROR multiple applicable items in scope
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
error[E0034]: multiple applicable items in scope
|
||||||
|
--> $DIR/no-common-ancestor-2.rs:35:8
|
||||||
|
|
|
||||||
|
LL | ().hello();
|
||||||
|
| ^^^^^ multiple `hello` found
|
||||||
|
|
|
||||||
|
note: candidate #1 is defined in an impl of the trait `A` for the type `T`
|
||||||
|
--> $DIR/no-common-ancestor-2.rs:4:5
|
||||||
|
|
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
note: candidate #2 is defined in an impl of the trait `B` for the type `T`
|
||||||
|
--> $DIR/no-common-ancestor-2.rs:11:5
|
||||||
|
|
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
note: candidate #3 is defined in an impl of the trait `C` for the type `T`
|
||||||
|
--> $DIR/no-common-ancestor-2.rs:18:5
|
||||||
|
|
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
note: candidate #4 is defined in an impl of the trait `D` for the type `T`
|
||||||
|
--> $DIR/no-common-ancestor-2.rs:28:5
|
||||||
|
|
|
||||||
|
LL | fn hello(&self) {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
help: disambiguate the method for candidate #1
|
||||||
|
|
|
||||||
|
LL - ().hello();
|
||||||
|
LL + A::hello(&());
|
||||||
|
|
|
||||||
|
help: disambiguate the method for candidate #2
|
||||||
|
|
|
||||||
|
LL - ().hello();
|
||||||
|
LL + B::hello(&());
|
||||||
|
|
|
||||||
|
help: disambiguate the method for candidate #3
|
||||||
|
|
|
||||||
|
LL - ().hello();
|
||||||
|
LL + C::hello(&());
|
||||||
|
|
|
||||||
|
help: disambiguate the method for candidate #4
|
||||||
|
|
|
||||||
|
LL - ().hello();
|
||||||
|
LL + D::hello(&());
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0034`.
|
Loading…
Add table
Add a link
Reference in a new issue