Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion Sources/SwiftParser/Expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2718,8 +2718,10 @@ extension Parser.Lookahead {
}

// Parse pattern-tuple func-signature-result? 'in'.
var isBracketed = false
if lookahead.at(.leftParen) { // Consume the '('.
// While we don't have '->' or ')', eat balanced tokens.
isBracketed = true
var skipProgress = LoopProgressCondition()
while !lookahead.at(.endOfFile, .rightBrace, .keyword(.in)) && !lookahead.at(.arrow)
&& lookahead.hasProgressed(&skipProgress)
Expand Down Expand Up @@ -2754,7 +2756,10 @@ extension Parser.Lookahead {
}

// Consume the ')', if it's there.
lookahead.consume(if: .rightParen)
var hasRightParen = false
if isBracketed {
hasRightParen = lookahead.consume(if: .rightParen) != nil
}

lookahead.consumeEffectsSpecifiers()

Expand All @@ -2775,9 +2780,14 @@ extension Parser.Lookahead {
return true
}

// If we started with '(', we MUST have found a ')' to trust the arrow.
if isBracketed && !hasRightParen {
return false
}
// Even if 'in' is missing, the presence of a top-level '->' makes this look like a
// closure signature. There's no other valid syntax that could legally
// contain '->' at this position.

return sawTopLevelArrowInLookahead
}
}
Expand Down
23 changes: 23 additions & 0 deletions Tests/SwiftParserTest/Issue3163.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import SwiftParser
import SwiftParserDiagnostics
import SwiftSyntax
import XCTest

public class Issue3163Tests: XCTestCase {
func testFixForIssue3163() {
let source = "struct Foo {func a(s: S [{{g) -> Int {}}}}"

// Parse the code
let tree = Parser.parse(source: source)

// Get the error messages
let diagnostics = ParseDiagnosticsGenerator.diagnostics(for: tree)

// CHECK: Ensure the specific "missing 'in'" error is NOT present
let hasBadError = diagnostics.contains { $0.message.contains("expected 'in' in closure signature") }

// This will pass if the error is gone (FIXED).
// This will fail if the error is still there (BROKEN).
XCTAssertFalse(hasBadError, "The parser incorrectly identified a closure signature and asked for 'in'")
}
}