diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift index d186a4b0a7d..a9e4a01f449 100644 --- a/Sources/SwiftParser/Declarations.swift +++ b/Sources/SwiftParser/Declarations.swift @@ -1215,8 +1215,11 @@ extension Parser { let unexpectedAfterIdentifier: RawUnexpectedNodesSyntax? let identifier: RawTokenSyntax if self.at(anyIn: Operator.self) != nil || self.at(.exclamationMark, .prefixAmpersand) { + // If the name is an operator token that ends in '<' followed by an identifier or 'let', + // leave the '<' so it's parsed as a generic parameter clause. This allows things like + // 'func ==(x:T, y:T) {}'. var name = self.currentToken.tokenText - if !currentToken.isEditorPlaceholder && name.hasSuffix("<") && self.peek(isAt: .identifier) { + if !currentToken.isEditorPlaceholder && name.hasSuffix("<") && self.peek(isAt: .identifier, .keyword(.let)) { name = SyntaxText(rebasing: name.dropLast()) } unexpectedBeforeIdentifier = nil diff --git a/Tests/SwiftParserTest/ValueGenericsTests.swift b/Tests/SwiftParserTest/ValueGenericsTests.swift index 7ff15a96dc9..7350ca0b749 100644 --- a/Tests/SwiftParserTest/ValueGenericsTests.swift +++ b/Tests/SwiftParserTest/ValueGenericsTests.swift @@ -287,4 +287,12 @@ final class ValueGenericsTests: ParserTestCase { fixedSource: "func foo() -> (<#type#>-1) X" ) } + + func testOperatorFunc() { + assertParse( + """ + func *(l: A, r: A) -> Int { l.int * r.int } + """ + ) + } }