-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider types appearing in const expressions to be invariant #89829
Conversation
This comment has been minimized.
This comment has been minimized.
Thanks for the PR 👍 I am a bit unsure about this. As variance shouldn't influence the result of const eval (and any well formed requirements are checked for the parent anyways) we could let parameters only used in constants be bivariant afaik. Now, doing that doesn't actually fix the "unused parameter" errors, as these get triggered for all bivariant parameters which are not the target of a projection. We could change this to also allow bivariant parameters if they are used by constants, which I probably prefer 🤔 Making the substs invariant prevents the following from compiling, which is a bit unfortunate: #![feature(generic_const_exprs)]
struct Foo<'a>([&'a u32; std::mem::size_of::<&'a u32>()]);
fn covariant<'a>(v: &'a Foo<'static>) -> &'a Foo<'a> {
v
} We generally have the issue that Considering the generic parameters used by constants to be "actually used" therefore has some forward compatibility concerns (once #![feature(generic_const_exprs)]
struct Foo<T, const N: usize>([u8; N + 1]) where [u8; N + 1]: Trait<T>;
trait Trait<T> {}
impl<T, U> Trait<T> for U {} The way we currently intend to filter the generic arguments supplied to anonymous constants should end up considering This will probably be fine as writing code like that by accident is probably pretty rare, so even if this causes theoretical breakage, it shouldn't be an issue in real code. Another solution to this far off potential breakage would be to change the "parameter never used" errors to be a deny by default lint. Having generic parameters be unused or bivariant isn't unsound so this way we should be able to allow this as a lint.
@rust-lang/project-const-generics thoughts here? |
talked with @nikomatsakis about this and came to the following conclusions if i remember correctly:
#![feature(generic_const_exprs)]
use std::marker::PhantomData;
trait SadBee {
const ASSOC: usize;
}
// fn(&'static ())` is a supertype of `for<'a> fn(&'a ())` while
// we allow two different impls for these types, leading
// to different const eval results.
impl SadBee for for<'a> fn(&'a ()) {
const ASSOC: usize = 0;
}
impl SadBee for fn(&'static ()) {
const ASSOC: usize = 100;
}
struct Foo<T: SadBee>([u8; <T as SadBee>::ASSOC], PhantomData<T>) where [(); <T as SadBee>::ASSOC]:,;
fn covariant(v: &'static Foo<for<'a> fn(&'a ())>) -> &'static Foo<fn(&'static ())> {
v
}
fn main() {
let y = covariant(&Foo([], PhantomData));
println!("{:?}", y.0);
}
|
going to approve this PR even if it was previously a draft as it looks ready to me. Good job 👍 @bors r+ |
📌 Commit a400f10 has been approved by |
Consider types appearing in const expressions to be invariant This is an approach to fix rust-lang#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 rust-lang#60058)
…askrgr Rollup of 5 pull requests Successful merges: - rust-lang#85833 (Scrape code examples from examples/ directory for Rustdoc) - rust-lang#88041 (Make all proc-macro back-compat lints deny-by-default) - rust-lang#89829 (Consider types appearing in const expressions to be invariant) - rust-lang#90168 (Reset qualifs when a storage of a local ends) - rust-lang#90198 (Add caveat about changing parallelism and function call overhead) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
add const generics test cc rust-lang#89829 (comment) r? rust-lang/project-const-generics
add const generics test cc rust-lang#89829 (comment) r? rust-lang/project-const-generics
add const generics test cc rust-lang#89829 (comment) r? rust-lang/project-const-generics
add const generics test cc rust-lang#89829 (comment) r? rust-lang/project-const-generics
add const generics test cc rust-lang#89829 (comment) r? rust-lang/project-const-generics
add const generics test cc rust-lang#89829 (comment) r? rust-lang/project-const-generics
add const generics test cc rust-lang#89829 (comment) r? rust-lang/project-const-generics
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:
(playgound)
While it is possible to silence this error by adding a
PhantomData<T>
field, I think the better solution would be to makeT
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)