Skip to content

Possibly incorrect syntax Enum::<Type, Params>::Variant allowed since 1.33 #69356

Open
@estebank

Description

@estebank

A coworker recently identified the following case:

pub enum Foo<'a, T> {
    Struct {},
    Tuple(),
    Unit,
    Usage(&'a T),
}
pub fn main() {
    let foo = Foo::<String>::Unit;
    let foo = Foo::<String>::Tuple();
    let foo = Foo::<String>::Struct {};
}

This used to fail because of the lack of implicit bound T: 'a:

error[E0309]: the parameter type `T` may not live long enough
 --> <source>:5:11
  |
1 | pub enum Foo<'a, T> {
  |                  - help: consider adding an explicit lifetime bound `T: 'a`...
...
5 |     Usage(&'a T),
  |           ^^^^^
  |
note: ...so that the reference type `&'a T` does not outlive the data it points at
 --> <source>:5:11
  |
5 |     Usage(&'a T),
  |           ^^^^^

After fixing that, it complains about the type params:

error[E0109]: type parameters are not allowed on this type
 --> <source>:8:21
  |
8 |     let foo = Foo::<String>::Unit;
  |                     ^^^^^^ type parameter not allowed

error[E0109]: type parameters are not allowed on this type
 --> <source>:9:21
  |
9 |     let foo = Foo::<String>::Tuple();
  |                     ^^^^^^ type parameter not allowed

error[E0109]: type parameters are not allowed on this type
  --> <source>:10:21
   |
10 |     let foo = Foo::<String>::Struct {};
   |                     ^^^^^^ type parameter not allowed

Starting in 1.33, all but the Struct path are accepted:

error[E0110]: lifetime arguments are not allowed on this entity
  --> <source>:10:15
   |
10 |     let foo = Foo::<String>::Struct {};
   |               ^^^^^^^^^^^^^^^^^^^^^ lifetime argument not allowed

error[E0107]: wrong number of lifetime arguments: expected 1, found 0
  --> <source>:10:15
   |
10 |     let foo = Foo::<String>::Struct {};
   |               ^^^^^^^^^^^^^^^^^^^^^ expected 1 lifetime argument

The correct code for this would of course be:

pub enum Foo<'a, T> {
    Struct {},
    Tuple(),
    Unit,
    Usage(&'a T),
}
pub fn main() {
    let foo = Foo::Unit::<String>;
    let foo = Foo::Tuple::<String>();
    let foo = Foo::Struct::<String> {};
}

My questions:

  • Was this change in behavior (accepting some of these paths) intended?
  • If so, was it intended to deny only one of these cases?
  • If this change wasn't intended, should we try to reintroduce it or grandfather it in?

Depending on the answer to those questions, the solution to this ticket could be:

  • Make the compiler accept the let foo = Foo::Struct::<String> {}; case
  • Deny all cases with a suggestion pointing at the right syntax

cc @Centril

Metadata

Metadata

Assignees

Labels

A-type-systemArea: Type systemC-bugCategory: This is a bug.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions