Skip to content

feat(effect): native Effect diagnostics in tsc-rs - #4

Merged
t3dotgg merged 3 commits into
mainfrom
effect-native-diagnostics
Oct 7, 2026
Merged

t3dotgg merged 3 commits into
mainfrom
effect-native-diagnostics

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Projects that use Effect need a second compiler for its diagnostics. T3 Code runs tsc-rs --noEmit and then effect-tsgo diagnostics, a second full Go check of the same project. That makes a complete check 2x slower than Effect-patched TypeScript alone.

This PR adds the Effect language service diagnostics (@effect/language-service, TS377xxx) to tsc-rs itself. They come from the same program and checker pass as the ordinary TypeScript diagnostics.

How

  • crates/ts_goport/src/effect is a line-by-line port of Effect-TS/tsgo at the @effect/tsgo@0.46.1 release commit f1a7cad0: the type parser, all 116 rules, plugin config parsing (defaults, extends deep merge, per-file overrides), @effect-diagnostics directives, and the exit-code options.
  • It hooks in at the 7 places where the reference patches TypeScript. Each site names its patch:
    • after checkSourceFile, and relation-error capture
    • @ts-ignore does not hide Effect diagnostics
    • exit code and noEmitOnError filters
    • tsc mode
    • .tsbuildinfo holds the Effect options, so a config change invalidates cached diagnostics
  • Without an @effect/language-service plugin entry, nothing runs. The language server shows the same diagnostics, because the hook is in the checker.
  • Effect messages are in a separate catalog, generated from the vendored JSON. The TypeScript catalog is unchanged. --version is unchanged.
  • Not ported: editor-only features of the language service (quick fixes, refactors, hover, completions).

Verification

All against the reference Effect-patched tsc (TypeScript 7.0.2 + @effect/tsgo 0.46.1):

Check Result
The reference's own 529 test cases (Effect v3 and v4) 529/529 identical output
T3 Code at a7ce09c3, 14 workspaces 231/231 Effect diagnostics, 0 missing, 0 extra, 0 TS differences
Focused fixtures (crates/ts_goport/tests/effect_fixtures) 13/13, and each also passes on the reference
--incremental and --watch after source, imported type, config and directive edits 8/8 steps
--pretty output byte-identical

The scripts are in scripts/effect; docs/effect-diagnostics.md describes them.

Timing (T3 Code, Mac ARM64)

Medians of 5 sequential runs in rotated order. Both Rust builds use the goport profile. Seconds:

Workspace Rust alone Rust + Effect Go + Effect Rust + separate Effect pass
apps/server 3.33 5.46 11.64 21.68
apps/web (cold) 2.01 3.10 5.85 12.62
apps/mobile (no Effect config) 0.94 0.95 2.03 1.52
packages/client-runtime 0.61 0.90 1.78 3.78
packages/shared 0.28 0.38 0.79 1.51

A complete check is about 2x faster than Go + Effect and 4-5x faster than the current two-pass setup. Each rule walks the file, as in the reference, so a shared walk is a possible later speedup.

Notes

  • I have not run the protected regression pipeline (it needs the Linux hosts). Non-Effect projects take no new code path beyond a None check.
  • With --noEmit and errors, tsc-rs exits 2 where TS 7.0.2 exits 1. That is the pinned TypeScript Go behavior, not part of this change.

🤖 Generated with Claude Code. Opus 5.5 in Claude Code (T3 Code harness), with Opus 5.5 subagents for the rule and type parser port lanes.

Note

Add native Effect diagnostics to tsc-rs compiler

  • Ports the Effect lint and diagnostic rule set into the Rust compiler as a native module, with ~60 rules spanning style, correctness, and antipattern groups (codes 377000-377999). Rules run via effect.after_check_source_file after ordinary type checking.
  • Adds a type parser (typeparser) that detects Effect types, versions (v3/v4), layers, services, schemas, piping flows, and package exports, backed by checker-scoped caches.
  • Wires Effect configuration end to end: tsconfig plugin options parsing, merge across extended configs, per-file overrides, severity resolution, and validation of unknown rule names.
  • Adds @effect-diagnostics comment directives (line, next-line, file-level, *:skip-file) plus unused-directive reporting; TypeScript @ts-ignore no longer suppresses Effect codes.
  • Adds exit-code controls (ignoreEffectErrorsInTscExitCode etc.), persisted Effect options in incremental build info, and a large fixture suite plus benchmark/parity/LSP scripts under scripts/effect.
  • Risk: behavioral change — checker (check_source_file in checker_p03.rs) now clears prior Effect relation errors and runs the Effect pass on every check; get_diagnostics_with_preceding_directives in program.rs exempts 377xxx codes from ordinary ignore-directive suppression.

Macroscope summarized cd9c04b.

Port of Effect-TS/tsgo at @effect/tsgo@0.46.1 (f1a7cad0): the type parser,
all 116 diagnostic rules, @effect/language-service config parsing with the
extends deep merge and per-file overrides, @effect-diagnostics directives,
and the tsc exit-code options. Rules run after the checker checks a file
and add their diagnostics to it, so one program and one checker produce
ordinary and Effect diagnostics. Projects without the plugin run nothing.

Adds focused fixtures and differential scripts under scripts/effect, and
docs/effect-diagnostics.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@macroscopeapp

macroscopeapp Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $53.18, which exceeds your per-review limit of $15.00.

The top 3 files driving up this estimate:

File Diff Size Estimate
crates/ts_goport/src/effect/typeparser/piping_flow.rs 52.08KB $2.08
crates/ts_goport/src/effect/typeparser/effect_fn_opportunity.rs 41.56KB $1.66
crates/ts_goport/src/effect/typeparser/pipeable_signature_shape.rs 37.56KB $1.50

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

t3dotgg and others added 2 commits October 6, 2026 22:50
Rustdoc compiled the indented TypeScript examples in ported Go comments
as Rust doctests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- get_relation_errors checks an unchecked file even when the checker has
  no current context, as Go does with a nil context.
- The exit-code filter borrows the diagnostics when there are no Effect
  options, so projects without the plugin copy nothing.
- Docs: a plugin entry with only a name runs every rule at its default.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@t3dotgg

t3dotgg commented Oct 7, 2026

Copy link
Copy Markdown
Member Author

Note

🤖 Claude Opus 5.5 responding on behalf of Theo

Independent review of the hand-written integration layer (hooks, options, merge, directives, runner, build info) found no behavior differences from the Go reference. Projects without the plugin are unchanged. Three small items are fixed in cd9c04b:

  • get_relation_errors now checks an unchecked file even when the checker has no current context, as Go does with a nil context. No current rule hit this; they only pass their own, already checked file.
  • The exit-code filter borrows the diagnostics when there are no Effect options, so non-Effect projects no longer copy them.
  • docs/effect-diagnostics.md: a plugin entry with only a name runs every rule at its default severity.

Left as is, on purpose:

  • The tsc mode flag is process-global, as in Go. Only parallel in-process tests that check an Effect project with suggestions could see the wrong mode. No such test exists.
  • Go patch 021 (the +effect-tsgo.<version> suffix) is not ported, to keep --version at 7.1.0-dev for typesVersions. So a tsc-rs upgrade does not invalidate .tsbuildinfo for Effect rule changes. This is already true for any checker change in tsc-rs.

After the fixes: 529/529 reference cases, 13/13 fixtures and 8/8 incremental and watch steps still match the reference.

@t3dotgg
t3dotgg merged commit 380b9c0 into main Oct 7, 2026
4 checks passed
t3dotgg added a commit that referenced this pull request Oct 7, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Oct 7, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Oct 7, 2026
checker-port holds R177's crates (the same tree as goport-int48, merged
above); main is ahead of it by Theo's PRs #1, #3, #4, #5, so main's tree
is kept, as in the R176 checker-port merge.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Oct 7, 2026
goport-int50 975517e: on main 22745cf (R178 plus Theo PRs #1, #3, #4, #5, #6, #7, #9), merges of goport-effectfix1 4c618c1, goport-effectfix2 3508d5e, goport-loadcrit1 e5f234e, goport-followups31 7d2cef9 and goport-effectapi1 0899a4f, a lib blob commit, a root comment commit and the build info fix
t3dotgg added a commit that referenced this pull request Oct 8, 2026
…lugin

Since PR #4 the effect training config lists @effect/language-service, so
PGO trained only the Effect path there. Training it both ways (pgotrain2
study, PGO-only bins on alvin) is 0.5% faster with and without the plugin;
dropping the plugin from training instead makes plugin runs 2.3% slower.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Strate pushed a commit to chatium/ts-rust that referenced this pull request Oct 8, 2026
…gain

tsc-rs from Theo PR pingdotgg#4, before effectfix2, wrote build info with the
Effect options and diagnostics but the plain version. A standalone API
process (no Effect rules) took that version as its own and reused the
Effect diagnostics. effect-tsgo sees another version there and builds
again. is_valid_version now also asks for no Effect options when the
reader runs no rules, so the API and plain tsc-rs build again too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

1 participant