jtbandes
(Jacob Bandes-Storch)
July 1, 2019, 1:04am
1
Someone pointed out that the TextMate language grammar (used by GitHub for Swift syntax highlighting) rejects enum Foo { case foo(_ bar: Int) }
:
opened 06:35PM - 27 Jun 19 UTC
closed 04:40PM - 13 Jul 19 UTC
GitHub’s syntax highlighting uses [github/liguist](https://github.com/github/lin… guist), which in turn uses swift.tmbundle. This combination of software incorrectly considers enum cases that use `_ x` as an associated value label (where `x` can be any valid identifier) as invalid Swift code (highlighted with a red background).
`_ x` is valid as an enum associated value in Swift, but `x y` is not valid, which might be the source of the issue.
## Steps to reproduce
Option A:
1. Create a `.swift` file in a GitHub repo
2. Add an enum with a case with an associated value to the file
3. Label that associated value `_ foo`, where `foo` can be any valid identifier (see example below)
Option B:
1. Create an issue like this one (or other Markdown document) on GitHub
2. Embed an enum with a case with an associated value in the document surrounded by ```` ```swift ```` and ```` ``` ````
3. Label that associated value `_ foo`, where `foo` can be any valid identifier (see example below)
```swift
enum Foo {
case one(_ x: Int) // no error, but marked as invalid
case two(_: Int)
case three(x y: Int) // error: enum case cannot have keyword arguments
case four(x: Int)
case five(__ x: Int) // error: enum case cannot have keyword arguments
}
```
Note the following:
- `case one(_ x: Int)` **is valid, but is incorrectly marked invalid**
- `case two(_: Int)` is valid, and marked valid
- `case three(x y: Int)` is invalid, and marked invalid
- `case four(x: Int)` is valid, and marked valid
- `case five(__ x: Int)` (two `_`s) is invalid, and marked invalid
## Expected results
`case one(_ x: Int)` should be considered valid Swift code.
## Actual results
`case one(_ x: Int)` is marked as invalid Swift code (highlighted with a red background).
## Environment
GitHub, using (presumably) the latest version of Linguist, using (presumably) a recent version of swift.tmbundle.
But as far as I can tell, the language grammar/"spec" doesn't allow this:
...
union-style-enum-case → enum-case-name tuple-type opt
tuple-type → (
)
| (
tuple-type-element ,
tuple-type-element-list )
tuple-type-element-list → tuple-type-element | tuple-type-element ,
tuple-type-element-list
tuple-type-element → element-name type-annotation | type
element-name → identifier
Is it intentional that the compiler does allow it?
Also, what's going on here — is this just a problem that will be fixed by SE-0155 ?
let x: Foo = .foo(bar: 4) // valid
let y: Foo = .foo(4) // invalid
let z = Foo.foo
z(bar: 4) // invalid
z(4) // valid
I think this is an artifact of the parser using common logic to parse enum cases and function parameter lists. At this point I don't think we can ban it without breaking source compatibility.
There is also at least one other place where you can do this -- function types:
func f(_: (_ x: Int, _ y: Int) -> ()) {}
jtbandes
(Jacob Bandes-Storch)
July 1, 2019, 3:16am
3
Seems like it would be quite rare, because only _
is allowed in that position (if you use any other label, you get an error). Anyway, if it's not going to be removed, at least the grammar should probably be updated to include it
Couldn't we start deprecating it as a long-term plan?
krilnon
(Kyle Murray)
July 1, 2019, 6:30pm
5
Certainly worth considering! Usually we try not to document unintended implementation quirks in the grammar, but if we're going to keep it forever…