Description
The following fails to compile, incorrectly/inconsistently reporting ResursiveGenCovariant<T>
as invariant over T
:
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
pub struct ResursiveGenCovariant<T> {
// assure_covariant(...) does compile:
// - without `_links`, or
// - without `generic_const_exprs`, or
// - with the array size of `links` being not an expression (such as `0*0`),
// but a literal (such as `0`).
_links: [Option<Box<ResursiveGenCovariant<T>>>; 0*0],
_p: core::marker::PhantomData<T>
}
#[allow(dead_code)]
fn assure_covariant<'new>(v: ResursiveGenCovariant<&'static ()>) -> ResursiveGenCovariant<&'new ()> {
v
}
Error:
10 | fn assure_covariant<'new>(v: R...
| ---- lifetime `'new` defined here
11 | v
| ^ returning this value requires that `'new` must outlive `'static`
|
= note: requirement occurs because of the type `ResursiveGenCovariant<&()>`, which makes the generic argument `&()` invariant
= note: the struct `ResursiveGenCovariant<T>` is invariant over the parameter `T`
However, the following alternatives do compile (in the order respective to the changes listed in the comment above; the middle one fails with both 1.69.0-nightly (44cfafe2f 2023-03-03)
and stable 1.67.1 (d5a82bbd2 2023-02-07)
). Same code as above (without the above comments), with changes marked with new comments:
Alternative 1:
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
pub struct ResursiveGenCovariant<T> {
// no _links
_p: core::marker::PhantomData<T>
}
#[allow(dead_code)]
fn assure_covariant<'new>(v: ResursiveGenCovariant<&'static ()>) -> ResursiveGenCovariant<&'new ()> {
v
}
Alternative 2:
// no generic_const_exprs
pub struct ResursiveGenCovariant<T> {
_links: [Option<Box<ResursiveGenCovariant<T>>>; 0*0],
_p: core::marker::PhantomData<T>
}
#[allow(dead_code)]
fn assure_covariant<'new>(v: ResursiveGenCovariant<&'static ()>) -> ResursiveGenCovariant<&'new ()> {
v
}
Alternative 3:
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
pub struct ResursiveGenCovariant<T> {
_links: [Option<Box<ResursiveGenCovariant<T>>>; 0], // <-- 0*0 changed to 0
_p: core::marker::PhantomData<T>
}
#[allow(dead_code)]
fn assure_covariant<'new>(v: ResursiveGenCovariant<&'static ()>) -> ResursiveGenCovariant<&'new ()> {
v
}
Motivation: Based on indirect recursion between LeafNode
and InternalNode
in BTreeMap's internals, and assert_covariance()
in library/alloc/src/collections/btree/map/tests.rs
and library/alloc/src/collections/btree/set/tests.rs
. It means that adding generic_const_exprs
to library/alloc/src/lib.rs
breaks its compilation.
Related to #108725.