Skip to content

Commit fbb1428

Browse files
Rollup merge of rust-lang#160520 - jackh726:specialization-tests, r=nikomatsakis
Add some tests for specialization cc rust-lang#31844 (specialization tracking issue) Closes rust-lang#32483 (fixed) Closes rust-lang#48515 (fixed) Closes rust-lang#52396 (fixed) Closes rust-lang#74809 (fixed) Closes rust-lang#77026 (fixed) Closes rust-lang#80700 (fixed) Closes rust-lang#126268 (dupe of rust-lang#102252) cc. rust-lang#50318 (known-bug) cc. rust-lang#36262 (known-bug, fixed-by-next-solver) cc. rust-lang#125014 (known-bug, fixed-by-next-solver) r? nikomatsakis Disclosure: These issues are from Github, but I used an LLM to help copy them over. I reviewed all tests.
2 parents e2c89eb + 6794814 commit fbb1428

18 files changed

Lines changed: 808 additions & 18 deletions
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
//@ known-bug: #126268
1+
//@ known-bug: #102252
2+
23
#![feature(min_specialization)]
34

45
trait Trait {}
@@ -16,3 +17,5 @@ struct DatasetIter<'a, R: Data> {
1617
pub struct ArrayBase {}
1718

1819
impl<'a> Trait for DatasetIter<'a, ArrayBase> {}
20+
21+
fn main() {}

tests/crashes/125014.rs

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//@ check-pass
2+
3+
#![allow(incomplete_features)]
4+
#![feature(specialization)]
5+
6+
// Tests that you can use a trait's associated types in the bounds of a default impl.
7+
// Regression test for #52396.
8+
9+
trait Foo {
10+
type Baz;
11+
fn bar(&self, _: Self::Baz);
12+
}
13+
14+
default impl<A: Foo<Baz = isize>> Foo for A {
15+
fn bar(&self, _: isize) { }
16+
}
17+
18+
fn main() {}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@ check-pass
2+
3+
#![feature(specialization)]
4+
#![allow(incomplete_features)]
5+
6+
// Tests that a blanket impl supplying a `default type` does not make a
7+
// recursive trait requirement diverge.
8+
// Regression test for #80700.
9+
10+
use std::marker::PhantomData;
11+
12+
struct Nil;
13+
struct Cons<Head, Tail>(PhantomData<(Head, Tail)>);
14+
struct Error;
15+
16+
trait GetLast {
17+
type Output;
18+
}
19+
20+
impl<T> GetLast for T {
21+
default type Output = Error;
22+
}
23+
24+
impl<Head> GetLast for Cons<Head, Nil> {
25+
type Output = Nil;
26+
}
27+
28+
impl<Head, Head2, Tail2> GetLast for Cons<Head, Cons<Head2, Tail2>>
29+
where
30+
Cons<Head2, Tail2>: GetLast,
31+
{
32+
type Output = <Cons<Head2, Tail2> as GetLast>::Output;
33+
}
34+
35+
fn main() {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//@ check-fail
2+
3+
#![feature(specialization)]
4+
#![allow(incomplete_features)]
5+
6+
// `default impl` still participates in coherence. However, we shouldn't get an overflow here.
7+
// Regresion test for #77026.
8+
9+
pub enum Either<L, R> {
10+
Left(L),
11+
Right(R),
12+
}
13+
14+
default impl<L, R> From<L> for Either<L, R> {
15+
fn from(l: L) -> Self {
16+
Either::Left(l)
17+
}
18+
}
19+
20+
impl<L, R> From<R> for Either<L, R> {
21+
//~^ ERROR conflicting implementations of trait `From<_>` for type `Either<_, _>`
22+
fn from(r: R) -> Self {
23+
Either::Right(r)
24+
}
25+
}
26+
27+
fn main() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0119]: conflicting implementations of trait `From<_>` for type `Either<_, _>`
2+
--> $DIR/default-impl-coherence-overlap-issue-77026.rs:20:1
3+
|
4+
LL | default impl<L, R> From<L> for Either<L, R> {
5+
| ------------------------------------------- first implementation here
6+
...
7+
LL | impl<L, R> From<R> for Either<L, R> {
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Either<_, _>`
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0119`.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//@ check-fail
2+
3+
#![feature(specialization)]
4+
#![allow(incomplete_features)]
5+
6+
// Tests that we don't overflow when using `default impl`.
7+
// Regression test for #48515, #98478, and #117909.
8+
9+
// #48515
10+
11+
trait TypeString {
12+
fn type_string() -> &'static str;
13+
}
14+
15+
default impl<T> TypeString for T {
16+
fn type_string() -> &'static str {
17+
"unknown type"
18+
}
19+
}
20+
21+
impl TypeString for () {
22+
fn type_string() -> &'static str {
23+
"()"
24+
}
25+
}
26+
27+
// #98478
28+
29+
trait Spam {}
30+
31+
trait SpamMore: Spam {}
32+
33+
default impl<T> Spam for T where T: SpamMore {}
34+
35+
struct A;
36+
37+
impl SpamMore for A {}
38+
//~^ ERROR the trait bound `A: Spam` is not satisfied
39+
40+
fn needs_spam<T: Spam>() {}
41+
42+
// #117909
43+
44+
trait Set<T> {
45+
fn contains(&self, bit: T);
46+
}
47+
48+
default impl<T, S> Set<&T> for S
49+
where
50+
S: Set<T>,
51+
{
52+
fn contains(&self, _: &T) {}
53+
}
54+
55+
fn main() {
56+
let _ = <usize as TypeString>::type_string();
57+
//~^ ERROR the trait bound `usize: TypeString` is not satisfied
58+
59+
needs_spam::<A>();
60+
//~^ ERROR the trait bound `A: Spam` is not satisfied
61+
62+
0u32.contains(());
63+
//~^ ERROR no method named `contains` found for type `u32` in the current scope
64+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
error[E0277]: the trait bound `A: Spam` is not satisfied
2+
--> $DIR/default-impl-not-a-candidate-issue-48515.rs:37:19
3+
|
4+
LL | impl SpamMore for A {}
5+
| ^ unsatisfied trait bound
6+
|
7+
help: the trait `Spam` is not implemented for `A`
8+
--> $DIR/default-impl-not-a-candidate-issue-48515.rs:35:1
9+
|
10+
LL | struct A;
11+
| ^^^^^^^^
12+
note: required by a bound in `SpamMore`
13+
--> $DIR/default-impl-not-a-candidate-issue-48515.rs:31:17
14+
|
15+
LL | trait SpamMore: Spam {}
16+
| ^^^^ required by this bound in `SpamMore`
17+
18+
error[E0277]: the trait bound `usize: TypeString` is not satisfied
19+
--> $DIR/default-impl-not-a-candidate-issue-48515.rs:56:14
20+
|
21+
LL | let _ = <usize as TypeString>::type_string();
22+
| ^^^^^ the trait `TypeString` is not implemented for `usize`
23+
|
24+
help: the trait `TypeString` is implemented for `()`
25+
--> $DIR/default-impl-not-a-candidate-issue-48515.rs:21:1
26+
|
27+
LL | impl TypeString for () {
28+
| ^^^^^^^^^^^^^^^^^^^^^^
29+
30+
error[E0277]: the trait bound `A: Spam` is not satisfied
31+
--> $DIR/default-impl-not-a-candidate-issue-48515.rs:59:18
32+
|
33+
LL | needs_spam::<A>();
34+
| ^ unsatisfied trait bound
35+
|
36+
help: the trait `Spam` is not implemented for `A`
37+
--> $DIR/default-impl-not-a-candidate-issue-48515.rs:35:1
38+
|
39+
LL | struct A;
40+
| ^^^^^^^^
41+
note: required by a bound in `needs_spam`
42+
--> $DIR/default-impl-not-a-candidate-issue-48515.rs:40:18
43+
|
44+
LL | fn needs_spam<T: Spam>() {}
45+
| ^^^^ required by this bound in `needs_spam`
46+
47+
error[E0599]: no method named `contains` found for type `u32` in the current scope
48+
--> $DIR/default-impl-not-a-candidate-issue-48515.rs:62:10
49+
|
50+
LL | 0u32.contains(());
51+
| ^^^^^^^^ method not found in `u32`
52+
|
53+
= help: items from traits can only be used if the trait is implemented and in scope
54+
note: `Set` defines an item `contains`, perhaps you need to implement it
55+
--> $DIR/default-impl-not-a-candidate-issue-48515.rs:44:1
56+
|
57+
LL | trait Set<T> {
58+
| ^^^^^^^^^^^^
59+
60+
error: aborting due to 4 previous errors
61+
62+
Some errors have detailed explanations: E0277, E0599.
63+
For more information about an error, try `rustc --explain E0277`.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//@ check-fail
2+
3+
#![feature(specialization)]
4+
#![allow(incomplete_features)]
5+
6+
// Tests that a `default impl` does not count as an *actual* impl, so it cannot
7+
// be used to satisfy trait bounds.
8+
9+
// A `default impl` may omit trait items, but a real impl may not.
10+
11+
trait Gapped {
12+
fn a(&self) -> u32;
13+
fn b(&self) -> u32;
14+
}
15+
16+
default impl<T> Gapped for T {
17+
fn a(&self) -> u32 {
18+
1
19+
}
20+
}
21+
22+
impl Gapped for u8 {}
23+
//~^ ERROR not all trait items implemented, missing: `b`
24+
25+
// A `default impl` that defines *every* trait item is still not an impl.
26+
27+
trait Foo {
28+
fn f(&self) -> u32;
29+
}
30+
31+
default impl<T> Foo for T {
32+
fn f(&self) -> u32 {
33+
1
34+
}
35+
}
36+
37+
fn need_foo<T: Foo>(t: &T) -> u32 {
38+
t.f()
39+
}
40+
41+
trait Bar {
42+
fn b(&self) -> u32;
43+
}
44+
45+
impl<T: Foo> Bar for T {
46+
fn b(&self) -> u32 {
47+
self.f()
48+
}
49+
}
50+
51+
fn need_bar<T: Bar>(t: &T) -> u32 {
52+
t.b()
53+
}
54+
55+
fn main() {
56+
// as a bound (UFCS `<u32 as Foo>::f` is the same trait-selection path, omitted)
57+
need_foo(&0u32);
58+
//~^ ERROR the trait bound `u32: Foo` is not satisfied
59+
60+
// as a method-probe candidate
61+
0u32.f();
62+
//~^ ERROR no method named `f` found for type `u32` in the current scope
63+
64+
// when building a vtable
65+
let _: &dyn Foo = &0u32;
66+
//~^ ERROR the trait bound `u32: Foo` is not satisfied
67+
68+
// transitively, as another impl's where-clause
69+
need_bar(&0i64);
70+
//~^ ERROR the trait bound `i64: Bar` is not satisfied
71+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
error[E0046]: not all trait items implemented, missing: `b`
2+
--> $DIR/default-impl-not-an-impl.rs:22:1
3+
|
4+
LL | fn b(&self) -> u32;
5+
| ------------------- `b` from trait
6+
...
7+
LL | impl Gapped for u8 {}
8+
| ^^^^^^^^^^^^^^^^^^ missing `b` in implementation
9+
10+
error[E0277]: the trait bound `u32: Foo` is not satisfied
11+
--> $DIR/default-impl-not-an-impl.rs:57:14
12+
|
13+
LL | need_foo(&0u32);
14+
| -------- ^^^^^ the trait `Foo` is not implemented for `u32`
15+
| |
16+
| required by a bound introduced by this call
17+
|
18+
note: required by a bound in `need_foo`
19+
--> $DIR/default-impl-not-an-impl.rs:37:16
20+
|
21+
LL | fn need_foo<T: Foo>(t: &T) -> u32 {
22+
| ^^^ required by this bound in `need_foo`
23+
24+
error[E0599]: no method named `f` found for type `u32` in the current scope
25+
--> $DIR/default-impl-not-an-impl.rs:61:10
26+
|
27+
LL | 0u32.f();
28+
| ^ method not found in `u32`
29+
|
30+
= help: items from traits can only be used if the trait is implemented and in scope
31+
note: `Foo` defines an item `f`, perhaps you need to implement it
32+
--> $DIR/default-impl-not-an-impl.rs:27:1
33+
|
34+
LL | trait Foo {
35+
| ^^^^^^^^^
36+
37+
error[E0277]: the trait bound `u32: Foo` is not satisfied
38+
--> $DIR/default-impl-not-an-impl.rs:65:23
39+
|
40+
LL | let _: &dyn Foo = &0u32;
41+
| ^^^^^ the trait `Foo` is not implemented for `u32`
42+
|
43+
= note: required for the cast from `&u32` to `&dyn Foo`
44+
45+
error[E0277]: the trait bound `i64: Bar` is not satisfied
46+
--> $DIR/default-impl-not-an-impl.rs:69:14
47+
|
48+
LL | need_bar(&0i64);
49+
| -------- ^^^^^ the trait `Foo` is not implemented for `i64`
50+
| |
51+
| required by a bound introduced by this call
52+
|
53+
note: required for `i64` to implement `Bar`
54+
--> $DIR/default-impl-not-an-impl.rs:45:14
55+
|
56+
LL | impl<T: Foo> Bar for T {
57+
| --- ^^^ ^
58+
| |
59+
| unsatisfied trait bound introduced here
60+
note: required by a bound in `need_bar`
61+
--> $DIR/default-impl-not-an-impl.rs:51:16
62+
|
63+
LL | fn need_bar<T: Bar>(t: &T) -> u32 {
64+
| ^^^ required by this bound in `need_bar`
65+
66+
error: aborting due to 5 previous errors
67+
68+
Some errors have detailed explanations: E0046, E0277, E0599.
69+
For more information about an error, try `rustc --explain E0046`.

0 commit comments

Comments
 (0)