diff options
| author | Manish Goregaokar <manishsmail@gmail.com> | 2022-11-11 12:12:27 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-11 12:12:27 -0500 |
| commit | cd30ccf9744a09fb4fd7d63703a3f29899a5e88d (patch) | |
| tree | 4f54db86605f27c62c03db83547ca906edac3aeb /src | |
| parent | 742d3f02c243964e5b868d90afd60c2907be5853 (diff) | |
| parent | 94f67e667be3efd1845bb95fcd25fcce11cf983c (diff) | |
| download | rust-cd30ccf9744a09fb4fd7d63703a3f29899a5e88d.tar.gz rust-cd30ccf9744a09fb4fd7d63703a3f29899a5e88d.zip | |
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.
Diffstat (limited to 'src')
11 files changed, 284 insertions, 3 deletions
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs new file mode 100644 index 00000000000..3ac90992486 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs @@ -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() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr new file mode 100644 index 00000000000..4aea1979421 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -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`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs new file mode 100644 index 00000000000..9ddea427cfd --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs @@ -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); +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs new file mode 100644 index 00000000000..a3bb9b3f93e --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs @@ -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() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr new file mode 100644 index 00000000000..24766804708 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr @@ -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 + diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs new file mode 100644 index 00000000000..2aac0a2b4d1 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs @@ -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() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs new file mode 100644 index 00000000000..9c2c2cf1610 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs @@ -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() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs new file mode 100644 index 00000000000..1e6b1c6513b --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs @@ -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() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs new file mode 100644 index 00000000000..35aa52fbd4e --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs @@ -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); +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs index ff0cd489d47..9ab170f0920 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs @@ -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 } diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr index 3296c109c4e..843fc6ce84d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr @@ -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 |
