Skip to content

perf: replace source importer with gcexportdata for ~1000x faster type resolution#58

Merged
erudenko merged 3 commits into
mainfrom
worktree-perf-gcexportdata-importer
Mar 28, 2026
Merged

perf: replace source importer with gcexportdata for ~1000x faster type resolution#58
erudenko merged 3 commits into
mainfrom
worktree-perf-gcexportdata-importer

Conversation

@erudenko

Copy link
Copy Markdown
Member

Summary

  • Replace the slow importer.ForCompiler("source") in TypeResolver with a fast gcexportdata-based importer backed by go list -export -deps
  • Add process-level goListCache to eliminate duplicate go list invocations between pipeline phases (Phase 0 validation + Step 2.1 error propagation)
  • Fall back gracefully to source importer if go list -export fails

Benchmarks

Path Before After
TypeResolver (first call) 1.4s+ (source import) ~42ms (go list + gcexportdata)
TypeResolver (second call, same process) 1.4s+ (no reuse) 750ns (cache hit)
Large repo (Cosmos SDK, 500+ packages) ~15 minutes ~seconds (after first go build)

Test plan

  • 11 new tests in gc_export_importer_test.go (stdlib import, caching, transitive deps, missing package, cache ordering, TypeResolver integration)
  • Full go test ./... passes with zero regressions
  • End-to-end test: dingo go transpiles correctly with DINGO_PROFILE=1 showing fast path
  • 6-model team review (Gemini, GPT-5.4, GLM-5, MiniMax, Qwen, Claude) — review feedback addressed

Addresses #38

🤖 Generated with Claude Code

erudenko and others added 3 commits March 28, 2026 22:52
…aster type resolution

The type resolver previously used importer.ForCompiler("source") which
recursively parses all transitive dependencies from .go source files.
For large dependency graphs (e.g., Cosmos SDK), this took 15+ minutes.

Now uses gcexportdata to read pre-compiled type data from Go's build
cache via `go list -export -deps`. Benchmarks show:
- go list -export -deps: ~42ms (finds all dependency export files)
- gcexportdata.Read() for all deps: ~23ms
- Cached (second call, same process): 750ns

The gcExportImporter also caches `go list` results across multiple
NewTypeResolver calls, eliminating the duplicate invocation between
Phase 0 (semantic validation) and Step 2.1 (error propagation).

Falls back to source importer if `go list -export` fails.

Addresses #38

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Review feedback from 6-model team review:
- Remove GOFLAGS= override that broke vendor mode projects
- Capture go list stderr for better error diagnostics
- File descriptor leak was a false positive (os.Open error IS checked
  before defer f.Close() is registered)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📊 Performance Benchmark Report

Performance Benchmark Report

Analyzed 190 benchmark(s)

Benchmark ns/op allocs/op bytes/op
BenchmarkTupleCodeGen_SimpleLiteral 169.30 2 80
BenchmarkTupleCodeGen_SimpleLiteral 167.50 2 80
BenchmarkTupleCodeGen_SimpleLiteral 166.60 2 80
BenchmarkTupleCodeGen_SimpleLiteral 167.70 2 80
BenchmarkTupleCodeGen_SimpleLiteral 167.70 2 80
BenchmarkTupleCodeGen_ComplexDestructure 823.90 14 304
BenchmarkTupleCodeGen_ComplexDestructure 825.20 14 304
BenchmarkTupleCodeGen_ComplexDestructure 820.70 14 304
BenchmarkTupleCodeGen_ComplexDestructure 824.10 14 304
BenchmarkTupleCodeGen_ComplexDestructure 826.50 14 304
BenchmarkMapToDingo 90.41 1 64
BenchmarkMapToDingo 92.59 1 64
BenchmarkMapToDingo 92.28 1 64
BenchmarkMapToDingo 91.49 1 64
BenchmarkMapToDingo 91.82 1 64
BenchmarkParseSingleExpression/simple_ident 3367.00 51 5123
BenchmarkParseSingleExpression/simple_ident 3422.00 51 5123
BenchmarkParseSingleExpression/simple_ident 3361.00 51 5123
BenchmarkParseSingleExpression/simple_ident 3387.00 51 5123
BenchmarkParseSingleExpression/simple_ident 3383.00 51 5123
BenchmarkParseSingleExpression/binary_add 6044.00 65 8320
BenchmarkParseSingleExpression/binary_add 5923.00 65 8320
BenchmarkParseSingleExpression/binary_add 5937.00 65 8320
BenchmarkParseSingleExpression/binary_add 5924.00 65 8320
BenchmarkParseSingleExpression/binary_add 5910.00 65 8320
BenchmarkParseSingleExpression/binary_chain 13552.00 109 18744
BenchmarkParseSingleExpression/binary_chain 13537.00 109 18744
BenchmarkParseSingleExpression/binary_chain 13501.00 109 18744
BenchmarkParseSingleExpression/binary_chain 13502.00 109 18744
BenchmarkParseSingleExpression/binary_chain 13632.00 109 18744
BenchmarkParseSingleExpression/error_prop 7064.00 79 9160
BenchmarkParseSingleExpression/error_prop 7068.00 79 9160
BenchmarkParseSingleExpression/error_prop 7044.00 79 9160
BenchmarkParseSingleExpression/error_prop 7054.00 79 9160
BenchmarkParseSingleExpression/error_prop 7056.00 79 9160
BenchmarkParseSingleExpression/error_context 7313.00 82 9192
BenchmarkParseSingleExpression/error_context 7335.00 82 9192
BenchmarkParseSingleExpression/error_context 7361.00 82 9192
BenchmarkParseSingleExpression/error_context 7329.00 82 9192
BenchmarkParseSingleExpression/error_context 7315.00 82 9192
BenchmarkParseSingleExpression/error_lambda_rust 15572.00 127 20232
BenchmarkParseSingleExpression/error_lambda_rust 15383.00 127 20232
BenchmarkParseSingleExpression/error_lambda_rust 15449.00 127 20232
BenchmarkParseSingleExpression/error_lambda_rust 15311.00 127 20232
BenchmarkParseSingleExpression/error_lambda_rust 15287.00 127 20232
BenchmarkParseSingleExpression/error_lambda_ts 16011.00 131 20688
BenchmarkParseSingleExpression/error_lambda_ts 16096.00 131 20688
BenchmarkParseSingleExpression/error_lambda_ts 16066.00 131 20688
BenchmarkParseSingleExpression/error_lambda_ts 16069.00 131 20688
BenchmarkParseSingleExpression/error_lambda_ts 16031.00 131 20688
BenchmarkParseSingleExpression/error_lambda_ts_single 13742.00 114 18496
BenchmarkParseSingleExpression/error_lambda_ts_single 13655.00 114 18496
BenchmarkParseSingleExpression/error_lambda_ts_single 13869.00 114 18496
BenchmarkParseSingleExpression/error_lambda_ts_single 13700.00 114 18496
BenchmarkParseSingleExpression/error_lambda_ts_single 13671.00 114 18496
BenchmarkParseSingleExpression/ternary 8556.00 80 11816
BenchmarkParseSingleExpression/ternary 8550.00 80 11816
BenchmarkParseSingleExpression/ternary 8512.00 80 11816
BenchmarkParseSingleExpression/ternary 8566.00 80 11816
BenchmarkParseSingleExpression/ternary 8561.00 80 11816
BenchmarkParseSingleExpression/nested_ternary 13254.00 103 18816
BenchmarkParseSingleExpression/nested_ternary 13164.00 103 18816
BenchmarkParseSingleExpression/nested_ternary 13518.00 103 18816
BenchmarkParseSingleExpression/nested_ternary 13209.00 103 18816
BenchmarkParseSingleExpression/nested_ternary 13169.00 103 18816
BenchmarkParseSingleExpression/safe_nav 7167.00 73 10504
BenchmarkParseSingleExpression/safe_nav 7176.00 73 10504
BenchmarkParseSingleExpression/safe_nav 7203.00 73 10504
BenchmarkParseSingleExpression/safe_nav 7305.00 73 10504
BenchmarkParseSingleExpression/safe_nav 7186.00 73 10504
BenchmarkParseSingleExpression/null_coal 5641.00 61 7713
BenchmarkParseSingleExpression/null_coal 5651.00 61 7713
BenchmarkParseSingleExpression/null_coal 5632.00 61 7713
BenchmarkParseSingleExpression/null_coal 5610.00 61 7713
BenchmarkParseSingleExpression/null_coal 5632.00 61 7713
BenchmarkParseSingleExpression/match_simple 20141.00 150 26880
BenchmarkParseSingleExpression/match_simple 20147.00 150 26880
BenchmarkParseSingleExpression/match_simple 20118.00 150 26880
BenchmarkParseSingleExpression/match_simple 20115.00 150 26880
BenchmarkParseSingleExpression/match_simple 20067.00 150 26880
BenchmarkParseSingleExpression/lambda_rust 11853.00 100 16920
BenchmarkParseSingleExpression/lambda_rust 11868.00 100 16920
BenchmarkParseSingleExpression/lambda_rust 11957.00 100 16920
BenchmarkParseSingleExpression/lambda_rust 11908.00 100 16920
BenchmarkParseSingleExpression/lambda_rust 11896.00 100 16920
BenchmarkParseSingleExpression/lambda_ts 12447.00 104 17376
BenchmarkParseSingleExpression/lambda_ts 12430.00 104 17376
BenchmarkParseSingleExpression/lambda_ts 12480.00 104 17376
BenchmarkParseSingleExpression/lambda_ts 12514.00 104 17376
BenchmarkParseSingleExpression/lambda_ts 12467.00 104 17376
BenchmarkParseSingleExpression/complex_chain 12325.00 108 15939
BenchmarkParseSingleExpression/complex_chain 12622.00 108 15939
BenchmarkParseSingleExpression/complex_chain 12401.00 108 15939
BenchmarkParseSingleExpression/complex_chain 12374.00 108 15939
BenchmarkParseSingleExpression/complex_chain 12341.00 108 15939
BenchmarkLookahead/isTypeScriptLambda_positive 11883.00 97 17064
BenchmarkLookahead/isTypeScriptLambda_positive 11883.00 97 17064
BenchmarkLookahead/isTypeScriptLambda_positive 11898.00 97 17064
BenchmarkLookahead/isTypeScriptLambda_positive 11887.00 97 17064
BenchmarkLookahead/isTypeScriptLambda_positive 11873.00 97 17064
BenchmarkLookahead/isTypeScriptLambda_negative 7876.00 77 10836
BenchmarkLookahead/isTypeScriptLambda_negative 7881.00 77 10836
BenchmarkLookahead/isTypeScriptLambda_negative 7912.00 77 10836
BenchmarkLookahead/isTypeScriptLambda_negative 7926.00 77 10836
BenchmarkLookahead/isTypeScriptLambda_negative 7932.00 77 10836
BenchmarkLookahead/classifyQuestion_ternary 5864.00 63 8248
BenchmarkLookahead/classifyQuestion_ternary 5910.00 63 8248
BenchmarkLookahead/classifyQuestion_ternary 5883.00 63 8248
BenchmarkLookahead/classifyQuestion_ternary 5913.00 63 8248
BenchmarkLookahead/classifyQuestion_ternary 5869.00 63 8248
BenchmarkLookahead/classifyQuestion_postfix 3170.00 53 4340
BenchmarkLookahead/classifyQuestion_postfix 3186.00 53 4340
BenchmarkLookahead/classifyQuestion_postfix 3169.00 53 4340
BenchmarkLookahead/classifyQuestion_postfix 3174.00 53 4340
BenchmarkLookahead/classifyQuestion_postfix 3201.00 53 4340
BenchmarkLookahead/classifyQuestion_context 2358.00 47 3280
BenchmarkLookahead/classifyQuestion_context 2358.00 47 3280
BenchmarkLookahead/classifyQuestion_context 2348.00 47 3280
BenchmarkLookahead/classifyQuestion_context 2361.00 47 3280
BenchmarkLookahead/classifyQuestion_context 2362.00 47 3280
BenchmarkLookahead/hasTernaryColon_found 5809.00 63 8248
BenchmarkLookahead/hasTernaryColon_found 5835.00 63 8248
BenchmarkLookahead/hasTernaryColon_found 5818.00 63 8248
BenchmarkLookahead/hasTernaryColon_found 5814.00 63 8248
BenchmarkLookahead/hasTernaryColon_found 5789.00 63 8248
BenchmarkLookahead/hasTernaryColon_nested 12569.00 102 17696
BenchmarkLookahead/hasTernaryColon_nested 12576.00 102 17696
BenchmarkLookahead/hasTernaryColon_nested 12547.00 102 17696
BenchmarkLookahead/hasTernaryColon_nested 12547.00 102 17696
BenchmarkLookahead/hasTernaryColon_nested 12548.00 102 17696
BenchmarkMatchExpression 52999.00 354 71145
BenchmarkMatchExpression 53383.00 354 71144
BenchmarkMatchExpression 53109.00 354 71144
BenchmarkMatchExpression 53407.00 354 71144
BenchmarkMatchExpression 53331.00 354 71144
BenchmarkLargeFile 910859.00 0 0
BenchmarkLargeFile 913536.00 0 0
BenchmarkLargeFile 908530.00 0 0
BenchmarkLargeFile 916270.00 0 0
BenchmarkLargeFile 911509.00 0 0
BenchmarkParserCreation 3340.00 50 5099
BenchmarkParserCreation 3318.00 50 5099
BenchmarkParserCreation 3341.00 50 5099
BenchmarkParserCreation 3330.00 50 5099
BenchmarkParserCreation 3326.00 50 5099
BenchmarkStateOperations 38.01 0 0
BenchmarkStateOperations 37.99 0 0
BenchmarkStateOperations 38.07 0 0
BenchmarkStateOperations 38.02 0 0
BenchmarkStateOperations 37.91 0 0
BenchmarkComplexExpression 29942.00 206 41266
BenchmarkComplexExpression 29939.00 206 41266
BenchmarkComplexExpression 29929.00 206 41266
BenchmarkComplexExpression 29902.00 206 41266
BenchmarkComplexExpression 30453.00 206 41266
BenchmarkIsAddressable_Identifier 2.18 0 0
BenchmarkIsAddressable_Identifier 2.18 0 0
BenchmarkIsAddressable_Identifier 2.19 0 0
BenchmarkIsAddressable_Identifier 2.18 0 0
BenchmarkIsAddressable_Identifier 2.18 0 0
BenchmarkIsAddressable_Literal 2.49 0 0
BenchmarkIsAddressable_Literal 2.50 0 0
BenchmarkIsAddressable_Literal 2.49 0 0
BenchmarkIsAddressable_Literal 2.49 0 0
BenchmarkIsAddressable_Literal 2.50 0 0
BenchmarkWrapInIIFE 503.20 19 656
BenchmarkWrapInIIFE 506.80 19 656
BenchmarkWrapInIIFE 503.30 19 656
BenchmarkWrapInIIFE 503.90 19 656
BenchmarkWrapInIIFE 502.80 19 656
BenchmarkMaybeWrapForAddressability_NoWrap 28.80 1 32
BenchmarkMaybeWrapForAddressability_NoWrap 28.91 1 32
BenchmarkMaybeWrapForAddressability_NoWrap 28.85 1 32
BenchmarkMaybeWrapForAddressability_NoWrap 29.44 1 32
BenchmarkMaybeWrapForAddressability_NoWrap 28.89 1 32
BenchmarkMaybeWrapForAddressability_Wrap 506.70 19 656
BenchmarkMaybeWrapForAddressability_Wrap 506.10 19 656
BenchmarkMaybeWrapForAddressability_Wrap 506.50 19 656
BenchmarkMaybeWrapForAddressability_Wrap 506.90 19 656
BenchmarkMaybeWrapForAddressability_Wrap 509.10 19 656
BenchmarkExtractImports 3427.00 55 2528
BenchmarkExtractImports 3299.00 55 2528
BenchmarkExtractImports 3300.00 55 2528
BenchmarkExtractImports 3343.00 55 2528
BenchmarkExtractImports 3296.00 55 2528
BenchmarkExtractImportsRegex 16951.00 120 12916
BenchmarkExtractImportsRegex 16984.00 120 12919
BenchmarkExtractImportsRegex 16929.00 120 12918
BenchmarkExtractImportsRegex 16852.00 120 12912
BenchmarkExtractImportsRegex 16882.00 120 12918

@erudenko
erudenko merged commit 9b0fc8a into main Mar 28, 2026
9 of 12 checks passed
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