Rollup merge of #95292 - BGR360:const-trait-specialize, r=lcnr

Allow specialized const trait impls.

Fixes #95186.
Fixes #95187.

I've done my best to create a comprehensive test suite for the interaction between `min_specialization` and `const_trait_impls`. I wouldn't be surprised if there are interesting cases I haven't tested, please let me know.
This commit is contained in:
Manish Goregaokar 2022-11-11 12:12:27 -05:00 committed by GitHub
commit cd30ccf974
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 382 additions and 25 deletions

View file

@ -0,0 +1,46 @@
// Tests that trait bounds on specializing trait impls must be `~const` if the
// same bound is present on the default impl and is `~const` there.
#![feature(const_trait_impl)]
#![feature(rustc_attrs)]
#![feature(min_specialization)]
#[rustc_specialization_trait]
trait Specialize {}
#[const_trait]
trait Foo {}
#[const_trait]
trait Bar {}
// bgr360: I was only able to exercise the code path that raises the
// "missing ~const qualifier" error by making this base impl non-const, even
// though that doesn't really make sense to do. As seen below, if the base impl
// is made const, rustc fails earlier with an overlapping impl failure.
impl<T> Bar for T
where
T: ~const Foo,
{}
impl<T> Bar for T
where
T: Foo, //~ ERROR missing `~const` qualifier
T: Specialize,
{}
#[const_trait]
trait Baz {}
impl<T> const Baz for T
where
T: ~const Foo,
{}
impl<T> const Baz for T //~ ERROR conflicting implementations of trait `Baz`
where
T: Foo,
T: Specialize,
{}
fn main() {}

View file

@ -0,0 +1,18 @@
error: missing `~const` qualifier for specialization
--> $DIR/const-default-bound-non-const-specialized-bound.rs:28:8
|
LL | T: Foo,
| ^^^
error[E0119]: conflicting implementations of trait `Baz`
--> $DIR/const-default-bound-non-const-specialized-bound.rs:40:1
|
LL | impl<T> const Baz for T
| ----------------------- first implementation here
...
LL | impl<T> const Baz for T
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0119`.

View file

@ -0,0 +1,39 @@
// Tests that a const default trait impl can be specialized by another const
// trait impl and that the specializing impl will be used during const-eval.
// run-pass
#![feature(const_trait_impl)]
#![feature(min_specialization)]
#[const_trait]
trait Value {
fn value() -> u32;
}
const fn get_value<T: ~const Value>() -> u32 {
T::value()
}
impl<T> const Value for T {
default fn value() -> u32 {
0
}
}
struct FortyTwo;
impl const Value for FortyTwo {
fn value() -> u32 {
42
}
}
const ZERO: u32 = get_value::<()>();
const FORTY_TWO: u32 = get_value::<FortyTwo>();
fn main() {
assert_eq!(ZERO, 0);
assert_eq!(FORTY_TWO, 42);
}

View file

@ -0,0 +1,26 @@
// Tests that specializing trait impls must be at least as const as the default impl.
#![feature(const_trait_impl)]
#![feature(min_specialization)]
#[const_trait]
trait Value {
fn value() -> u32;
}
impl<T> const Value for T {
default fn value() -> u32 {
0
}
}
struct FortyTwo;
impl Value for FortyTwo { //~ ERROR cannot specialize on const impl with non-const impl
fn value() -> u32 {
println!("You can't do that (constly)");
42
}
}
fn main() {}

View file

@ -0,0 +1,8 @@
error: cannot specialize on const impl with non-const impl
--> $DIR/const-default-impl-non-const-specialized-impl.rs:19:1
|
LL | impl Value for FortyTwo {
| ^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -0,0 +1,15 @@
// check-pass
#![feature(const_trait_impl)]
#![feature(min_specialization)]
#[const_trait]
trait Foo {
fn foo();
}
impl const Foo for u32 {
default fn foo() {}
}
fn main() {}

View file

@ -0,0 +1,37 @@
// Tests that `~const` trait bounds can be used to specialize const trait impls.
// check-pass
#![feature(const_trait_impl)]
#![feature(rustc_attrs)]
#![feature(min_specialization)]
#[const_trait]
#[rustc_specialization_trait]
trait Specialize {}
#[const_trait]
trait Foo {}
impl<T> const Foo for T {}
impl<T> const Foo for T
where
T: ~const Specialize,
{}
#[const_trait]
trait Bar {}
impl<T> const Bar for T
where
T: ~const Foo,
{}
impl<T> const Bar for T
where
T: ~const Foo,
T: ~const Specialize,
{}
fn main() {}

View file

@ -0,0 +1,45 @@
// Tests that `T: ~const Foo` in a specializing impl is treated as equivalent to
// `T: Foo` in the default impl for the purposes of specialization (i.e., it
// does not think that the user is attempting to specialize on trait `Foo`).
// check-pass
#![feature(rustc_attrs)]
#![feature(min_specialization)]
#![feature(const_trait_impl)]
#[rustc_specialization_trait]
trait Specialize {}
#[const_trait]
trait Foo {}
#[const_trait]
trait Bar {}
impl<T> Bar for T
where
T: Foo,
{}
impl<T> const Bar for T
where
T: ~const Foo,
T: Specialize,
{}
#[const_trait]
trait Baz {}
impl<T> const Baz for T
where
T: Foo,
{}
impl<T> const Baz for T
where
T: ~const Foo,
T: Specialize,
{}
fn main() {}

View file

@ -0,0 +1,39 @@
// Tests that a non-const default impl can be specialized by a const trait impl,
// but that the default impl cannot be used in a const context.
// run-pass
#![feature(const_trait_impl)]
#![feature(min_specialization)]
#[const_trait]
trait Value {
fn value() -> u32;
}
const fn get_value<T: ~const Value>() -> u32 {
T::value()
}
impl<T> Value for T {
default fn value() -> u32 {
println!("You can't do that (constly)");
0
}
}
struct FortyTwo;
impl const Value for FortyTwo {
fn value() -> u32 {
42
}
}
fn main() {
let zero = get_value::<()>();
assert_eq!(zero, 0);
const FORTY_TWO: u32 = get_value::<FortyTwo>();
assert_eq!(FORTY_TWO, 42);
}

View file

@ -17,7 +17,9 @@ impl<T: ~const Default> const A for T {
}
}
impl<T: Default + Sup> A for T { //~ ERROR: cannot specialize
impl<T: Default + Sup> A for T {
//~^ ERROR: cannot specialize
//~| ERROR: missing `~const` qualifier
fn a() -> u32 {
3
}

View file

@ -1,8 +1,14 @@
error: cannot specialize on trait `Default`
error: cannot specialize on const impl with non-const impl
--> $DIR/specializing-constness.rs:20:1
|
LL | impl<T: Default + Sup> A for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing `~const` qualifier for specialization
--> $DIR/specializing-constness.rs:20:9
|
LL | impl<T: Default + Sup> A for T {
| ^^^^^^^
error: aborting due to previous error
error: aborting due to 2 previous errors