Skip to content

invariant detection for recursive generic types incorrect with generic_const_exprs #108751

Open
@peter-lyons-kehl

Description

@peter-lyons-kehl

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-varianceArea: Variance (https://doc.rust-lang.org/nomicon/subtyping.html)C-bugCategory: This is a bug.F-generic_const_exprs`#![feature(generic_const_exprs)]`requires-incomplete-featuresThis issue requires the use of incomplete features.requires-nightlyThis issue requires a nightly compiler in some way.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions