Rollup merge of #155172 - jackh726:supertrait-shadowing-cleanup, r=lcnr

Some small nits for supertrait_item_shadowing, and additional testing

cc rust-lang/rust#89151

r? types
This commit is contained in:
Jacob Pratt
2026-04-14 23:02:33 -04:00
committed by GitHub
26 changed files with 251 additions and 149 deletions
@@ -2377,8 +2377,8 @@ fn collapse_candidates_to_subtrait_pick(
continue;
}
// This pick is not a supertrait of the `child_pick`.
// Check if it's a subtrait of the `child_pick`, instead.
// This candidate is not a supertrait of the `child_trait`.
// Check if it's a subtrait of the `child_trait`, 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.
@@ -2392,7 +2392,8 @@ fn collapse_candidates_to_subtrait_pick(
continue;
}
// `child_pick` is not a supertrait of this pick.
// Neither `child_trait` or the current candidate are
// supertraits of each other.
// 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
@@ -1,5 +1,4 @@
//@ run-pass
//@ check-run-results
#![feature(supertrait_item_shadowing)]
#![allow(dead_code)]
@@ -19,5 +18,5 @@ impl<T> B for T {
}
fn main() {
println!("{}", i32::CONST);
assert_eq!(i32::CONST, 2)
}
@@ -1 +0,0 @@
2
@@ -0,0 +1,22 @@
#![feature(staged_api)]
#![stable(feature = "main", since = "1.0.0")]
#[stable(feature = "main", since = "1.0.0")]
pub trait A {
#[stable(feature = "main", since = "1.0.0")]
fn hello(&self) -> &'static str {
"A"
}
}
#[stable(feature = "main", since = "1.0.0")]
impl<T> A for T {}
#[stable(feature = "main", since = "1.0.0")]
pub trait B: A {
#[unstable(feature = "downstream", issue = "none")]
fn hello(&self) -> &'static str {
"B"
}
}
#[stable(feature = "main", since = "1.0.0")]
impl<T> B for T {}
@@ -1,5 +1,4 @@
//@ run-pass
//@ check-run-results
#![feature(supertrait_item_shadowing)]
#![warn(resolving_to_items_shadowing_supertrait_items)]
@@ -7,28 +6,28 @@
#![allow(dead_code)]
trait A {
fn hello(&self) {
println!("A");
fn hello(&self) -> &'static str {
"A"
}
}
impl<T> A for T {}
trait B {
fn hello(&self) {
println!("B");
fn hello(&self) -> &'static str {
"B"
}
}
impl<T> B for T {}
trait C: A + B {
fn hello(&self) {
fn hello(&self) -> &'static str {
//~^ WARN trait item `hello` from `C` shadows identically named item
println!("C");
"C"
}
}
impl<T> C for T {}
fn main() {
().hello();
assert_eq!(().hello(), "C");
//~^ WARN trait item `hello` from `C` shadows identically named item from supertrait
}
@@ -1,44 +1,44 @@
warning: trait item `hello` from `C` shadows identically named item from supertrait
--> $DIR/common-ancestor-2.rs:24:5
--> $DIR/common-ancestor-2.rs:23:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: items from several supertraits are shadowed: `B` and `A`
--> $DIR/common-ancestor-2.rs:10:5
--> $DIR/common-ancestor-2.rs:9:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor-2.rs:6:9
--> $DIR/common-ancestor-2.rs:5:9
|
LL | #![warn(shadowing_supertrait_items)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: trait item `hello` from `C` shadows identically named item from supertrait
--> $DIR/common-ancestor-2.rs:32:8
--> $DIR/common-ancestor-2.rs:31:19
|
LL | ().hello();
| ^^^^^
LL | assert_eq!(().hello(), "C");
| ^^^^^
|
note: item from `C` shadows a supertrait item
--> $DIR/common-ancestor-2.rs:24:5
--> $DIR/common-ancestor-2.rs:23:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: items from several supertraits are shadowed: `A` and `B`
--> $DIR/common-ancestor-2.rs:10:5
--> $DIR/common-ancestor-2.rs:9:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor-2.rs:5:9
--> $DIR/common-ancestor-2.rs:4:9
|
LL | #![warn(resolving_to_items_shadowing_supertrait_items)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1,5 +1,4 @@
//@ run-pass
//@ check-run-results
#![feature(supertrait_item_shadowing)]
#![warn(resolving_to_items_shadowing_supertrait_items)]
@@ -7,23 +6,23 @@
#![allow(dead_code)]
trait A {
fn hello(&self) {
println!("A");
fn hello(&self) -> &'static str {
"A"
}
}
impl<T> A for T {}
trait B {
fn hello(&self) {
println!("B");
fn hello(&self) -> &'static str {
"B"
}
}
impl<T> B for T {}
trait C: A + B {
fn hello(&self) {
fn hello(&self) -> &'static str {
//~^ WARN trait item `hello` from `C` shadows identically named item
println!("C");
"C"
}
}
impl<T> C for T {}
@@ -31,14 +30,14 @@ impl<T> C for T {}
// `D` extends `C` which extends `B` and `A`
trait D: C {
fn hello(&self) {
fn hello(&self) -> &'static str {
//~^ WARN trait item `hello` from `D` shadows identically named item
println!("D");
"D"
}
}
impl<T> D for T {}
fn main() {
().hello();
assert_eq!(().hello(), "D");
//~^ WARN trait item `hello` from `D` shadows identically named item from supertrait
}
@@ -1,65 +1,65 @@
warning: trait item `hello` from `C` shadows identically named item from supertrait
--> $DIR/common-ancestor-3.rs:24:5
--> $DIR/common-ancestor-3.rs:23:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: items from several supertraits are shadowed: `B` and `A`
--> $DIR/common-ancestor-3.rs:10:5
--> $DIR/common-ancestor-3.rs:9:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor-3.rs:6:9
--> $DIR/common-ancestor-3.rs:5:9
|
LL | #![warn(shadowing_supertrait_items)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: trait item `hello` from `D` shadows identically named item from supertrait
--> $DIR/common-ancestor-3.rs:34:5
--> $DIR/common-ancestor-3.rs:33:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: items from several supertraits are shadowed: `C`, `B`, and `A`
--> $DIR/common-ancestor-3.rs:10:5
--> $DIR/common-ancestor-3.rs:9:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: trait item `hello` from `D` shadows identically named item from supertrait
--> $DIR/common-ancestor-3.rs:42:8
--> $DIR/common-ancestor-3.rs:41:19
|
LL | ().hello();
| ^^^^^
LL | assert_eq!(().hello(), "D");
| ^^^^^
|
note: item from `D` shadows a supertrait item
--> $DIR/common-ancestor-3.rs:34:5
--> $DIR/common-ancestor-3.rs:33:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: items from several supertraits are shadowed: `A`, `B`, and `C`
--> $DIR/common-ancestor-3.rs:10:5
--> $DIR/common-ancestor-3.rs:9:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor-3.rs:5:9
--> $DIR/common-ancestor-3.rs:4:9
|
LL | #![warn(resolving_to_items_shadowing_supertrait_items)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1,5 +1,4 @@
//@ run-pass
//@ check-run-results
#![feature(supertrait_item_shadowing)]
#![warn(resolving_to_items_shadowing_supertrait_items)]
@@ -7,21 +6,21 @@
#![allow(dead_code)]
trait A {
fn hello(&self) {
println!("A");
fn hello(&self) -> &'static str {
"A"
}
}
impl<T> A for T {}
trait B: A {
fn hello(&self) {
fn hello(&self) -> &'static str {
//~^ WARN trait item `hello` from `B` shadows identically named item
println!("B");
"B"
}
}
impl<T> B for T {}
fn main() {
().hello();
assert_eq!(().hello(), "B");
//~^ WARN trait item `hello` from `B` shadows identically named item from supertrait
}
@@ -1 +0,0 @@
B
@@ -1,38 +1,38 @@
warning: trait item `hello` from `B` shadows identically named item from supertrait
--> $DIR/common-ancestor.rs:17:5
--> $DIR/common-ancestor.rs:16:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: item from `A` is shadowed by a subtrait item
--> $DIR/common-ancestor.rs:10:5
--> $DIR/common-ancestor.rs:9:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor.rs:6:9
--> $DIR/common-ancestor.rs:5:9
|
LL | #![warn(shadowing_supertrait_items)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: trait item `hello` from `B` shadows identically named item from supertrait
--> $DIR/common-ancestor.rs:25:8
--> $DIR/common-ancestor.rs:24:19
|
LL | ().hello();
| ^^^^^
LL | assert_eq!(().hello(), "B");
| ^^^^^
|
note: item from `B` shadows a supertrait item
--> $DIR/common-ancestor.rs:17:5
--> $DIR/common-ancestor.rs:16:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: item from `A` is shadowed by a subtrait item
--> $DIR/common-ancestor.rs:10:5
--> $DIR/common-ancestor.rs:9:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor.rs:5:9
--> $DIR/common-ancestor.rs:4:9
|
LL | #![warn(resolving_to_items_shadowing_supertrait_items)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1,22 +1,22 @@
#![feature(supertrait_item_shadowing)]
trait A {
fn hello(&self) {
println!("A");
fn hello(&self) -> &'static str {
"A"
}
}
impl<T> A for T {}
trait B {
fn hello(&self) {
println!("B");
fn hello(&self) -> &'static str {
"B"
}
}
impl<T> B for T {}
trait C: A + B {
fn hello(&self) {
println!("C");
fn hello(&self) -> &'static str {
"C"
}
}
impl<T> C for T {}
@@ -25,8 +25,8 @@ impl<T> C for T {}
// we have no obvious lower bound.
trait D: B {
fn hello(&self) {
println!("D");
fn hello(&self) -> &'static str {
"D"
}
}
impl<T> D for T {}
@@ -7,23 +7,23 @@ LL | ().hello();
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) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL - ().hello();
@@ -1,15 +1,15 @@
#![feature(supertrait_item_shadowing)]
trait A {
fn hello(&self) {
println!("A");
fn hello(&self) -> &'static str {
"A"
}
}
impl<T> A for T {}
trait B {
fn hello(&self) {
println!("B");
fn hello(&self) -> &'static str {
"B"
}
}
impl<T> B for T {}
@@ -7,13 +7,13 @@ LL | ().hello();
note: candidate #1 is defined in an impl of the trait `A` for the type `T`
--> $DIR/no-common-ancestor.rs:4:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `B` for the type `T`
--> $DIR/no-common-ancestor.rs:11:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
LL | fn hello(&self) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL - ().hello();
@@ -1,24 +1,23 @@
//@ run-pass
//@ check-run-results
#![allow(dead_code)]
mod out_of_scope {
pub trait Subtrait: super::Supertrait {
fn hello(&self) {
println!("subtrait");
fn hello(&self) -> &'static str {
"subtrait"
}
}
impl<T> Subtrait for T {}
}
trait Supertrait {
fn hello(&self) {
println!("supertrait");
fn hello(&self) -> &'static str {
"supertrait"
}
}
impl<T> Supertrait for T {}
fn main() {
().hello();
assert_eq!(().hello(), "supertrait");
}
@@ -1 +0,0 @@
supertrait
@@ -1,20 +1,23 @@
//@ check-pass
//@ run-pass
// Make sure we don't prefer a subtrait that we would've otherwise eliminated
// in `consider_probe` during method probing.
#![feature(supertrait_item_shadowing)]
#![allow(dead_code)]
struct W<T>(T);
trait Upstream {
fn hello(&self) {}
fn hello(&self) -> &'static str {
"upstream"
}
}
impl<T> Upstream for T {}
trait Downstream: Upstream {
fn hello(&self) {}
fn hello(&self) -> &'static str {
"downstream"
}
}
impl<T> Downstream for W<T> where T: Foo {}
@@ -22,5 +25,5 @@ trait Foo {}
fn main() {
let x = W(1i32);
x.hello();
assert_eq!(x.hello(), "upstream");
}
@@ -1,5 +1,4 @@
//@ run-pass
//@ check-run-results
// Makes sure we can shadow with type-dependent method syntax.
@@ -7,23 +6,23 @@
#![allow(dead_code)]
trait A {
fn hello() {
println!("A");
fn hello() -> &'static str {
"A"
}
}
impl<T> A for T {}
trait B: A {
fn hello() {
println!("B");
fn hello() -> &'static str {
"B"
}
}
impl<T> B for T {}
fn foo<T>() {
T::hello();
fn foo<T>() -> &'static str {
T::hello()
}
fn main() {
foo::<()>();
assert_eq!(foo::<()>(), "B");
}
@@ -1 +0,0 @@
B
@@ -0,0 +1,17 @@
warning: a method with this name may be added to the standard library in the future
--> $DIR/unstable.rs:26:19
|
LL | assert_eq!(().hello(), "A");
| ^^^^^
|
= help: call with fully qualified syntax `shadowed_stability::A::hello(...)` to keep using the current method
= warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior!
= note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919>
= note: `#[warn(unstable_name_collisions)]` (part of `#[warn(future_incompatible)]`) on by default
help: add `#![feature(downstream)]` to the crate attributes to enable `shadowed_stability::B::hello`
|
LL + #![feature(downstream)]
|
warning: 1 warning emitted
@@ -0,0 +1,17 @@
warning: a method with this name may be added to the standard library in the future
--> $DIR/unstable.rs:26:19
|
LL | assert_eq!(().hello(), "A");
| ^^^^^
|
= help: call with fully qualified syntax `shadowed_stability::A::hello(...)` to keep using the current method
= warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior!
= note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919>
= note: `#[warn(unstable_name_collisions)]` (part of `#[warn(future_incompatible)]`) on by default
help: add `#![feature(downstream)]` to the crate attributes to enable `shadowed_stability::B::hello`
|
LL + #![feature(downstream)]
|
warning: 1 warning emitted
@@ -0,0 +1,22 @@
error[E0034]: multiple applicable items in scope
--> $DIR/unstable.rs:30:19
|
LL | assert_eq!(().hello(), "B");
| ^^^^^ multiple `hello` found
|
= note: candidate #1 is defined in an impl of the trait `shadowed_stability::A` for the type `T`
= note: candidate #2 is defined in an impl of the trait `shadowed_stability::B` for the type `T`
help: disambiguate the method for candidate #1
|
LL - assert_eq!(().hello(), "B");
LL + assert_eq!(shadowed_stability::A::hello(&()), "B");
|
help: disambiguate the method for candidate #2
|
LL - assert_eq!(().hello(), "B");
LL + assert_eq!(shadowed_stability::B::hello(&()), "B");
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0034`.
@@ -0,0 +1,32 @@
// This tests the interaction of feature staging and supertrait item shadowing.
// When a feature is *off*, then we should not consider unstable methods for probing.
// When a feature is *on*, then we follow the normal supertrait item shadowing rules:
// - When supertrait item shadowing is disabled, this is a clash.
// - When supertrait item shadowing is enabled, we pick subtraits.
//@ aux-build: shadowed_stability.rs
//@ revisions: off_normal on_normal off_shadowing on_shadowing
//@[off_normal] run-pass
//@[on_normal] check-fail
//@[off_shadowing] run-pass
//@[on_shadowing] run-pass
//@ check-run-results
#![allow(dead_code, unused_features, unused_imports)]
#![cfg_attr(on_shadowing, feature(downstream))]
#![cfg_attr(on_normal, feature(downstream))]
#![cfg_attr(off_shadowing, feature(supertrait_item_shadowing))]
#![cfg_attr(on_shadowing, feature(supertrait_item_shadowing))]
extern crate shadowed_stability;
use shadowed_stability::*;
fn main() {
#[cfg(any(off_normal, off_shadowing))]
assert_eq!(().hello(), "A");
//[off_normal,off_shadowing]~^ WARN a method with this name may be added
//[off_normal,off_shadowing]~| WARN once this associated item is added
#[cfg(any(on_normal, on_shadowing))]
assert_eq!(().hello(), "B");
//[on_normal]~^ ERROR multiple applicable items in scope
}