rigortype 0.3.7 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/docs/handbook/11-sig-gen.md +24 -14
- data/docs/manual/02-cli-reference.md +7 -0
- data/docs/manual/04-diagnostics.md +1 -1
- data/lib/rigor/analysis/crash_signature.rb +78 -6
- data/lib/rigor/analysis/incremental_session.rb +19 -7
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +142 -17
- data/lib/rigor/analysis/runner/pool_coordinator.rb +232 -47
- data/lib/rigor/analysis/runner/run_snapshots.rb +7 -2
- data/lib/rigor/analysis/runner.rb +66 -7
- data/lib/rigor/analysis/worker_session.rb +28 -3
- data/lib/rigor/builtins/imported_refinements.rb +11 -9
- data/lib/rigor/cache/annotation_location.rb +72 -0
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +39 -0
- data/lib/rigor/cache/store.rb +8 -1
- data/lib/rigor/cli/sig_gen_command.rb +29 -0
- data/lib/rigor/environment/failure_slot.rb +28 -0
- data/lib/rigor/environment/rbs_loader.rb +228 -57
- data/lib/rigor/environment.rb +87 -10
- data/lib/rigor/inference/hkt_registry.rb +16 -4
- data/lib/rigor/inference/hkt_sugar_translator.rb +15 -21
- data/lib/rigor/plugin/registry.rb +25 -2
- data/lib/rigor/rbs_extended/envelope_scanner.rb +8 -7
- data/lib/rigor/rbs_extended/hkt_directives.rb +16 -1
- data/lib/rigor/rbs_extended/reporter.rb +93 -13
- data/lib/rigor/rbs_extended.rb +6 -1
- data/lib/rigor/sig_gen/generator.rb +66 -80
- data/lib/rigor/sig_gen/renderer.rb +13 -6
- data/lib/rigor/version.rb +1 -1
- data/sig/rigor/environment.rbs +6 -0
- metadata +3 -1
|
@@ -115,11 +115,62 @@ module Rigor
|
|
|
115
115
|
# sources. The env stays a LOCAL variable (not an ivar) so it goes GC-eligible when the method
|
|
116
116
|
# returns — holding it as long-lived state added memory pressure that surfaced as a Bus Error
|
|
117
117
|
# during the spec suite under Ruby 4.0 + rbs 4.0.2.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
# @param project_files [Array<String>, nil] issue #784 — the WHOLE project's analyzed file set
|
|
119
|
+
# (`expansion.fetch(:files)`), independent of any `analyze_only` narrowing of `files`. Read only
|
|
120
|
+
# when `files` is empty, to decide whether anyone could have demanded the HKT registry at all.
|
|
121
|
+
def analyze_files(files, environment: nil, project_files: nil)
|
|
122
|
+
if files.empty?
|
|
123
|
+
# Issue #784 — an EMPTY analyze set still owes the run its HKT-scan row: the per-file cache never
|
|
124
|
+
# holds it (`IncrementalSession` caches only `Runner#per_file_diagnostics`, so every run-level row
|
|
125
|
+
# is regenerated every run), so returning here without recording flips a red project green — and
|
|
126
|
+
# the shipping `--incremental` path reaches this branch with NO environment in hand on every
|
|
127
|
+
# warm recheck that changed nothing (`CheckCommand#run_incremental_check` builds its session
|
|
128
|
+
# without one). So: an environment already in hand is consulted; otherwise one is resolved over
|
|
129
|
+
# the project's OWN file list — not `[]`, which would drop every plugin-synthesized virtual RBS
|
|
130
|
+
# (`Environment.collect_virtual_rbs` short-circuits on an empty list) and scan a different type
|
|
131
|
+
# universe from the one a full run analyses — and only when the project HAS files: with none,
|
|
132
|
+
# nobody could have demanded a registry, and an empty project keeps paying no env build. Keyed
|
|
133
|
+
# on the project's files rather than on `analyze_only`, because a recheck over an EMPTY project
|
|
134
|
+
# narrows to `Set[]`, which is non-nil.
|
|
135
|
+
env = environment || @environment_override
|
|
136
|
+
if project_files && !project_files.empty?
|
|
137
|
+
env ||= resolve_sequential_environment(source_files: project_files)
|
|
138
|
+
end
|
|
139
|
+
# #788 rounds 6 and 9 — everything the run owes from its environment that no per-file analysis
|
|
140
|
+
# produces is taken here, the way `analyze_files_sequentially` takes it: the project-signature
|
|
141
|
+
# state (`synthesized-namespace`, `quarantined-signature`, `environment-build-failed`, the
|
|
142
|
+
# conformance results), the effect-annotation carrier the residual pass reads, and the HKT-scan
|
|
143
|
+
# outcome. Now that run-level rows are never served from the per-file cache, this branch is the
|
|
144
|
+
# only producer on a warm recheck that changed nothing — leaving any of them out turned a red
|
|
145
|
+
# project green on its second `--incremental` run (the inline-only `effect.annotations-unchecked`
|
|
146
|
+
# went 1 → 0; a quarantined `signature_paths:` file went 1 → 0; a `conforms-to` class whose
|
|
147
|
+
# definition build fails went 1 → 0). Same ORDER as the sequential path, because the order is
|
|
148
|
+
# the contract: the conformance scan inside the signature-state snapshot demands the definition
|
|
149
|
+
# of every `rigor:v1:conforms-to` class — a user-authored, invocation-independent demand that
|
|
150
|
+
# #696 counts — so the definition-build failures are read AFTER it and BEFORE the HKT demand,
|
|
151
|
+
# exactly where `analyze_files_sequentially` reads them relative to its own. What this branch
|
|
152
|
+
# cannot regenerate is the part of that set the per-file ANALYSIS demanded (#796). This also
|
|
153
|
+
# retires the #441 "`.rbs` lane only when the run analyses nothing" boundary: its cost premise
|
|
154
|
+
# (no environment on this path) stopped holding the moment the branch above resolved one.
|
|
155
|
+
snapshot_project_signature_state(env)
|
|
156
|
+
snapshot_effect_annotation_carrier(env&.rbs_loader)
|
|
157
|
+
record_definition_build_failures(env&.rbs_loader&.definition_build_failures)
|
|
158
|
+
record_hkt_scan_failure(hkt_scan_outcome(env))
|
|
159
|
+
return []
|
|
160
|
+
end
|
|
161
|
+
# Issue #784 / #793 — `files` is what this run ANALYSES; `source_files` is what its environment
|
|
162
|
+
# is BUILT over, and the two are the same only on a full run. A narrowed run (`analyze_only`: an
|
|
163
|
+
# incremental closure, a `--verify-incremental` partition) used to build its environment over the
|
|
164
|
+
# subset, so plugin-synthesized virtual RBS from every excluded file was missing and the run
|
|
165
|
+
# scanned a different type universe than the full run it is compared against — a scan failure
|
|
166
|
+
# whose trigger lived in an excluded file's synthesized RBS fired on the full run and vanished on
|
|
167
|
+
# the subset. Every environment and worker this run builds now takes the whole project.
|
|
168
|
+
source_files = project_files || files
|
|
169
|
+
return dispatch_pool(files, source_files: source_files) if pool_mode?
|
|
170
|
+
|
|
171
|
+
analyze_files_sequentially(
|
|
172
|
+
files, environment || resolve_sequential_environment(source_files: source_files)
|
|
173
|
+
)
|
|
123
174
|
end
|
|
124
175
|
|
|
125
176
|
def analyze_files_sequentially(files, environment)
|
|
@@ -130,6 +181,13 @@ module Rigor
|
|
|
130
181
|
# first demand), so a snapshot taken beside the ones above — which run BEFORE `files.flat_map` —
|
|
131
182
|
# would read an empty list on every run, including the ones this diagnostic exists for.
|
|
132
183
|
record_definition_build_failures(environment&.rbs_loader&.definition_build_failures)
|
|
184
|
+
# Issue #784 — same timing contract, same reason: the HKT scan is first demanded from inside a
|
|
185
|
+
# file's analysis (the dispatcher's Singleton-receiver tier), so a snapshot taken any earlier
|
|
186
|
+
# would read nil on every run. And demanded HERE once more by the run itself, because a subset
|
|
187
|
+
# run (`--verify-incremental`'s partition, an incremental recheck's closure) may contain no file
|
|
188
|
+
# that demands it — the row must not depend on which files were analysed. See {#hkt_scan_outcome}
|
|
189
|
+
# for why a Rigor-owned demand is sound here where #696 forbids it.
|
|
190
|
+
record_hkt_scan_failure(hkt_scan_outcome(environment))
|
|
133
191
|
if @collect_stats
|
|
134
192
|
loader = environment.rbs_loader
|
|
135
193
|
@snapshots.class_decl_paths = loader&.class_decl_paths || {}.freeze
|
|
@@ -156,7 +214,8 @@ module Rigor
|
|
|
156
214
|
return
|
|
157
215
|
end
|
|
158
216
|
|
|
159
|
-
|
|
217
|
+
# nil-safe: the empty-closure path reaches here with no environment when the project has no files.
|
|
218
|
+
loader = environment&.rbs_loader
|
|
160
219
|
@snapshots.synthesized_namespaces = loader&.synthesized_namespaces || []
|
|
161
220
|
@snapshots.quarantined_signatures = loader&.quarantined_signatures || []
|
|
162
221
|
@snapshots.env_build_failure = loader&.env_build_failure
|
|
@@ -220,20 +279,24 @@ module Rigor
|
|
|
220
279
|
# An effects run (ADR-103 WD13) is pinned for exactly the same reason — the Ractor messages carry
|
|
221
280
|
# no side-table channel — and degrades the same way. The degrade is sound rather than merely safe:
|
|
222
281
|
# the sequential fallback still collects, so the effect graph is complete either way.
|
|
223
|
-
|
|
282
|
+
# @param source_files [Array<String>] the file list every worker's / the fallback's environment is
|
|
283
|
+
# built over — the whole project (issue #793), defaulting to `files` for direct callers.
|
|
284
|
+
def dispatch_pool(files, source_files: files)
|
|
224
285
|
if @record_dependencies || @record_effects
|
|
225
|
-
return analyze_files_in_fork_pool(files) if Process.respond_to?(:fork)
|
|
286
|
+
return analyze_files_in_fork_pool(files, source_files: source_files) if Process.respond_to?(:fork)
|
|
226
287
|
|
|
227
288
|
return analyze_files_sequentially_fallback(
|
|
228
|
-
files, reason: "incremental parallelism requires fork; recording sequentially"
|
|
289
|
+
files, reason: "incremental parallelism requires fork; recording sequentially",
|
|
290
|
+
source_files: source_files
|
|
229
291
|
)
|
|
230
292
|
end
|
|
231
293
|
case pool_backend
|
|
232
|
-
when :ractor then analyze_files_in_pool(files)
|
|
233
|
-
when :fork then analyze_files_in_fork_pool(files)
|
|
294
|
+
when :ractor then analyze_files_in_pool(files, source_files: source_files)
|
|
295
|
+
when :fork then analyze_files_in_fork_pool(files, source_files: source_files)
|
|
234
296
|
else
|
|
235
297
|
analyze_files_sequentially_fallback(
|
|
236
|
-
files, reason: "fork-based parallelism is unavailable on this platform"
|
|
298
|
+
files, reason: "fork-based parallelism is unavailable on this platform",
|
|
299
|
+
source_files: source_files
|
|
237
300
|
)
|
|
238
301
|
end
|
|
239
302
|
end
|
|
@@ -299,7 +362,7 @@ module Rigor
|
|
|
299
362
|
# worker touches comes back as an internal analyzer error. What the code below fixes is the
|
|
300
363
|
# failure MODE, not the backend: the run used to hang forever instead of saying anything. Reviving
|
|
301
364
|
# the backend needs an upstream change, which is why `pool_backend` keeps `fork` as the default.
|
|
302
|
-
def analyze_files_in_pool(files) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
365
|
+
def analyze_files_in_pool(files, source_files: files) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
303
366
|
# Pre-warm class-level lazy memos on the MAIN Ractor. `Environment::ClassRegistry.default` is the
|
|
304
367
|
# default kwarg threaded through `Environment.new` inside each worker session; lazy-initialising
|
|
305
368
|
# it from a non-main Ractor would trip `Ractor::IsolationError`. Touching it here forces the
|
|
@@ -314,10 +377,28 @@ module Rigor
|
|
|
314
377
|
# constants.
|
|
315
378
|
if @cache_store.nil?
|
|
316
379
|
return analyze_files_sequentially_fallback(
|
|
317
|
-
files, reason: "pool mode requires a cache_store (--no-cache disables pool)"
|
|
380
|
+
files, reason: "pool mode requires a cache_store (--no-cache disables pool)",
|
|
381
|
+
source_files: source_files
|
|
318
382
|
)
|
|
319
383
|
end
|
|
320
|
-
|
|
384
|
+
# Issue #798 — the SAME gap the fork pool had: this coordinator never analyses a file itself, so
|
|
385
|
+
# without an explicit read the project-signature state (`synthesized-namespace`,
|
|
386
|
+
# `quarantined-signature`, `environment-build-failed`, the conformance results) has no producer.
|
|
387
|
+
# Unlike the fork pool's copy-on-write children, a Ractor worker builds its OWN Environment
|
|
388
|
+
# inside its own isolated Ractor, so nothing here inherits what the coordinator's environment
|
|
389
|
+
# finds. `#prewarm_rbs_cache_for_pool` already builds and fully loads exactly this
|
|
390
|
+
# coordinator-side environment (to warm the cache before any worker spawns); it now hands it
|
|
391
|
+
# back so its RBS state can be read the same way the fork pool reads its pre-fork session
|
|
392
|
+
# environment. The conformance scan inside the snapshot demands the definition of every
|
|
393
|
+
# `rigor:v1:conforms-to` class — a demand no Ractor worker shares memory with — so a resulting
|
|
394
|
+
# definition-build failure is recorded explicitly right after, exactly as the empty-closure
|
|
395
|
+
# branch reads its own environment's demand (#788). No matching explicit call for the HKT-scan
|
|
396
|
+
# outcome: every worker already demands it from its OWN environment in `#drain_reporters`, and
|
|
397
|
+
# the scan has one outcome whoever demands it, so a worker's report already says what the
|
|
398
|
+
# coordinator's own demand would.
|
|
399
|
+
warm_env = prewarm_rbs_cache_for_pool
|
|
400
|
+
snapshot_project_signature_state(warm_env)
|
|
401
|
+
record_definition_build_failures(warm_env&.rbs_loader&.definition_build_failures)
|
|
321
402
|
|
|
322
403
|
configuration = @configuration
|
|
323
404
|
cache_root = @cache_store&.root
|
|
@@ -325,8 +406,9 @@ module Rigor
|
|
|
325
406
|
explain = @explain
|
|
326
407
|
# ADR-32 WD4 — the full project file list travels into every Ractor worker so each worker's
|
|
327
408
|
# WorkerSession can invoke loaded plugins' source_rbs_synthesizers at env-build time. The list is
|
|
328
|
-
# a frozen Array<String>; cheaply shareable.
|
|
329
|
-
|
|
409
|
+
# a frozen Array<String>; cheaply shareable. Issue #793 — it IS the full project now
|
|
410
|
+
# (`source_files`), not the analyzed subset this comment always described.
|
|
411
|
+
shareable_source_files = source_files.map { |path| path.to_s.dup.freeze }.freeze
|
|
330
412
|
|
|
331
413
|
pool = Array.new(@workers) do
|
|
332
414
|
Ractor.new(configuration, cache_root, blueprints, explain, shareable_source_files) do |configuration, cache_root, blueprints, explain, shareable_source_files| # rubocop:disable Layout/LineLength
|
|
@@ -397,15 +479,28 @@ module Rigor
|
|
|
397
479
|
# The files no worker reported — every file of a worker that died, and any file in flight when
|
|
398
480
|
# it did. Re-analysed in process, exactly as the fork backend re-analyses a dead child's slice.
|
|
399
481
|
degraded = files.reject { |path| results_by_path.key?(path) }
|
|
400
|
-
|
|
401
|
-
environment = build_runner_environment(source_files: files)
|
|
402
|
-
degraded.each { |path| results_by_path[path] = @analyze_file.call(path, environment) }
|
|
403
|
-
end
|
|
482
|
+
reanalyze_degraded_in_process(degraded, results_by_path, source_files: source_files)
|
|
404
483
|
|
|
405
484
|
diagnostics = Array(prepare_diagnostics) + files.flat_map { |path| results_by_path.fetch(path, []) }
|
|
406
485
|
degraded.empty? ? diagnostics : diagnostics.unshift(pool_degraded_diagnostic(degraded.size, "ractor"))
|
|
407
486
|
end
|
|
408
487
|
|
|
488
|
+
# The Ractor backend's degrade: the files of a worker that died are re-analysed on a LOCAL
|
|
489
|
+
# environment built over the whole project. That worker never sent `:done`, so nothing drains its
|
|
490
|
+
# reporters — and the local environment has no session to drain either — so the run-level state
|
|
491
|
+
# this analysis produced is taken here, exactly as the sequential fallback takes it: the
|
|
492
|
+
# definition-build failures the re-analysis demanded (#696) and the HKT-scan outcome, demanded
|
|
493
|
+
# once more by the run itself (#784 — a rescued scan failure otherwise vanished with the worker).
|
|
494
|
+
# The fork backend needs none of this: it re-analyses on the parent {WorkerSession} and drains it.
|
|
495
|
+
def reanalyze_degraded_in_process(degraded, results_by_path, source_files:)
|
|
496
|
+
return if degraded.empty?
|
|
497
|
+
|
|
498
|
+
environment = build_runner_environment(source_files: source_files)
|
|
499
|
+
degraded.each { |path| results_by_path[path] = @analyze_file.call(path, environment) }
|
|
500
|
+
record_definition_build_failures(environment.rbs_loader&.definition_build_failures)
|
|
501
|
+
record_hkt_scan_failure(hkt_scan_outcome(environment))
|
|
502
|
+
end
|
|
503
|
+
|
|
409
504
|
# ADR-15 Amendment (2026-05-20) — fork-based worker pool, the active backend for `workers > 0`.
|
|
410
505
|
# Builds ONE {WorkerSession} on the parent, then `fork`s N children that copy-on-write inherit it.
|
|
411
506
|
# Each child analyses a contiguous slice of `files` and writes a Marshal'd `{results:, reporters:}`
|
|
@@ -418,7 +513,11 @@ module Rigor
|
|
|
418
513
|
#
|
|
419
514
|
# A child that exits non-zero (crash / unmarshalable payload) is degraded: the parent re-analyses
|
|
420
515
|
# that slice in-process and prepends a `pool-degraded` warning.
|
|
421
|
-
|
|
516
|
+
#
|
|
517
|
+
# Also snapshots the project-signature state and the effect-annotation carrier off the pre-fork
|
|
518
|
+
# `session.environment` before any child spawns (#798) — the only environment this backend's
|
|
519
|
+
# coordinator ever holds, and so the only place those diagnostic rows can be read from.
|
|
520
|
+
def analyze_files_in_fork_pool(files, source_files: files) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
422
521
|
Environment::ClassRegistry.default
|
|
423
522
|
|
|
424
523
|
session = WorkerSession.new(
|
|
@@ -429,12 +528,27 @@ module Rigor
|
|
|
429
528
|
synthetic_method_index: synthetic_method_index,
|
|
430
529
|
project_patched_methods: project_patched_methods,
|
|
431
530
|
project_scope_seed: project_scope_seed,
|
|
432
|
-
source_files:
|
|
531
|
+
source_files: source_files,
|
|
433
532
|
record_dependencies: @record_dependencies
|
|
434
533
|
)
|
|
435
534
|
# Force the full RBS load on the parent so children copy-on-write inherit a warm Environment
|
|
436
535
|
# rather than each rebuilding it after the fork.
|
|
437
536
|
session.environment.rbs_loader&.prewarm
|
|
537
|
+
# Issue #798 — same set, same ORDER as the sequential path (docs/type-specification/
|
|
538
|
+
# diagnostic-policy.md § `rbs.coverage.*`): the project-signature state
|
|
539
|
+
# (`synthesized-namespace`, `quarantined-signature`, `environment-build-failed`, the
|
|
540
|
+
# conformance results) has no per-file producer, so this coordinator-side environment is the
|
|
541
|
+
# only place a pooled run can take it from — exactly as the empty-closure branch above is the
|
|
542
|
+
# only place an empty run can (#788). Taken BEFORE the fork below: the conformance scan this
|
|
543
|
+
# runs demands the definition of every `rigor:v1:conforms-to` class, and doing that HERE means
|
|
544
|
+
# a resulting definition-build failure is already sitting in the parent's loader at the moment
|
|
545
|
+
# each child copy-on-write-inherits it — every child's own `#drain_reporters` then reports it
|
|
546
|
+
# right alongside whatever its own slice demanded, with no separate plumbing needed. Left
|
|
547
|
+
# unconditional, unlike `#snapshot_fork_pool_stats` below: these are diagnostic rows, not
|
|
548
|
+
# `RunStats` telemetry, and the stats gate must not decide which diagnostics a run reports (a
|
|
549
|
+
# `--workers N --no-stats` run used to say strictly LESS than the sequential path over the
|
|
550
|
+
# same project).
|
|
551
|
+
snapshot_project_signature_state(session.environment)
|
|
438
552
|
snapshot_effect_annotation_carrier(session.environment.rbs_loader)
|
|
439
553
|
snapshot_fork_pool_stats(session) if @collect_stats
|
|
440
554
|
|
|
@@ -488,18 +602,16 @@ module Rigor
|
|
|
488
602
|
exit!(1)
|
|
489
603
|
end
|
|
490
604
|
|
|
491
|
-
#
|
|
492
|
-
#
|
|
605
|
+
# Issue #798 — `RunStats` telemetry ONLY, now that `#snapshot_project_signature_state` (called
|
|
606
|
+
# unconditionally above) owns every diagnostic-bearing slot this method used to ALSO write
|
|
607
|
+
# (`quarantined_signatures`, `env_build_failure`): those must not be gated on `@collect_stats`, and
|
|
608
|
+
# this method's own name says what is left — `class_decl_paths` / `signature_paths`, read off the
|
|
609
|
+
# parent session's loader so end-of-run {RunStats} can attribute the RBS class universe, which a
|
|
610
|
+
# `--no-stats` run legitimately skips.
|
|
493
611
|
def snapshot_fork_pool_stats(session)
|
|
494
612
|
loader = session.environment.rbs_loader
|
|
495
613
|
@snapshots.class_decl_paths = loader&.class_decl_paths || {}.freeze
|
|
496
614
|
@snapshots.signature_paths = loader&.signature_paths || [].freeze
|
|
497
|
-
# The workers each quarantine the same broken file, but they report no diagnostics for it — the row is
|
|
498
|
-
# a whole-run one. Read it off the parent session's loader so a pooled run says exactly what a
|
|
499
|
-
# sequential one says. The same reasoning holds for a total env-build failure.
|
|
500
|
-
@snapshots.quarantined_signatures =
|
|
501
|
-
project_signature_paths? ? (loader&.quarantined_signatures || []) : []
|
|
502
|
-
@snapshots.env_build_failure = project_signature_paths? ? loader&.env_build_failure : nil
|
|
503
615
|
end
|
|
504
616
|
|
|
505
617
|
# Waits for every forked child, merges each successful payload into `results_by_path`, and returns
|
|
@@ -545,9 +657,10 @@ module Rigor
|
|
|
545
657
|
|
|
546
658
|
# ADR-15 Phase 4b.x — drives every cached RBS producer on the main Ractor so each worker can serve
|
|
547
659
|
# all reflection queries from disk (Marshal-load only). Builds a single coordinator-side
|
|
548
|
-
# {Environment} for this purpose
|
|
549
|
-
#
|
|
550
|
-
#
|
|
660
|
+
# {Environment} for this purpose and returns it fully loaded — issue #798: the caller also reads
|
|
661
|
+
# the project-signature state off it, since it is the only environment this backend's coordinator
|
|
662
|
+
# ever holds. Workers still build their OWN `Environment.for_project` inside the Ractor body, which
|
|
663
|
+
# then routes through `cached_env` instead of `RBS::EnvironmentLoader.new`.
|
|
551
664
|
def prewarm_rbs_cache_for_pool
|
|
552
665
|
warm_env = Environment.for_project(
|
|
553
666
|
libraries: @configuration.libraries,
|
|
@@ -560,14 +673,18 @@ module Rigor
|
|
|
560
673
|
rbs_collection_auto_detect: @configuration.rbs_collection_auto_detect
|
|
561
674
|
)
|
|
562
675
|
warm_env.rbs_loader&.prewarm
|
|
676
|
+
warm_env
|
|
563
677
|
end
|
|
564
678
|
|
|
565
679
|
# ADR-15 Phase 4b.x — pool-mode safety net. When pool mode is configured but a precondition fails
|
|
566
680
|
# (currently: `--no-cache` would force workers through `EnvironmentLoader.new`), degrade to
|
|
567
681
|
# sequential analysis with a `:warning` `pool-degraded` diagnostic at run start. The actual
|
|
568
682
|
# per-file analysis runs on the coordinator, identical to the default sequential path.
|
|
569
|
-
|
|
570
|
-
|
|
683
|
+
# @param source_files [Array<String>] issue #793 — the whole project, so this path's environment
|
|
684
|
+
# carries the same plugin-synthesized RBS the pool workers' would. It used to build over `[]`,
|
|
685
|
+
# i.e. with no synthesized RBS at all, even on a full run.
|
|
686
|
+
def analyze_files_sequentially_fallback(files, reason:, source_files: files)
|
|
687
|
+
environment = build_runner_environment(source_files: source_files)
|
|
571
688
|
snapshot_effect_annotation_carrier(environment.rbs_loader)
|
|
572
689
|
diagnostics = files.flat_map { |path| @analyze_file.call(path, environment) }
|
|
573
690
|
loader = environment.rbs_loader
|
|
@@ -576,6 +693,10 @@ module Rigor
|
|
|
576
693
|
# `fork` is unavailable (Windows) and on `--incremental` / effects runs without it: a run that
|
|
577
694
|
# degraded to sequential must not also report less than a sequential run would.
|
|
578
695
|
record_definition_build_failures(loader&.definition_build_failures)
|
|
696
|
+
# Issue #784 — same reasoning: this path's Environment IS the one that reached the scan, so it
|
|
697
|
+
# must snapshot the slot too, or a run that degraded to sequential would report less than a
|
|
698
|
+
# sequential run would. Demanded once by the run as well, for the reason at the sequential site.
|
|
699
|
+
record_hkt_scan_failure(hkt_scan_outcome(environment))
|
|
579
700
|
@snapshots.class_decl_paths = loader&.class_decl_paths || {}.freeze
|
|
580
701
|
@snapshots.signature_paths = loader&.signature_paths || [].freeze
|
|
581
702
|
@snapshots.quarantined_signatures =
|
|
@@ -591,17 +712,7 @@ module Rigor
|
|
|
591
712
|
end
|
|
592
713
|
|
|
593
714
|
def merge_worker_reporters(drained)
|
|
594
|
-
|
|
595
|
-
rbs.fetch(:unresolved_payloads).each do |entry|
|
|
596
|
-
@rbs_extended_reporter.record_unresolved(
|
|
597
|
-
payload: entry.payload, source_location: entry.source_location
|
|
598
|
-
)
|
|
599
|
-
end
|
|
600
|
-
rbs.fetch(:lossy_projections).each do |entry|
|
|
601
|
-
@rbs_extended_reporter.record_lossy_projection(
|
|
602
|
-
head: entry.head, source_location: entry.source_location
|
|
603
|
-
)
|
|
604
|
-
end
|
|
715
|
+
merge_rbs_extended_reporter(drained.fetch(:rbs_extended))
|
|
605
716
|
drained.fetch(:boundary_cross).each do |entry|
|
|
606
717
|
@boundary_cross_reporter.record(
|
|
607
718
|
class_name: entry.class_name,
|
|
@@ -619,10 +730,42 @@ module Rigor
|
|
|
619
730
|
end
|
|
620
731
|
# Issue #696. Fetched with a default so an older drain stays compatible, exactly as the line above.
|
|
621
732
|
record_definition_build_failures(drained[:definition_build_failures])
|
|
733
|
+
# Issue #784. `Hash#[]` is already a nil default, exactly as `env_build_failure` is snapshotted
|
|
734
|
+
# elsewhere — an older drain shape simply has no key and records nothing.
|
|
735
|
+
record_hkt_scan_failure(drained[:hkt_scan_failure])
|
|
622
736
|
end
|
|
623
737
|
|
|
624
738
|
private
|
|
625
739
|
|
|
740
|
+
# Replays one worker's three {RbsExtended::Reporter} streams into the run's own reporter.
|
|
741
|
+
#
|
|
742
|
+
# `hkt_directive_errors` (issue #785) is read with `Hash#[]`'s nil default rather than `fetch`,
|
|
743
|
+
# exactly as `source_rbs_synthesis` is, so an older drain shape simply records nothing.
|
|
744
|
+
#
|
|
745
|
+
# All three streams replay by their `(path, line, column)` primitives (#785 for the hkt stream, #805
|
|
746
|
+
# for its two elders). Every worker reads the same `.rbs`, so each hands over the same entries, and
|
|
747
|
+
# only a primitive-keyed dedup collapses them back to the single row a `--workers=0` run prints — an
|
|
748
|
+
# `RBS::Location` compares equal only against a location over the same `RBS::Buffer` object, so a
|
|
749
|
+
# location-keyed one would print N copies at `--workers=N`. The entries could not reach here carrying
|
|
750
|
+
# a location anyway: the drain Marshals its payload and an `RBS::Location` has no `_dump`.
|
|
751
|
+
def merge_rbs_extended_reporter(rbs)
|
|
752
|
+
rbs.fetch(:unresolved_payloads).each do |entry|
|
|
753
|
+
@rbs_extended_reporter.record_unresolved(
|
|
754
|
+
payload: entry.payload, path: entry.path, line: entry.line, column: entry.column
|
|
755
|
+
)
|
|
756
|
+
end
|
|
757
|
+
rbs.fetch(:lossy_projections).each do |entry|
|
|
758
|
+
@rbs_extended_reporter.record_lossy_projection(
|
|
759
|
+
head: entry.head, path: entry.path, line: entry.line, column: entry.column
|
|
760
|
+
)
|
|
761
|
+
end
|
|
762
|
+
Array(rbs[:hkt_directive_errors]).each do |entry|
|
|
763
|
+
@rbs_extended_reporter.record_hkt_error(
|
|
764
|
+
message: entry.message, path: entry.path, line: entry.line, column: entry.column
|
|
765
|
+
)
|
|
766
|
+
end
|
|
767
|
+
end
|
|
768
|
+
|
|
626
769
|
# Issue #696 — accumulate the per-class `RBS::DefinitionBuilder` failures this run observed, deduped
|
|
627
770
|
# by class name and kept in first-seen order.
|
|
628
771
|
#
|
|
@@ -646,6 +789,48 @@ module Rigor
|
|
|
646
789
|
(@snapshots.definition_build_failures + failures).uniq(&:first).freeze
|
|
647
790
|
end
|
|
648
791
|
|
|
792
|
+
# Issue #784 — first-wins, unlike {#record_definition_build_failures}'s accumulate-and-dedup. That
|
|
793
|
+
# method accumulates because each pool WORKER owns its own loader and its own per-class memo, so a
|
|
794
|
+
# collapsed class can genuinely be observed by only some workers and the run's set is the union.
|
|
795
|
+
# The HKT scan has no such per-worker variation: `Environment#hkt_registry` builds from the SAME
|
|
796
|
+
# `signature_paths:` overlay every worker was handed, so every worker that demands it either all
|
|
797
|
+
# raise identically or all succeed — there is only ever one tuple to record, and `||=` is correct
|
|
798
|
+
# (and cheap) rather than an accumulate-and-dedup this slot never needs.
|
|
799
|
+
def record_hkt_scan_failure(tuple)
|
|
800
|
+
@snapshots.hkt_scan_failure ||= tuple
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
# Issue #784 — demand the registry once on behalf of the run, then read the slot. The seam in
|
|
804
|
+
# {Environment#hkt_registry} is demand-driven, and nothing guarantees any analysed file demands it:
|
|
805
|
+
# a `--verify-incremental` partition or an incremental closure can miss every `Klass.method` call,
|
|
806
|
+
# and then the slot is nil after the loop and the run says nothing — while `--incremental` has also
|
|
807
|
+
# dropped the row from its per-file cache. Demanding here makes the outcome a property of the RUN,
|
|
808
|
+
# not of which files happened to be in it.
|
|
809
|
+
#
|
|
810
|
+
# This is sound where #696's "a demand that is Rigor's own MUST NOT contribute" is not, and the
|
|
811
|
+
# difference is the shape of what is recorded. #696 reports a per-class LIST whose membership is
|
|
812
|
+
# "the classes the analysis demanded"; a Rigor-internal demand adds classes the user never asked
|
|
813
|
+
# about and makes that list vary with configuration. The HKT scan is ONE build with ONE outcome —
|
|
814
|
+
# the same tuple whoever demands it — so an extra demand cannot change what is reported, only
|
|
815
|
+
# guarantee it is observed.
|
|
816
|
+
#
|
|
817
|
+
# What it costs, stated plainly because {#record_definition_build_failures}'s comment promises
|
|
818
|
+
# "nothing is forced here": the demand DOES force the RBS env build when the environment has not
|
|
819
|
+
# built it yet (the scan reads the loader). On every path that reaches this method that build is
|
|
820
|
+
# either already done (the loop demanded it) or the same load one analysed file would have paid:
|
|
821
|
+
# a Marshal load when a cache store exists, the parse a full run pays under `--no-cache`. Never a
|
|
822
|
+
# build on a project with no files (see {#analyze_files}). Memoised, so on a reused Environment
|
|
823
|
+
# this is a hash read.
|
|
824
|
+
#
|
|
825
|
+
# @param environment [Rigor::Environment, nil]
|
|
826
|
+
# @return [Array, nil] the recorded tuple, or nil (no environment, or the scan built)
|
|
827
|
+
def hkt_scan_outcome(environment)
|
|
828
|
+
return nil if environment.nil?
|
|
829
|
+
|
|
830
|
+
environment.hkt_registry
|
|
831
|
+
environment.hkt_scan_failure
|
|
832
|
+
end
|
|
833
|
+
|
|
649
834
|
# True when the project declares its own `signature_paths:` (the only place the
|
|
650
835
|
# qualified-name-without-namespace mistake lives).
|
|
651
836
|
def project_signature_paths?
|
|
@@ -17,7 +17,8 @@ module Rigor
|
|
|
17
17
|
class RunSnapshots
|
|
18
18
|
attr_accessor :class_decl_paths, :signature_paths,
|
|
19
19
|
:synthesized_namespaces, :quarantined_signatures, :conformance_results,
|
|
20
|
-
:env_build_failure, :definition_build_failures, :
|
|
20
|
+
:env_build_failure, :definition_build_failures, :hkt_scan_failure,
|
|
21
|
+
:effect_annotation_carrier
|
|
21
22
|
|
|
22
23
|
# Constructor defaults match the {Runner} constructor: the pre-seed values `build_run_stats` /
|
|
23
24
|
# `pre_file_diagnostics` read before the first analysis path runs are frozen empties. The
|
|
@@ -25,7 +26,9 @@ module Rigor
|
|
|
25
26
|
# `[error_class, first_line, buffer_names]` tuple or nothing. Its per-class sibling
|
|
26
27
|
# `definition_build_failures` (#696) holds a LIST, because a collapsed universe fails many classes,
|
|
27
28
|
# and is accumulated ACROSS pool workers rather than assigned once — see
|
|
28
|
-
# {PoolCoordinator#merge_worker_reporters}.
|
|
29
|
+
# {PoolCoordinator#merge_worker_reporters}. `hkt_scan_failure` (#784) is nil-or-tuple like
|
|
30
|
+
# `env_build_failure`, not a list like `definition_build_failures`: the scan is ONE build over the
|
|
31
|
+
# whole `signature_paths:` overlay, not a per-class one, so it has exactly one outcome per run.
|
|
29
32
|
def initialize
|
|
30
33
|
@class_decl_paths = {}.freeze
|
|
31
34
|
@signature_paths = [].freeze
|
|
@@ -34,6 +37,7 @@ module Rigor
|
|
|
34
37
|
@conformance_results = [].freeze
|
|
35
38
|
@env_build_failure = nil
|
|
36
39
|
@definition_build_failures = [].freeze
|
|
40
|
+
@hkt_scan_failure = nil
|
|
37
41
|
@effect_annotation_carrier = [].freeze
|
|
38
42
|
end
|
|
39
43
|
|
|
@@ -47,6 +51,7 @@ module Rigor
|
|
|
47
51
|
@conformance_results = []
|
|
48
52
|
@env_build_failure = nil
|
|
49
53
|
@definition_build_failures = []
|
|
54
|
+
@hkt_scan_failure = nil
|
|
50
55
|
@effect_annotation_carrier = [].freeze
|
|
51
56
|
end
|
|
52
57
|
end
|
|
@@ -29,6 +29,7 @@ require_relative "../inference/scope_indexer"
|
|
|
29
29
|
require_relative "../inference/synthetic_method_scanner"
|
|
30
30
|
require_relative "../inference/project_patched_scanner"
|
|
31
31
|
require_relative "../inference/method_dispatcher/file_folding"
|
|
32
|
+
require_relative "crash_signature"
|
|
32
33
|
require_relative "buffer_binding"
|
|
33
34
|
require_relative "check_rules"
|
|
34
35
|
require_relative "dependency_recorder"
|
|
@@ -64,7 +65,14 @@ module Rigor
|
|
|
64
65
|
|
|
65
66
|
attr_reader :cache_store, :plugin_registry, :dependency_source_index,
|
|
66
67
|
:rbs_extended_reporter, :boundary_cross_reporter,
|
|
67
|
-
:analyzed_files, :unresolved_self_calls, :seed_bundles
|
|
68
|
+
:analyzed_files, :unresolved_self_calls, :seed_bundles,
|
|
69
|
+
# #788 rounds 6–7 — the rows per-file analysis produced this run, severity-resolved exactly
|
|
70
|
+
# as the run's stream is and sliced to this run's targets (a pool backend folds `.rigor.yml`
|
|
71
|
+
# prepare / degraded rows into `analyze_files`'s return). `IncrementalSession` caches ONLY
|
|
72
|
+
# this and serves reused files from it without re-stamping: a run-level row is regenerated
|
|
73
|
+
# every run wherever it is positioned, and slicing the run's full stream by path cached the
|
|
74
|
+
# file-positioned ones (`effect.annotations-unchecked`, `source-rbs-*`).
|
|
75
|
+
:per_file_diagnostics
|
|
68
76
|
|
|
69
77
|
# ADR-46 — the per-file cross-file read records this run captured (empty unless
|
|
70
78
|
# `record_dependencies: true`). Sequential analysis records into `@file_dependencies` via
|
|
@@ -302,6 +310,7 @@ module Rigor
|
|
|
302
310
|
# See `self_undefined_rule_active?`.
|
|
303
311
|
@self_undefined_rule_active = nil
|
|
304
312
|
@analyzed_files = [].freeze
|
|
313
|
+
@per_file_diagnostics = [].freeze
|
|
305
314
|
# In-memory source map for `#run_source` — `{ logical_path => source String }`. When set,
|
|
306
315
|
# `parse_source` reads bytes from here instead of disk and `expand_paths` accepts the (possibly
|
|
307
316
|
# non-existent) logical path. nil on a normal disk-backed run.
|
|
@@ -426,6 +435,9 @@ module Rigor
|
|
|
426
435
|
# Per-run reset of the environment the cacheable path resolves, reused by the envelope pass so a
|
|
427
436
|
# run never builds two.
|
|
428
437
|
@run_environment = nil
|
|
438
|
+
# #788 — the per-file reader is assigned only on the analysis (miss) path; reset it here so a run the
|
|
439
|
+
# ADR-45 result cache serves does not answer with the previous run's rows.
|
|
440
|
+
@per_file_diagnostics = [].freeze
|
|
429
441
|
# ADR-84 WD2 — roll the return-memo bucket: a fresh frozen token per run makes every per-file scope
|
|
430
442
|
# of THIS run share one memo bucket while entries from any earlier run in this process (stale after
|
|
431
443
|
# an edit) become unreachable.
|
|
@@ -674,7 +686,14 @@ module Rigor
|
|
|
674
686
|
@run_generation = Object.new.freeze
|
|
675
687
|
run_project_pre_passes(expansion: expansion)
|
|
676
688
|
ensure_project_discovery(expansion)
|
|
677
|
-
|
|
689
|
+
# Issue #795 — `source_files:` is the WHOLE project's file list, never `target_files(expansion)`.
|
|
690
|
+
# `IncrementalSession#build_runner` threads its own `@buffer` into this Runner, so in editor-buffer
|
|
691
|
+
# mode `target_files` narrows to the buffer's single logical path; an environment built over just
|
|
692
|
+
# that path drops every OTHER file's plugin-synthesized virtual RBS, which can flip a re-evaluated
|
|
693
|
+
# return descriptor and wrongly declare a caller's return type unstable (or stable) relative to the
|
|
694
|
+
# full-project answer. This probe never analyzes a file, so it carries none of #788's per-file-cache
|
|
695
|
+
# duplication concern either.
|
|
696
|
+
environment = @pool_coordinator.resolve_sequential_environment(source_files: expansion.fetch(:files))
|
|
678
697
|
specs.to_h do |spec|
|
|
679
698
|
[[spec[:class_name], spec[:method_name], spec[:singleton]], evaluate_spec_returns(spec, environment)]
|
|
680
699
|
end
|
|
@@ -927,9 +946,19 @@ module Rigor
|
|
|
927
946
|
).diagnostics
|
|
928
947
|
end
|
|
929
948
|
|
|
949
|
+
# Issue #795 — `source_files:` is the WHOLE project's file list (`expansion.fetch(:files)`), never
|
|
950
|
+
# `target_files(expansion)`. A subset or editor-buffer run's `target_files` narrows to the
|
|
951
|
+
# `analyze_only` closure or the buffer's single logical path; building the envelope walk's
|
|
952
|
+
# environment over that subset drops every plugin-synthesized virtual RBS from an excluded file, so
|
|
953
|
+
# an envelope declared only in that file's inline annotation is invisible to the walk — the same #793
|
|
954
|
+
# gap #788 closed for per-file analysis, left open here because #788's binding sentences scoped
|
|
955
|
+
# themselves to "the environments the per-file analysis builds". This path is exempt from #788's
|
|
956
|
+
# per-file-cache duplication concern: `effect.unknown-label` (and its envelope-pass siblings) are
|
|
957
|
+
# produced by this pass, never by `Runner#per_file_diagnostics`, so `IncrementalSession` never caches
|
|
958
|
+
# them and widening this source list cannot duplicate a row on recheck.
|
|
930
959
|
def envelope_rbs_loader(expansion)
|
|
931
960
|
environment = @run_environment ||
|
|
932
|
-
@pool_coordinator.resolve_sequential_environment(source_files:
|
|
961
|
+
@pool_coordinator.resolve_sequential_environment(source_files: expansion.fetch(:files))
|
|
933
962
|
environment&.rbs_loader
|
|
934
963
|
rescue StandardError
|
|
935
964
|
nil
|
|
@@ -985,7 +1014,17 @@ module Rigor
|
|
|
985
1014
|
# per-file cache, so it needs the full analyzed set to subtract the affected closure from.
|
|
986
1015
|
targets = target_files(expansion)
|
|
987
1016
|
@analyzed_files = targets
|
|
988
|
-
|
|
1017
|
+
# Issue #784 — the whole project's file list rides along so an EMPTY `targets` (a narrowed run whose
|
|
1018
|
+
# closure is empty) can still resolve the environment a full run would — same files, same
|
|
1019
|
+
# synthesized RBS — to demand the HKT registry once, while a project with no files resolves nothing.
|
|
1020
|
+
# #788 rounds 6–7 — the per-file stream is kept apart from the run-level streams appended below,
|
|
1021
|
+
# because `IncrementalSession` must cache ONLY what per-file analysis produced (#per_file_diagnostics),
|
|
1022
|
+
# and the reader is exposed SEVERITY-RESOLVED and sliced to this run's targets. The cache serves a
|
|
1023
|
+
# reused file without re-stamping, so a raw row would resurrect a rule the profile resolves to `:off`
|
|
1024
|
+
# (`static.value-use.void` ships off on the default profile) and serve the authored severity where an
|
|
1025
|
+
# override re-stamps it; and a pool backend folds `.rigor.yml`-positioned prepare / pool-degraded rows
|
|
1026
|
+
# into the same return, which the slice drops. The run's own stream is stamped once, at the end.
|
|
1027
|
+
diagnostics += analyze_targets(targets, environment: environment, project_files: expansion.fetch(:files))
|
|
989
1028
|
# ADR-103 WD12 — the effect fixpoint, in the post-pool aggregation slot beside the conformance
|
|
990
1029
|
# results. Graph-only over a finite lattice, so it is a plain worklist to a true fixpoint; it
|
|
991
1030
|
# contributes NO diagnostics and its result leaves through `#effect_table`, never through the
|
|
@@ -993,10 +1032,14 @@ module Rigor
|
|
|
993
1032
|
close_effect_graph
|
|
994
1033
|
diagnostics += @diagnostic_aggregator.rbs_quarantined_signature_diagnostics
|
|
995
1034
|
diagnostics += @diagnostic_aggregator.rbs_environment_build_failed_diagnostics
|
|
996
|
-
# Issue #696 — after its env-wide twin and before the synthesized-namespace notice: the
|
|
1035
|
+
# Issue #696 — after its env-wide twin and before the synthesized-namespace notice: the four
|
|
997
1036
|
# `rbs.coverage.*` build conditions surface widest-consequence first, and their relative order is
|
|
998
1037
|
# the diagnostic output contract.
|
|
999
1038
|
diagnostics += @diagnostic_aggregator.rbs_definition_build_failed_diagnostics
|
|
1039
|
+
# Issue #784 — last of the four, deliberately: it loses only the IMPLICIT HKT registrations a
|
|
1040
|
+
# `type` alias would have contributed, never a class's own declared method surface, so it is the
|
|
1041
|
+
# narrowest-consequence rung on the same ladder.
|
|
1042
|
+
diagnostics += @diagnostic_aggregator.rbs_hkt_scan_failed_diagnostics
|
|
1000
1043
|
diagnostics += @diagnostic_aggregator.rbs_synthesized_namespace_diagnostics
|
|
1001
1044
|
diagnostics += @diagnostic_aggregator.conforms_to_diagnostics
|
|
1002
1045
|
diagnostics += @diagnostic_aggregator.rbs_extended_reporter_diagnostics
|
|
@@ -1004,6 +1047,21 @@ module Rigor
|
|
|
1004
1047
|
diagnostics + @diagnostic_aggregator.source_rbs_synthesis_diagnostics
|
|
1005
1048
|
end
|
|
1006
1049
|
|
|
1050
|
+
# #788 round 7 — runs per-file analysis over `targets` and exposes what it produced as
|
|
1051
|
+
# `#per_file_diagnostics`: the `analyze_files` return, stamped with the same severity profile the run's
|
|
1052
|
+
# own stream gets (`SeverityStamp` drops `:off` rows and re-stamps overrides, and the per-file cache never
|
|
1053
|
+
# re-stamps), sliced to the rows positioned at the targets. Returns the RAW return for the run's stream,
|
|
1054
|
+
# which is stamped once, at the end of `#run_analysis`.
|
|
1055
|
+
def analyze_targets(targets, environment:, project_files:)
|
|
1056
|
+
raw = @pool_coordinator.analyze_files(targets, environment: environment, project_files: project_files)
|
|
1057
|
+
analysed = targets.to_set
|
|
1058
|
+
@per_file_diagnostics = @diagnostic_aggregator.apply_severity_profile(raw)
|
|
1059
|
+
.select { |diagnostic| analysed.include?(diagnostic.path) }
|
|
1060
|
+
.freeze
|
|
1061
|
+
raw
|
|
1062
|
+
end
|
|
1063
|
+
private :analyze_targets
|
|
1064
|
+
|
|
1007
1065
|
# ADR-67 WD6a — the check-walk parameter-inference pre-pass. Populates `@project_param_inferred_types`
|
|
1008
1066
|
# (read by `project_scope_seed_tables`) with the call-site union of every undeclared parameter, running
|
|
1009
1067
|
# ONE round (a single hop of call-site → param typing; the protection scan's three-round fixpoint stays a
|
|
@@ -1427,7 +1485,7 @@ module Rigor
|
|
|
1427
1485
|
# indexes, prepare-diagnostic snapshot, and the four end-of-pass snapshots) is reached through reader
|
|
1428
1486
|
# procs so each collaborator observes the live ivar value at call time without a back-reference
|
|
1429
1487
|
# cycle. The reporter accumulators and the {RunSnapshots} sink are shared mutable instances.
|
|
1430
|
-
def build_collaborators # rubocop:disable Metrics/MethodLength
|
|
1488
|
+
def build_collaborators # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
1431
1489
|
@pre_passes = ProjectPrePasses.new(
|
|
1432
1490
|
configuration: @configuration, cache_store: @cache_store, buffer: @buffer,
|
|
1433
1491
|
plugin_requirer: @plugin_requirer, pool_mode: -> { pool_mode? }
|
|
@@ -1462,6 +1520,7 @@ module Rigor
|
|
|
1462
1520
|
quarantined_signatures_snapshot: -> { @snapshots.quarantined_signatures },
|
|
1463
1521
|
env_build_failure_snapshot: -> { @snapshots.env_build_failure },
|
|
1464
1522
|
definition_build_failures_snapshot: -> { @snapshots.definition_build_failures },
|
|
1523
|
+
hkt_scan_failure_snapshot: -> { @snapshots.hkt_scan_failure },
|
|
1465
1524
|
conformance_results_snapshot: -> { @snapshots.conformance_results }
|
|
1466
1525
|
)
|
|
1467
1526
|
end
|
|
@@ -1876,7 +1935,7 @@ module Rigor
|
|
|
1876
1935
|
path: path,
|
|
1877
1936
|
line: 1,
|
|
1878
1937
|
column: 1,
|
|
1879
|
-
message:
|
|
1938
|
+
message: CrashSignature.check_rule_message(e),
|
|
1880
1939
|
severity: :error
|
|
1881
1940
|
)
|
|
1882
1941
|
]
|