Repository: apple/swift-syntax (swift)

Issue:
Empty generic parameter clause produces no diagnostic
### Issue Kind

Bad Diagnostic Produced

### Source Code

```swift
// Can be parsed and produces no diagnostics.
func f< >() {}

// Can be parsed. Printing the node or asking for the diagnostics leads to a crash.
func f<>() {} 
```


### Description

In both examples, the "old" parser reports "Expected an identifier to name generic parameter" on `>` which is helpful, but not the real issue.

Best would be a message like "Generic parameter clause cannot be empty" or similar. It should be reported in both examples. The `ParseDiagnosticsGenerator` should not crash in the second example.

Pull request:
Fixes #1483 

Opened to see if I was on the right path

Patch:
diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift
index 181595f7e2d..298bbe8c75a 100644
--- a/Sources/SwiftParser/Declarations.swift
+++ b/Sources/SwiftParser/Declarations.swift
@@ -465,7 +465,7 @@ extension Parser {
     }
 
     precondition(self.currentToken.starts(with: "<"))
-    let langle = self.consumeAnyToken(remapping: .leftAngle)
+    let langle = self.consumePrefix("<", as: .leftAngle)
     var elements = [RawGenericParameterSyntax]()
     do {
       var keepGoing: RawTokenSyntax? = nil
@@ -477,7 +477,7 @@ extension Parser {
         var each = self.consume(if: .keyword(.each))
 
         let (unexpectedBetweenEachAndName, name) = self.expectIdentifier(allowSelfOrCapitalSelfAsIdentifier: true)
-        if attributes == nil && each == nil && unexpectedBetweenEachAndName == nil && name.isMissing && elements.isEmpty {
+        if attributes == nil && each == nil && unexpectedBetweenEachAndName == nil && name.isMissing && elements.isEmpty && !self.currentToken.starts(with: ">") {
           break
         }
 


Test patch:
diff --git a/Tests/SwiftParserTest/translated/RecoveryTests.swift b/Tests/SwiftParserTest/translated/RecoveryTests.swift
index 92be5a53967..728fe218155 100644
--- a/Tests/SwiftParserTest/translated/RecoveryTests.swift
+++ b/Tests/SwiftParserTest/translated/RecoveryTests.swift
@@ -1066,7 +1066,7 @@ final class RecoveryTests: XCTestCase {
     assertParse(
       """
       // Note: Don't move braces to a different line here.
-      struct ErrorGenericParameterList4< 1️⃣
+      struct ErrorGenericParameterList4<1️⃣
       {
       }
       """,
@@ -2280,4 +2280,34 @@ final class RecoveryTests: XCTestCase {
     )
   }
 
+  // https://github.com/apple/swift-syntax/issues/1483
+  func testRecovery183() {
+    // Can be parsed and produces no diagnostics.
+    assertParse(
+      "func f< 1️⃣>() {}",
+      diagnostics: [
+        DiagnosticSpec(
+          message: "expected generic parameter in generic parameter clause",
+          fixIts: ["insert generic parameter"]
+        )
+      ],
+      fixedSource: """
+        func f<<#identifier#> >() {}
+        """
+    )
+
+    // Can be parsed. Printing the node or asking for the diagnostics leads to a crash.
+    assertParse(
+      "func f<1️⃣>() {}",
+      diagnostics: [
+        DiagnosticSpec(
+          message: "expected generic parameter in generic parameter clause",
+          fixIts: ["insert generic parameter"]
+        )
+      ],
+      fixedSource: """
+        func f<<#identifier#>>() {}
+        """
+    )
+  }
 }