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:
commit
cd30ccf974
12 changed files with 382 additions and 25 deletions
|
|
@ -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() {}
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue