Skip to content

fix: keep source-context echo out of diagnostics - #87

Merged
alexey1312 merged 1 commit into
masterfrom
fix/issue-78-source-context-echo
Aug 28, 2026
Merged

fix: keep source-context echo out of diagnostics#87
alexey1312 merged 1 commit into
masterfrom
fix/issue-78-source-context-echo

Conversation

@alexey1312

Copy link
Copy Markdown
Collaborator

Fixes #78.

Problem

The compiler prints the offending source line, indented, under every file:line:col: error:/warning:/note: header, then a caret line. The echoed source can carry : error: inside a string literal or a comment. parseError read those bytes as a compile error, so a successful build got the failed verdict.

The repro in the issue does not reproduce, on 1.4.2 or on the 1.3.1 code. The parser searches for ": error: ", and public init(_ error: Error) { holds _ error: — no colon before the word. The fast-path marker is wider ("error:"), so the line does reach the error path, but parseError rejects it. The reported failure needs the echoed line to hold the full ": error: " byte sequence.

Real swift build output that reproduces it:

/p/M.swift:8:19: warning: expression took 4ms to type-check (limit: 1ms)
        let msg = "upload: error: " + String(1) + String(2)
                  ^~~~~~~~~~~~~~~~~
Build complete! (4.24s)
"status": "failed",
"errors": [{ "file": "        let msg = \"upload",
             "message": "\" + String(1) + String(2)" }]

Log messages with a prefix such as "upload: error: " are common, so a large codebase hits this often. print("...: error: \(x)") escapes the bug only by accident: isJSONLikeLine needs both a backslash and a quote on the line.

Why not an indentation test

The issue proposes a guard that drops an indented line unless it holds ": error: ". That guard is a no-op for the failure above, because the echoed line does hold ": error: ". It also drops real errors:

Input before with the proposed guard
Command PhaseScriptExecution failed with a nonzero exit code failed success
/p/File.swift:3: Fatal error: found nil failed success
the echoed source line above failed failed

Both regressions report a broken build as a successful one, which #73 closed. Indentation cannot decide this question: indented tool output stands on its own.

Change

Track the echo block as parser state. sourceContextOpen opens on a diagnostic header that carries a location, and closes on the caret line or on the next line without indentation. Error and warning parsing is skipped only inside the block.

  • The header test reuses the parse result (error.line != nil / warning.line != nil), so the hot path never scans a line twice.
  • note: opens a block too. No other parser reads those lines, so the marker gets its own candidate bit and one byte-exact search. LineCandidates.rawValue widens to UInt16 for bit 8.
  • isCaretLine runs only while a block is open, and rejects on the last byte first.
  • Tool output such as swiftgen: error: … carries no location, so it never opens a block and never hides the next line.
Input before after
echoed source with : error: under a warning: header failed success
echoed source with : error: under a note: header failed success
echoed source with : warning: under an error: header 1 error, 1 warning 1 error, 0 warnings
swiftgen: error: template not found failed failed
sourcery: error: could not parse failed failed
Command PhaseScriptExecution failed with a nonzero exit code failed failed
/p/File.swift:3: Fatal error: found nil failed failed
/p/File.swift:10:5: error: cannot find x failed failed
tool error on the line after a caret line phantom error real error

An indented line inside the block is never a diagnostic. Only interleaved output from parallel targets could place a real error there, and xcodebuild buffers output per task. The earlier failure mode was worse: a phantom error and a wrong verdict.

The new gutter diagnostic style of Swift 5.8+ was never affected, because every context line holds |. The caret style is what xcodebuild emits — the 2.7 MB build.txt fixture holds 30 caret lines and no gutter lines.

Verification

  • swift test — 452 tests, 0 failures (444 before).
  • Tests/XCSiftCoreTests/SourceContextEchoTests.swift — 8 tests. Five fail on master and cover the bug. Three pass on master and guard the indented tool output, so they fail on the proposed indentation guard.
  • swift format lint --strict --recursive . — clean.
  • SwiftLint reports the same 59 findings before and after.
  • Benchmarks/large-log.sh 100, medians of three to five runs: fast-reject 0.26 s → 0.26 s, fixture-mixed 0.24 s → 0.24 s, warning-duplicate 1.11 s → 1.11 s, video-go-shaped 1.43 s → 1.41 s.
  • The real swift build log above now reports success with four warnings and no errors.

A `file:line:col: error:/warning:/note:` header is followed by the offending
source line, indented, and a caret line. The echoed source can carry
`: error: ` inside a string literal or a comment. The parser read those bytes
as a build error, so a successful build got the `failed` verdict.

Track the echo block as parser state. The block opens on a diagnostic header
that carries a location. It closes on the caret line, or on the next line
without indentation. Error and warning parsing is skipped only inside the
block.

Indentation alone must never suppress a diagnostic. Indented tool output such
as `swiftgen: error: template not found` and an indented
`Command PhaseScriptExecution failed with a nonzero exit code` stay
reportable.

Fixes #78.
@alexey1312
alexey1312 merged commit 903f1ed into master Aug 28, 2026
2 checks passed
@alexey1312
alexey1312 deleted the fix/issue-78-source-context-echo branch August 28, 2026 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Indented source-context echo containing 'error:'/'warning:' is misparsed as a diagnostic

1 participant