Rollup merge of #89829 - voidc:assoc-const-variance, r=lcnr

Consider types appearing in const expressions to be invariant

This is an approach to fix #80977.
Currently, a type parameter which is only used in a constant expression is considered bivariant and will trigger error E0392 *"parameter T is never used"*.
Here is a short example:

```rust
pub trait Foo {
    const N: usize;
}

struct Bar<T: Foo>([u8; T::N])
where [(); T::N]:;
```
([playgound](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=b51a272853f75925e72efc1597478aa5))

While it is possible to silence this error by adding a `PhantomData<T>` field, I think the better solution would be to make `T` invariant.
This would be analogous to the invariance constraints added for associated types.
However, I'm quite new to the compiler and unsure whether this is the right approach.

r? ``@varkor`` (since you authored #60058)
This commit is contained in:
Matthias Krüger 2021-10-23 14:58:41 +02:00 committed by GitHub
commit 2b874f0242
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 57 additions and 30 deletions

View file

@ -223,8 +223,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_constraints_from_region(current, lt, variance_i) self.add_constraints_from_region(current, lt, variance_i)
} }
GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i), GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
GenericArgKind::Const(_) => { GenericArgKind::Const(val) => {
// Consts impose no constraints. self.add_constraints_from_const(current, val, variance_i)
} }
} }
} }
@ -263,7 +263,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance); self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
} }
ty::Array(typ, _) => { ty::Array(typ, len) => {
self.add_constraints_from_const(current, len, variance);
self.add_constraints_from_ty(current, typ, variance); self.add_constraints_from_ty(current, typ, variance);
} }
@ -385,13 +386,32 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_constraints_from_region(current, lt, variance_i) self.add_constraints_from_region(current, lt, variance_i)
} }
GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i), GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
GenericArgKind::Const(_) => { GenericArgKind::Const(val) => {
// Consts impose no constraints. self.add_constraints_from_const(current, val, variance)
} }
} }
} }
} }
/// Adds constraints appropriate for a const expression `val`
/// in a context with ambient variance `variance`
fn add_constraints_from_const(
&mut self,
current: &CurrentItem,
val: &ty::Const<'tcx>,
variance: VarianceTermPtr<'a>,
) {
debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance);
match &val.val {
ty::ConstKind::Unevaluated(uv) => {
let substs = uv.substs(self.tcx());
self.add_constraints_from_invariant_substs(current, substs, variance);
}
_ => {}
}
}
/// Adds constraints appropriate for a function with signature /// Adds constraints appropriate for a function with signature
/// `sig` appearing in a context with ambient variance `variance` /// `sig` appearing in a context with ambient variance `variance`
fn add_constraints_from_sig( fn add_constraints_from_sig(

View file

@ -8,15 +8,5 @@ LL | inner: [(); { [|_: &T| {}; 0].len() }],
| |
= help: consider moving this anonymous constant into a `const` function = help: consider moving this anonymous constant into a `const` function
error[E0392]: parameter `T` is never used error: aborting due to previous error
--> $DIR/issue-67375.rs:5:12
|
LL | struct Bug<T> {
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0392`.

View file

@ -3,7 +3,7 @@
#![cfg_attr(full, feature(generic_const_exprs))] #![cfg_attr(full, feature(generic_const_exprs))]
struct Bug<T> { struct Bug<T> {
//~^ ERROR parameter `T` is never used //[min]~^ ERROR parameter `T` is never used
inner: [(); { [|_: &T| {}; 0].len() }], inner: [(); { [|_: &T| {}; 0].len() }],
//[min]~^ ERROR generic parameters may not be used in const operations //[min]~^ ERROR generic parameters may not be used in const operations
//[full]~^^ ERROR overly complex generic constant //[full]~^^ ERROR overly complex generic constant

View file

@ -12,16 +12,6 @@ LL | let x: S = MaybeUninit::uninit();
= note: expected type parameter `S` = note: expected type parameter `S`
found union `MaybeUninit<_>` found union `MaybeUninit<_>`
error[E0392]: parameter `S` is never used error: aborting due to previous error
--> $DIR/issue-67945-1.rs:7:12
|
LL | struct Bug<S> {
| ^ unused parameter
|
= help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `S` to be a const parameter, use `const S: usize` instead
error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`.
Some errors have detailed explanations: E0308, E0392.
For more information about an error, try `rustc --explain E0308`.

View file

@ -5,7 +5,7 @@
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
struct Bug<S> { struct Bug<S> {
//~^ ERROR parameter `S` is never used //[min]~^ ERROR parameter `S` is never used
A: [(); { A: [(); {
let x: S = MaybeUninit::uninit(); let x: S = MaybeUninit::uninit();
//[min]~^ ERROR generic parameters may not be used in const operations //[min]~^ ERROR generic parameters may not be used in const operations

View file

@ -0,0 +1,17 @@
// Test that the variance computation considers types that
// appear in const expressions to be invariant.
#![feature(rustc_attrs)]
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
trait Trait {
const Const: usize;
}
#[rustc_variance]
struct Foo<T: Trait> { //~ ERROR [o]
field: [u8; <T as Trait>::Const]
}
fn main() { }

View file

@ -0,0 +1,10 @@
error[E0208]: [o]
--> $DIR/variance-associated-consts.rs:13:1
|
LL | / struct Foo<T: Trait> {
LL | | field: [u8; <T as Trait>::Const]
LL | | }
| |_^
error: aborting due to previous error