From b5c99374db0aff823f076a7129f29e727b0dec9b Mon Sep 17 00:00:00 2001 From: Kim de Vos Date: Sun, 15 Oct 2023 20:18:58 +0200 Subject: [PATCH] Handle generic parameter on enum case --- Sources/SwiftParser/Declarations.swift | 9 ++ .../ParseDiagnosticsGenerator.swift | 18 +++ .../ParserDiagnosticMessages.swift | 3 + Tests/SwiftParserTest/DeclarationTests.swift | 113 ++++++++++++++++++ 4 files changed, 143 insertions(+) diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift index 7075fcb0d7e..6cd0a74cb34 100644 --- a/Sources/SwiftParser/Declarations.swift +++ b/Sources/SwiftParser/Declarations.swift @@ -808,6 +808,14 @@ extension Parser { let unexpectedPeriod = self.consume(if: .period) let (unexpectedBeforeName, name) = self.expectIdentifier(keywordRecovery: true) + let unexpectedGenericParameters: RawUnexpectedNodesSyntax? + if self.at(prefix: "<") { + let genericParameters = self.parseGenericParameters() + unexpectedGenericParameters = RawUnexpectedNodesSyntax([genericParameters], arena: self.arena) + } else { + unexpectedGenericParameters = nil + } + let parameterClause: RawEnumCaseParameterClauseSyntax? if self.at(TokenSpec(.leftParen)) { parameterClause = self.parseParameterClause(RawEnumCaseParameterClauseSyntax.self) { parser in @@ -836,6 +844,7 @@ extension Parser { RawEnumCaseElementSyntax( RawUnexpectedNodesSyntax(combining: unexpectedPeriod, unexpectedBeforeName, arena: self.arena), name: name, + unexpectedGenericParameters, parameterClause: parameterClause, rawValue: rawValue, trailingComma: keepGoing, diff --git a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift index 067ae580b55..ed1d63a6e75 100644 --- a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift +++ b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift @@ -1074,6 +1074,24 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor { return .visitChildren } + public override func visit(_ node: EnumCaseElementSyntax) -> SyntaxVisitorContinueKind { + if shouldSkip(node) { + return .skipChildren + } + + if let unexpectedBetweenNameAndParameterClause = node.unexpectedBetweenNameAndParameterClause, + let genericParameter = unexpectedBetweenNameAndParameterClause.compactMap({ $0.as(GenericParameterClauseSyntax.self) }).only + { + addDiagnostic( + genericParameter, + .genericParamCantBeUsedInEnumCaseDecl, + handledNodes: [unexpectedBetweenNameAndParameterClause.id] + ) + } + + return .visitChildren + } + public override func visit(_ node: IfConfigClauseSyntax) -> SyntaxVisitorContinueKind { if shouldSkip(node) { return .skipChildren diff --git a/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift b/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift index 0f2f5916a04..75955a37219 100644 --- a/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift +++ b/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift @@ -167,6 +167,9 @@ extension DiagnosticMessage where Self == StaticParserError { public static var forbiddenInterpolatedString: Self { return .init("argument cannot be an interpolated string literal") } + public static var genericParamCantBeUsedInEnumCaseDecl: Self { + return .init("generic signature cannot be declared in enum 'case'") + } public static var initializerInPattern: Self { .init("unexpected initializer in pattern; did you mean to use '='?") } diff --git a/Tests/SwiftParserTest/DeclarationTests.swift b/Tests/SwiftParserTest/DeclarationTests.swift index de2bd77be3e..ee24ab0d121 100644 --- a/Tests/SwiftParserTest/DeclarationTests.swift +++ b/Tests/SwiftParserTest/DeclarationTests.swift @@ -2946,4 +2946,117 @@ final class DeclarationTests: ParserTestCase { ] ) } + + // https://github.com/apple/swift-syntax/issues/2273 + func testEnumCaseWithGenericParameter() { + assertParse( + """ + enum Foo { + case foo1️⃣(T) + } + """, + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "generic signature cannot be declared in enum 'case'" + ) + ] + ) + + assertParse( + """ + enum Foo { + case bar1️⃣(param: T) + } + """, + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "generic signature cannot be declared in enum 'case'" + ) + ] + ) + + assertParse( + """ + enum Foo { + case baz1️⃣ + } + """, + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "generic signature cannot be declared in enum 'case'" + ) + ] + ) + + assertParse( + """ + enum Foo { + case one, two1️⃣ + } + """, + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "generic signature cannot be declared in enum 'case'" + ) + ] + ) + + assertParse( + """ + enum Foo { + case three1️⃣, four + } + """, + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "generic signature cannot be declared in enum 'case'" + ) + ] + ) + + assertParse( + """ + enum Foo { + case five1️⃣(param: T), six + } + """, + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "generic signature cannot be declared in enum 'case'" + ) + ] + ) + + assertParse( + """ + enum Foo { + case seven1️⃣, eight2️⃣ + } + """, + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "generic signature cannot be declared in enum 'case'" + ), + DiagnosticSpec( + locationMarker: "2️⃣", + message: "generic signature cannot be declared in enum 'case'" + ), + ] + ) + + assertParse( + """ + enum Foo { + case five(param: T), six + } + """ + ) + } }