Skip to content

the type of ProjectionElem::Field is not correct wrt subtyping #96514

@lcnr

Description

@lcnr
Contributor
struct Foo<T>(T); // `T` is covariant.

fn foo<'b>(x: Foo<for<'a> fn(&'a ())>) {
    let Foo(y): Foo<fn(&'b ())> = x;
}

fn main() {}

should compile but errors with

error[E0308]: mismatched types
 --> src/main.rs:4:13
  |
4 |     let Foo(y): Foo<fn(&'b ())> = x;
  |             ^ one type is more general than the other
  |
  = note: expected fn pointer `for<'a> fn(&'a ())`
             found fn pointer `fn(&())`

looking at the mir of foo it becomes clear why that happens:

fn foo(_1: Foo<for<'a> fn(&'a ())>) -> () {
    debug x => _1;                       // in scope 0 at src/main.rs:3:12: 3:13
    let mut _0: ();                      // return place in scope 0 at src/main.rs:3:40: 3:40
    let _2: fn(&()) as UserTypeProjection { base: UserType(0), projs: [Field(field[0], ())] }; // in scope 0 at src/main.rs:4:13: 4:14
    scope 1 {
        debug y => _2;                   // in scope 1 at src/main.rs:4:13: 4:14
    }

    bb0: {
        AscribeUserType(_1, +, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at src/main.rs:4:17: 4:32
        StorageLive(_2);                 // scope 0 at src/main.rs:4:13: 4:14
        _2 = (_1.0: fn(&()));            // scope 0 at src/main.rs:4:13: 4:14
        _0 = const ();                   // scope 0 at src/main.rs:3:40: 5:2
        StorageDead(_2);                 // scope 0 at src/main.rs:5:1: 5:2
        return;                          // scope 0 at src/main.rs:5:2: 5:2
    }
}

notice that in _2 = (_1.0: fn(&())); the type of _1.0 is actually for<'a> fn(&'a ()).

Possible ways to fix this are:

  • correctly deal with subtyping when sanitizing field projections, note that they cannot just always be covariant.
  • change the type of the field to be the actual one during mir building, so that subtyping actually happens at the assignment
  • always lazily recompute the type of the field instead of storing it in the mir

Activity

lcnr

lcnr commented on Apr 28, 2022

@lcnr
ContributorAuthor

@rustbot claim

intend to work on this myself

deleted a comment from rustbot on Apr 28, 2022
lcnr

lcnr commented on Apr 29, 2022

@lcnr
ContributorAuthor

also add a test for

struct Foo<T>(T); // `T` is covariant.

fn foo<'b>(x: Foo<Foo<for<'a> fn(&'a ())>>) {
    let Foo(Foo(y)): Foo<Foo<fn(&'b ())>> = x;
}
removed their assignment
on Oct 21, 2022
added
E-hardCall for participation: Hard difficulty. Experience needed to fix: A lot.
E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.
A-varianceArea: Variance (https://doc.rust-lang.org/nomicon/subtyping.html)
T-typesRelevant to the types team, which will review and decide on the PR/issue.
on Oct 21, 2022
lcnr

lcnr commented on Oct 21, 2022

@lcnr
ContributorAuthor

change the type of the field to be the actual one during mir building, so that subtyping actually happens at the assignment

That's imo the correct solution. Open to mentor someone here, ideally with some experience with working with ty::Ty and mir building.

If you're interested and need help, contact me on zulip and we can either chat about it there or on zoom.

b-naber

b-naber commented on Oct 21, 2022

@b-naber
Contributor

@rustbot claim

24 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-varianceArea: Variance (https://doc.rust-lang.org/nomicon/subtyping.html)C-bugCategory: This is a bug.E-hardCall for participation: Hard difficulty. Experience needed to fix: A lot.E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.T-typesRelevant to the types team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Participants

    @trevyn@lqd@RalfJung@lcnr@b-naber

    Issue actions

      the type of `ProjectionElem::Field` is not correct wrt subtyping · Issue #96514 · rust-lang/rust