rigortype 0.3.6 → 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/data/builtins/ruby_core/date.yml +6 -3
- data/data/builtins/ruby_core/enumerable.yml +1 -0
- data/data/builtins/ruby_core/exception.yml +2 -1
- data/data/builtins/ruby_core/file.yml +28 -14
- data/data/builtins/ruby_core/hash.yml +5 -2
- data/data/builtins/ruby_core/io.yml +33 -16
- data/data/builtins/ruby_core/random.yml +2 -1
- data/data/builtins/ruby_core/re.yml +6 -3
- data/data/builtins/ruby_core/struct.yml +2 -0
- data/data/builtins/ruby_core/time.yml +2 -1
- data/data/gem_overlay/activesupport/core_ext.rbs +409 -11
- data/docs/handbook/11-sig-gen.md +24 -14
- data/docs/manual/02-cli-reference.md +23 -7
- data/docs/manual/04-diagnostics.md +1 -1
- data/docs/manual/05-inspecting-types.md +20 -8
- data/docs/manual/07-plugins.md +4 -0
- data/docs/manual/plugins/rigor-actionpack.md +61 -0
- data/docs/manual/plugins/rigor-activerecord.md +74 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +114 -12
- data/docs/manual/plugins/rigor-sidekiq.md +22 -0
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +12 -0
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +98 -0
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +3 -3
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +199 -0
- data/lib/rigor/analysis/check_rules/rule_walk.rb +1 -2
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +2 -2
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +6 -12
- data/lib/rigor/analysis/check_rules.rb +383 -48
- data/lib/rigor/analysis/crash_signature.rb +188 -0
- data/lib/rigor/analysis/dependency_recorder.rb +18 -3
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +2 -1
- data/lib/rigor/analysis/incremental.rb +28 -0
- data/lib/rigor/analysis/incremental_session.rb +63 -16
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +1 -2
- data/lib/rigor/analysis/reachability/graph.rb +14 -5
- data/lib/rigor/analysis/reachability/scan.rb +7 -3
- data/lib/rigor/analysis/result.rb +32 -0
- data/lib/rigor/analysis/run_cache_key.rb +41 -1
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +233 -16
- data/lib/rigor/analysis/runner/pool_coordinator.rb +266 -47
- data/lib/rigor/analysis/runner/project_pre_passes.rb +15 -11
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -2
- data/lib/rigor/analysis/runner.rb +212 -16
- data/lib/rigor/analysis/worker_session.rb +37 -3
- data/lib/rigor/bleeding_edge.rb +7 -6
- data/lib/rigor/builtins/hkt_builtins.rb +45 -6
- data/lib/rigor/builtins/imported_refinements.rb +11 -9
- data/lib/rigor/builtins/predefined_constant_refinements.rb +108 -59
- data/lib/rigor/builtins/static_return_refinements.rb +20 -1
- data/lib/rigor/cache/annotation_location.rb +72 -0
- data/lib/rigor/cache/descriptor.rb +42 -2
- data/lib/rigor/cache/incremental_snapshot.rb +40 -3
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +70 -8
- data/lib/rigor/cache/store.rb +17 -1
- data/lib/rigor/cli/coverage_command.rb +23 -18
- data/lib/rigor/cli/coverage_mutation.rb +13 -17
- data/lib/rigor/cli/coverage_scan.rb +47 -6
- data/lib/rigor/cli/fused_protection_renderer.rb +19 -2
- data/lib/rigor/cli/fused_protection_report.rb +23 -2
- data/lib/rigor/cli/measurement_integrity_warning.rb +57 -0
- data/lib/rigor/cli/mutation_protection_renderer.rb +22 -2
- data/lib/rigor/cli/mutation_protection_report.rb +31 -2
- data/lib/rigor/cli/sig_gen_command.rb +47 -0
- data/lib/rigor/cli/type_of_command.rb +188 -41
- data/lib/rigor/cli/type_of_renderer.rb +72 -3
- data/lib/rigor/cli/type_scan_command.rb +10 -1
- data/lib/rigor/cli.rb +1 -1
- data/lib/rigor/configuration.rb +7 -4
- data/lib/rigor/effects/plugin_facts.rb +1 -1
- data/lib/rigor/effects/scanner.rb +2 -3
- data/lib/rigor/environment/bundle_sig_discovery.rb +64 -13
- data/lib/rigor/environment/failure_slot.rb +28 -0
- data/lib/rigor/environment/lockfile_resolver.rb +15 -5
- data/lib/rigor/environment/missing_gem_constant_index.rb +45 -4
- data/lib/rigor/environment/rbs_hierarchy.rb +16 -22
- data/lib/rigor/environment/rbs_loader.rb +743 -93
- data/lib/rigor/environment.rb +125 -25
- data/lib/rigor/inference/acceptance.rb +172 -20
- data/lib/rigor/inference/captured_locals.rb +62 -0
- data/lib/rigor/inference/content_join.rb +347 -0
- data/lib/rigor/inference/def_handle.rb +15 -3
- data/lib/rigor/inference/def_node_resolver.rb +62 -3
- data/lib/rigor/inference/expression_typer.rb +1020 -141
- data/lib/rigor/inference/fork_map.rb +6 -1
- data/lib/rigor/inference/hkt_reducer.rb +12 -1
- data/lib/rigor/inference/hkt_registry.rb +61 -3
- data/lib/rigor/inference/hkt_sugar_translator.rb +87 -0
- data/lib/rigor/inference/index_write_widening.rb +48 -0
- data/lib/rigor/inference/indexed_narrowing.rb +14 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +7 -5
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +10 -0
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +58 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +81 -38
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +54 -17
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +63 -0
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +63 -10
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +104 -0
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +81 -0
- data/lib/rigor/inference/method_dispatcher.rb +155 -14
- data/lib/rigor/inference/method_parameter_binder.rb +3 -3
- data/lib/rigor/inference/mutation_widening.rb +244 -174
- data/lib/rigor/inference/narrowing.rb +331 -27
- data/lib/rigor/inference/parameter_inference_collector.rb +1 -0
- data/lib/rigor/inference/pre_eval_constants.rb +15 -0
- data/lib/rigor/inference/precision_scanner.rb +5 -2
- data/lib/rigor/inference/project_patched_scanner.rb +2 -1
- data/lib/rigor/inference/rbs_type_translator.rb +89 -39
- data/lib/rigor/inference/scope_indexer.rb +1493 -140
- data/lib/rigor/inference/statement_evaluator.rb +276 -91
- data/lib/rigor/inference/struct_fold_safety.rb +186 -27
- data/lib/rigor/inference/version_guard.rb +229 -0
- data/lib/rigor/language_server/selection_range_provider.rb +1 -1
- data/lib/rigor/plugin/base.rb +3 -2
- data/lib/rigor/plugin/inflector.rb +14 -5
- data/lib/rigor/plugin/io_boundary.rb +107 -4
- data/lib/rigor/plugin/loader.rb +14 -0
- data/lib/rigor/plugin/registry.rb +25 -2
- data/lib/rigor/protection/analysis_guard.rb +60 -0
- data/lib/rigor/protection/closure_kill_oracle.rb +43 -38
- data/lib/rigor/protection/diagnostic_oracle.rb +12 -4
- data/lib/rigor/protection/discovery_seed.rb +1 -1
- data/lib/rigor/protection/measurement_integrity.rb +36 -0
- data/lib/rigor/protection/mutation_scanner.rb +61 -6
- data/lib/rigor/protection/mutator.rb +121 -18
- 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/reflection.rb +182 -30
- data/lib/rigor/scope/discovery_index.rb +39 -1
- data/lib/rigor/scope.rb +385 -4
- data/lib/rigor/sig_gen/classification.rb +12 -1
- data/lib/rigor/sig_gen/generator.rb +320 -85
- data/lib/rigor/sig_gen/renderer.rb +14 -12
- data/lib/rigor/sig_gen/writer.rb +3 -0
- data/lib/rigor/source/constant_path.rb +79 -2
- data/lib/rigor/triage/catalogue.rb +1 -1
- data/lib/rigor/type/combinator.rb +10 -0
- data/lib/rigor/type/maybe.rb +47 -0
- data/lib/rigor/type/refined.rb +1 -2
- data/lib/rigor/type/result.rb +53 -0
- data/lib/rigor/type.rb +2 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +3 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +58 -8
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +15 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +4 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +3 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +39 -14
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +36 -3
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +6 -2
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +21 -5
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +47 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +13 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +242 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +3 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +7 -3
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +62 -11
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +15 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +3 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +5 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +2 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +798 -22
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +156 -13
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +140 -40
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +2 -2
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +20 -6
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +14 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +6 -3
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +23 -6
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +264 -9
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +876 -23
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +99 -0
- data/plugins/rigor-dry-monads/lib/rigor-dry-monads.rb +5 -0
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +34 -0
- data/plugins/rigor-ethon/lib/rigor-ethon.rb +3 -0
- data/plugins/rigor-ethon/sig/ethon.rbs +27 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +3 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +198 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/binding_recognizer.rb +75 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/catalog.rb +64 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +173 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/target_detector.rb +46 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +161 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +121 -0
- data/plugins/rigor-ffi/lib/rigor-ffi.rb +3 -0
- data/plugins/rigor-ffi/sig/ffi.rbs +67 -0
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +19 -0
- data/plugins/rigor-ffi-rzmq/lib/rigor-ffi-rzmq.rb +3 -0
- data/plugins/rigor-ffi-rzmq/sig/ffi_rzmq.rbs +29 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +2 -4
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +2 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +2 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +2 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +2 -1
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +156 -11
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +30 -0
- data/plugins/rigor-rbnacl/lib/rigor-rbnacl.rb +3 -0
- data/plugins/rigor-rbnacl/sig/rbnacl.rbs +22 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +55 -0
- data/plugins/rigor-sassc/lib/rigor-sassc.rb +3 -0
- data/plugins/rigor-sassc/sig/sassc.rbs +24 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +32 -11
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +3 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +4 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +63 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +15 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +61 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +4 -2
- data/sig/rigor/analysis/baseline.rbs +1 -1
- data/sig/rigor/environment.rbs +9 -0
- data/sig/rigor/inference.rbs +4 -1
- data/sig/rigor/plugin/io_boundary.rbs +2 -0
- data/sig/rigor/reflection.rbs +3 -1
- data/sig/rigor/scope.rbs +25 -1
- data/sig/rigor/type.rbs +95 -1
- data/sig/rigor.rbs +16 -0
- metadata +71 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../crash_signature"
|
|
3
4
|
require_relative "../diagnostic"
|
|
4
5
|
require_relative "../severity_stamp"
|
|
5
6
|
|
|
@@ -36,12 +37,20 @@ module Rigor
|
|
|
36
37
|
# because they do not parse (`[path, first_error_line]` pairs).
|
|
37
38
|
# @param env_build_failure_snapshot [#call] reader returning the total RBS env-build failure tuple
|
|
38
39
|
# (`[error_class, first_error_line, conflicting_buffer_names]`) or nil when the env built.
|
|
40
|
+
# @param definition_build_failures_snapshot [#call] issue #696 — reader returning the per-class
|
|
41
|
+
# `RBS::DefinitionBuilder` failures the run observed, as `[class_name, error_class, member,
|
|
42
|
+
# conflicting_buffer_names]` tuples. Empty for a healthy sig set.
|
|
43
|
+
# @param hkt_scan_failure_snapshot [#call] issue #784 — reader returning the `[error_class_name,
|
|
44
|
+
# first_message_line, raw_frame_or_nil, stage]` tuple whichever stage of the HKT-registry build
|
|
45
|
+
# raised, or nil when both built (or were never demanded). `stage` is `:scan` (the RBS `type`-alias
|
|
46
|
+
# scan) or `:overlay` (the plugin-manifest aggregation, #791), and picks the row's wording.
|
|
39
47
|
# @param conformance_results_snapshot [#call] reader.
|
|
40
48
|
def initialize(configuration:, rbs_extended_reporter:, boundary_cross_reporter:, # rubocop:disable Metrics/ParameterLists
|
|
41
49
|
source_rbs_synthesis_reporter:, plugin_registry:, dependency_source_index:,
|
|
42
50
|
pool_mode:, cached_plugin_prepare_diagnostics:,
|
|
43
51
|
pre_eval_diagnostics_from_scanner:, synthesized_namespaces_snapshot:,
|
|
44
52
|
quarantined_signatures_snapshot:, env_build_failure_snapshot:,
|
|
53
|
+
definition_build_failures_snapshot:, hkt_scan_failure_snapshot:,
|
|
45
54
|
conformance_results_snapshot:)
|
|
46
55
|
@configuration = configuration
|
|
47
56
|
@rbs_extended_reporter = rbs_extended_reporter
|
|
@@ -55,6 +64,8 @@ module Rigor
|
|
|
55
64
|
@synthesized_namespaces_snapshot_reader = synthesized_namespaces_snapshot
|
|
56
65
|
@quarantined_signatures_snapshot_reader = quarantined_signatures_snapshot
|
|
57
66
|
@env_build_failure_snapshot_reader = env_build_failure_snapshot
|
|
67
|
+
@definition_build_failures_snapshot_reader = definition_build_failures_snapshot
|
|
68
|
+
@hkt_scan_failure_snapshot_reader = hkt_scan_failure_snapshot
|
|
58
69
|
@conformance_results_snapshot_reader = conformance_results_snapshot
|
|
59
70
|
end
|
|
60
71
|
|
|
@@ -311,9 +322,11 @@ module Rigor
|
|
|
311
322
|
# user knows their sig set is malformed (`rbs validate` rejects it) and can fix it at the source.
|
|
312
323
|
# Authored `:info`: the analysis already succeeded; this is advisory, never a gate. Empty for a
|
|
313
324
|
# well-formed sig set.
|
|
314
|
-
# An unparseable `.rbs` under `signature_paths:` is QUARANTINED so the
|
|
315
|
-
#
|
|
316
|
-
#
|
|
325
|
+
# An unparseable or declaration-colliding `.rbs` under `signature_paths:` is QUARANTINED so the
|
|
326
|
+
# rest of the env survives (PR #50; issue #777 extends this to class-vs-module / constant
|
|
327
|
+
# collisions against bundled RBS), which means the types it declares are silently absent — calls
|
|
328
|
+
# into them read `Dynamic[top]`, and the run gets *quieter*, not louder. The stderr banner alone
|
|
329
|
+
# never reached CI:
|
|
317
330
|
# it is not a diagnostic, so it is absent from `--format json` / SARIF / GitHub annotations / the LSP
|
|
318
331
|
# and cannot move the exit code. This puts it in the diagnostic stream where every channel sees it.
|
|
319
332
|
#
|
|
@@ -351,6 +364,51 @@ module Rigor
|
|
|
351
364
|
[build_rbs_environment_build_failed_diagnostic(failure)]
|
|
352
365
|
end
|
|
353
366
|
|
|
367
|
+
# Issue #696 — the third rung of the same ladder, between its two neighbours by consequence: a
|
|
368
|
+
# QUARANTINED file removes what one FILE declared, this removes what one CLASS declared, an
|
|
369
|
+
# ENV-BUILD failure removes everything. `RBS::DefinitionBuilder` raising for a class (typically
|
|
370
|
+
# `DuplicatedMethodDefinitionError`: two signature sources declaring the same method, e.g. a project
|
|
371
|
+
# `sig/` carrying a vendored COPY of a bundled plugin's `.rbs`) leaves the class KNOWN but with no
|
|
372
|
+
# method surface, so every call on it — real methods and typos alike — reads `Dynamic[top]`. When
|
|
373
|
+
# the collision is on a class others inherit, the whole bundled type universe goes with it: the
|
|
374
|
+
# observed shape is thousands of stderr warnings, ZERO diagnostics, and exit 0.
|
|
375
|
+
#
|
|
376
|
+
# Not "drop the class to genuinely-unknown" instead. That also removes diagnostics, so it is not
|
|
377
|
+
# louder; it changes `Dynamic[top]` semantics for every rule that consults `class_known?`; and
|
|
378
|
+
# `class_known?` reads {Environment::RbsLoader#known_class_names_set}, a different table from the
|
|
379
|
+
# definition builder, so it would need a new "known but unbuildable" state regardless. The failure
|
|
380
|
+
# is made REPORTABLE; the class is not made invisible.
|
|
381
|
+
#
|
|
382
|
+
# Authored `:warning`, not `:error`, for the same reason as both neighbours: the collision is
|
|
383
|
+
# typically between the user's `sig/` and Rigor's OWN bundled RBS, so an `:error` default would let
|
|
384
|
+
# a Rigor release turn a green build red with no user change (ADR-5 / AGENTS.md § FP discipline).
|
|
385
|
+
# The `reject-unparseable-signatures` bleeding-edge feature promotes it to `:error`.
|
|
386
|
+
def rbs_definition_build_failed_diagnostics
|
|
387
|
+
failures = definition_build_failures_snapshot
|
|
388
|
+
return [] if failures.nil? || failures.empty?
|
|
389
|
+
|
|
390
|
+
[build_rbs_definition_build_failed_diagnostic(failures)]
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# Issue #784 — the fourth rung, narrowest consequence: one of the two builds behind
|
|
394
|
+
# `Environment#hkt_registry` raised instead of building. The `:scan` stage is the implicit HKT scan
|
|
395
|
+
# over RBS `type` aliases (ADR-20 WD2's `%a{rigor:v1:hkt_register / hkt_define}` overlay AND any
|
|
396
|
+
# recursive `type` alias in the project's own `.rbs` or an installed `rbs collection`); analysis
|
|
397
|
+
# proceeds over the PRE-scan registry — bundled builtins (`json::value`, …) plus the plugin overlay
|
|
398
|
+
# — so a `type` alias that would have registered as a type constructor reads its bound
|
|
399
|
+
# (`Dynamic[top]`) instead. The `:overlay` stage (#791) is the plugin-manifest aggregation, which
|
|
400
|
+
# sat ABOVE the seam until the run-owned demands made a raise there abort the run; it degrades one
|
|
401
|
+
# step further in and one step narrower — the plugin entries are dropped, the `.rbs` scan still
|
|
402
|
+
# runs. Either way everything else this run reports is unaffected: no class loses its method
|
|
403
|
+
# surface, no signature file is skipped, the environment builds. That is why this sits LAST on the
|
|
404
|
+
# ladder, after its two `rbs.coverage.*` siblings above.
|
|
405
|
+
def rbs_hkt_scan_failed_diagnostics
|
|
406
|
+
failure = hkt_scan_failure_snapshot
|
|
407
|
+
return [] if failure.nil?
|
|
408
|
+
|
|
409
|
+
[build_rbs_hkt_scan_failed_diagnostic(failure)]
|
|
410
|
+
end
|
|
411
|
+
|
|
354
412
|
def rbs_synthesized_namespace_diagnostics
|
|
355
413
|
synthesized = synthesized_namespaces_snapshot
|
|
356
414
|
return [] if synthesized.nil? || synthesized.empty?
|
|
@@ -428,11 +486,12 @@ module Rigor
|
|
|
428
486
|
path: ".rigor.yml",
|
|
429
487
|
line: 1,
|
|
430
488
|
column: 1,
|
|
431
|
-
message: "#{quarantined.size} RBS file(s) under `signature_paths:`
|
|
432
|
-
"
|
|
433
|
-
"loaded, but the types those files declare
|
|
434
|
-
"`Dynamic[top]`, so this run is quieter than it
|
|
435
|
-
"parse error(s)
|
|
489
|
+
message: "#{quarantined.size} RBS file(s) under `signature_paths:` were SKIPPED " \
|
|
490
|
+
"(unparseable, or duplicated against bundled RBS): #{sample.join(', ')}#{suffix}. " \
|
|
491
|
+
"The rest of your RBS environment still loaded, but the types those files declare " \
|
|
492
|
+
"are absent — calls into them read `Dynamic[top]`, so this run is quieter than it " \
|
|
493
|
+
"should be, not cleaner. Fix the parse error(s) or remove the conflicting " \
|
|
494
|
+
"declaration(s) (`rbs validate`) to restore that coverage.",
|
|
436
495
|
severity: :warning,
|
|
437
496
|
rule: "rbs.coverage.quarantined-signature",
|
|
438
497
|
source_family: :builtin
|
|
@@ -462,6 +521,124 @@ module Rigor
|
|
|
462
521
|
)
|
|
463
522
|
end
|
|
464
523
|
|
|
524
|
+
# Issue #696. One diagnostic per RUN, not per class: a collision on a widely-inherited class fails
|
|
525
|
+
# every descendant, and 2,709 rows saying the same thing about one `.rbs` line is noise, not
|
|
526
|
+
# visibility.
|
|
527
|
+
#
|
|
528
|
+
# The failed-class list alone is not actionable, and that is what the "First failure" clause is for.
|
|
529
|
+
# A duplicate on `::Object#blank?` fails `String`, `Integer`, `Array` and 1,333 more — every name in
|
|
530
|
+
# that list is a DESCENDANT, and none of them is where the fix goes. The member comes off the error
|
|
531
|
+
# object rather than out of its message ({RbsLoader#definition_build_member}), so it names the
|
|
532
|
+
# culprit and reads the same on a cache hit, where every `RBS::Location` has been dumped to a
|
|
533
|
+
# sentinel. The error class is attributed to that first failure explicitly rather than to all of
|
|
534
|
+
# them: the per-class memo keeps only the first reason, and one run can mix error classes.
|
|
535
|
+
def build_rbs_definition_build_failed_diagnostic(failures)
|
|
536
|
+
sample_size = 5
|
|
537
|
+
files = failures.flat_map { |failure| Array(failure[3]) }.uniq.map { |name| relative_signature_path(name) }
|
|
538
|
+
Diagnostic.new(
|
|
539
|
+
path: ".rigor.yml",
|
|
540
|
+
line: 1,
|
|
541
|
+
column: 1,
|
|
542
|
+
message: "#{failures.size} RBS class definition(s) failed to build: " \
|
|
543
|
+
"#{sampled(failures.map(&:first), sample_size)}." \
|
|
544
|
+
"#{first_failure_clause(failures.first)}#{conflicting_files_clause(files, sample_size)} " \
|
|
545
|
+
"Rigor still treats each class as KNOWN, so calls into it — real methods and typos " \
|
|
546
|
+
"alike — silently read `Dynamic[top]` instead of resolving, and this run is quieter " \
|
|
547
|
+
"than it should be rather than cleaner. Two signature sources declare the same " \
|
|
548
|
+
"member; remove the duplicate declaration (`rbs validate`) to restore type coverage.",
|
|
549
|
+
severity: :warning,
|
|
550
|
+
rule: "rbs.coverage.definition-build-failed",
|
|
551
|
+
source_family: :builtin
|
|
552
|
+
)
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
# `[class_name, error_class, member, buffers]`. The member is nil for the error classes that carry no
|
|
556
|
+
# name at all (`RecursiveAncestorError`), and the clause then names the error class alone rather than
|
|
557
|
+
# inventing a member.
|
|
558
|
+
def first_failure_clause(failure)
|
|
559
|
+
_, error_class, member, = failure
|
|
560
|
+
return " First failure: #{error_class}." if member.nil? || member.empty?
|
|
561
|
+
|
|
562
|
+
" First failure: #{error_class} on `#{member}`."
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
# Identical on a cache HIT: the ADR-54 env cache drops location POSITIONS but keeps each buffer's
|
|
566
|
+
# NAME, so a warm run names the same files a cold one does. Where a name is absent anyway, the
|
|
567
|
+
# reconstructed {RbsLoader::CACHED_LOCATION_BUFFER_NAME} sentinel is filtered out and the clause is
|
|
568
|
+
# omitted, rather than naming `<cached>` as if it were a path.
|
|
569
|
+
def conflicting_files_clause(files, sample_size)
|
|
570
|
+
return "" if files.empty?
|
|
571
|
+
|
|
572
|
+
" Conflicting signature file(s): #{sampled(files, sample_size)}."
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
# "a, b, c, and N more" — the sampling shape every `rbs.coverage.*` message above uses.
|
|
576
|
+
def sampled(names, sample_size)
|
|
577
|
+
sample = names.first(sample_size)
|
|
578
|
+
suffix = names.size > sample_size ? ", and #{names.size - sample_size} more" : ""
|
|
579
|
+
"#{sample.join(', ')}#{suffix}"
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
# Issue #784 — one `:error` row per run, unlike its two `:warning` `rbs.coverage.*` siblings above.
|
|
583
|
+
# Those two are typically a collision between the user's OWN `sig/` and Rigor's bundled RBS, so an
|
|
584
|
+
# `:error` default would let a Rigor release turn a green project red with zero user change (ADR-5
|
|
585
|
+
# / AGENTS.md § FP discipline) — the reason both stay `:warning` by default. This row has no such
|
|
586
|
+
# neighbour: post-#783 the scan itself raising is an ANALYZER defect, never something a user's
|
|
587
|
+
# `sig/` could trigger on its own, so there is no green project this could newly redden. And the
|
|
588
|
+
# run was already non-zero before this row existed — issue #784's seam is what stopped the raise
|
|
589
|
+
# from reaching every file as N identical `internal analyzer error` rows in the first place, and
|
|
590
|
+
# THAT per-file rescue is what `Result#success?` was already reading as a failure; this row only
|
|
591
|
+
# makes the reason legible.
|
|
592
|
+
#
|
|
593
|
+
# One row per RUN, not per file: the scan is one build over the whole `signature_paths:` overlay
|
|
594
|
+
# (memoised — see {Environment#hkt_registry}), so every file that would have demanded it hit the
|
|
595
|
+
# exact same failure, and a row per file would say the same thing N times.
|
|
596
|
+
#
|
|
597
|
+
# `:rbs_build` (via {CrashSignature::RBS_BUILD_FAILURE_RULES}), not `:check_rule`: the analysis ran
|
|
598
|
+
# to completion over a DEGRADED type universe — every rule still fired, unlike `:check_rule`'s
|
|
599
|
+
# whole-file replacement — so a consumer gating on {CrashSignature.discards_file_analysis?} must
|
|
600
|
+
# keep reading this run's diagnostics rather than refuse it as a crash.
|
|
601
|
+
def build_rbs_hkt_scan_failed_diagnostic(failure)
|
|
602
|
+
error_class, first_line, frame, stage = failure
|
|
603
|
+
relative_frame = CrashSignature.relativize_frame(frame)
|
|
604
|
+
frame_clause = relative_frame ? " at #{relative_frame}" : ""
|
|
605
|
+
raised = "(#{error_class}): #{first_line}#{frame_clause}."
|
|
606
|
+
Diagnostic.new(
|
|
607
|
+
path: ".rigor.yml",
|
|
608
|
+
line: 1,
|
|
609
|
+
column: 1,
|
|
610
|
+
message: stage == :overlay ? hkt_overlay_failed_message(raised) : hkt_scan_failed_message(raised),
|
|
611
|
+
severity: :error,
|
|
612
|
+
rule: "rbs.coverage.hkt-scan-failed",
|
|
613
|
+
source_family: :builtin
|
|
614
|
+
)
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
def hkt_scan_failed_message(raised)
|
|
618
|
+
"The implicit HKT scan over RBS `type` aliases raised #{raised} Rigor fell back to the bundled " \
|
|
619
|
+
"and plugin HKT registrations, so a recursive `type` alias in your `.rbs` or an installed " \
|
|
620
|
+
"`rbs collection` no longer registers as a type constructor and reads its bound " \
|
|
621
|
+
"(`Dynamic[top]`) instead — this run is quieter than it should be, not cleaner. " \
|
|
622
|
+
"This is an analyzer defect, not a problem with your signatures; please report it " \
|
|
623
|
+
"with the message above."
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
# Issue #791 — the overlay stage of the same build, worded for the plugin it came from. The scan
|
|
627
|
+
# wording would send a user to their `.rbs` for a defect that is not there: what failed is the
|
|
628
|
+
# aggregation of the loaded plugins' manifest-declared HKT entries, and the message names the
|
|
629
|
+
# plugin whenever the raise was attributable to one (`Plugin::Registry#hkt_overlay_registry` puts
|
|
630
|
+
# the id in the message it re-raises). The degradation is narrower than the scan's, so the fallback
|
|
631
|
+
# sentence differs too: only the plugin entries are missing, and the user's own `.rbs` scan still
|
|
632
|
+
# ran on top of the bundled registrations.
|
|
633
|
+
def hkt_overlay_failed_message(raised)
|
|
634
|
+
"Building the plugin HKT overlay raised #{raised} Rigor skipped every plugin-declared HKT " \
|
|
635
|
+
"registration and analysed with the bundled ones plus your own `.rbs` overlay, so a type " \
|
|
636
|
+
"constructor a plugin declares reads its bound (`Dynamic[top]`) instead — this run is " \
|
|
637
|
+
"quieter than it should be, not cleaner. This is a defect in the named plugin or in Rigor, " \
|
|
638
|
+
"not a problem with your signatures; report it with the message above, or remove the plugin " \
|
|
639
|
+
"from `plugins:` to analyse without it."
|
|
640
|
+
end
|
|
641
|
+
|
|
465
642
|
# The absolute path is what the loader records; the user thinks in project-relative terms.
|
|
466
643
|
def relative_signature_path(path)
|
|
467
644
|
root = "#{Dir.pwd}#{File::SEPARATOR}"
|
|
@@ -515,16 +692,19 @@ module Rigor
|
|
|
515
692
|
# enable.
|
|
516
693
|
# - `dynamic.shape.lossy-projection` for every shape-projection type function (`pick_of`, …) applied
|
|
517
694
|
# to a carrier that loses precision (anything other than `HashShape` / `Tuple`).
|
|
695
|
+
# - `dynamic.rbs-extended.hkt-directive-invalid` for every malformed ADR-20 `rigor:v1:hkt_register` /
|
|
696
|
+
# `rigor:v1:hkt_define` the directive parser declined (issue #785).
|
|
518
697
|
#
|
|
519
|
-
#
|
|
520
|
-
# column
|
|
521
|
-
#
|
|
698
|
+
# All three are authored `:info`; the severity profile re-stamps them per project taste. Every stream
|
|
699
|
+
# carries its `(path, line, column)` already flattened off the annotation's `RBS::Location`, because
|
|
700
|
+
# all three cross the pool drain channel (see {RbsExtended::Reporter}); an entry with no position
|
|
701
|
+
# falls back to `.rigor.yml`-style file-level attribution.
|
|
522
702
|
def rbs_extended_reporter_diagnostics
|
|
523
703
|
return [] if @rbs_extended_reporter.empty?
|
|
524
704
|
|
|
525
705
|
unresolved = @rbs_extended_reporter.unresolved_payloads.map do |entry|
|
|
526
|
-
|
|
527
|
-
entry
|
|
706
|
+
build_positioned_reporter_diagnostic(
|
|
707
|
+
entry,
|
|
528
708
|
rule: "dynamic.rbs-extended.unresolved",
|
|
529
709
|
message: "`RBS::Extended` directive payload could not be resolved: " \
|
|
530
710
|
"#{entry.payload.inspect}. Check for typos or enable a plugin " \
|
|
@@ -533,8 +713,8 @@ module Rigor
|
|
|
533
713
|
end
|
|
534
714
|
|
|
535
715
|
lossy = @rbs_extended_reporter.lossy_projections.map do |entry|
|
|
536
|
-
|
|
537
|
-
entry
|
|
716
|
+
build_positioned_reporter_diagnostic(
|
|
717
|
+
entry,
|
|
538
718
|
rule: "dynamic.shape.lossy-projection",
|
|
539
719
|
message: "Shape projection `#{entry.head}` applied to a carrier without a " \
|
|
540
720
|
"literal shape; the projection degrades to the input type. Author " \
|
|
@@ -542,7 +722,22 @@ module Rigor
|
|
|
542
722
|
)
|
|
543
723
|
end
|
|
544
724
|
|
|
545
|
-
unresolved + lossy
|
|
725
|
+
unresolved + lossy + hkt_directive_diagnostics
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
# Issue #785 — one row per declined HKT directive. The consequence sentence is the point: the parser
|
|
729
|
+
# is fail-soft, so nothing else in the run tells the author that the constructor they registered is
|
|
730
|
+
# not there and that every `App[…]` naming it silently reads its bound.
|
|
731
|
+
def hkt_directive_diagnostics
|
|
732
|
+
@rbs_extended_reporter.hkt_directive_errors.map do |entry|
|
|
733
|
+
build_positioned_reporter_diagnostic(
|
|
734
|
+
entry,
|
|
735
|
+
rule: "dynamic.rbs-extended.hkt-directive-invalid",
|
|
736
|
+
message: "`RBS::Extended` HKT directive was declined: #{entry.message}. The type " \
|
|
737
|
+
"constructor stays unregistered, so an `App[...]` carrier naming it reads " \
|
|
738
|
+
"its bound (`Dynamic[top]`) instead of the type function."
|
|
739
|
+
)
|
|
740
|
+
end
|
|
546
741
|
end
|
|
547
742
|
|
|
548
743
|
# ADR-32 WD6 — drains the per-run {Plugin::SourceRbsSynthesisReporter} into
|
|
@@ -624,6 +819,20 @@ module Rigor
|
|
|
624
819
|
)
|
|
625
820
|
end
|
|
626
821
|
|
|
822
|
+
# The {RbsExtended::Reporter} form of the builder above: its three streams carry the position as
|
|
823
|
+
# `(path, line, column)` primitives rather than as the `RBS::Location` a conformance record holds,
|
|
824
|
+
# because they cross the pool drain channel (#785, #805). A missing component falls back exactly as
|
|
825
|
+
# {#location_fields} does for a missing location.
|
|
826
|
+
def build_positioned_reporter_diagnostic(entry, rule:, message:)
|
|
827
|
+
path = entry.path.to_s
|
|
828
|
+
Diagnostic.new(
|
|
829
|
+
path: path.empty? ? ".rigor.yml" : path,
|
|
830
|
+
line: entry.line || 1,
|
|
831
|
+
column: entry.column || 1,
|
|
832
|
+
message: message, severity: :info, rule: rule, source_family: :builtin
|
|
833
|
+
)
|
|
834
|
+
end
|
|
835
|
+
|
|
627
836
|
def location_fields(source_location)
|
|
628
837
|
return [".rigor.yml", 1, 1] if source_location.nil?
|
|
629
838
|
|
|
@@ -684,6 +893,14 @@ module Rigor
|
|
|
684
893
|
@env_build_failure_snapshot_reader.call
|
|
685
894
|
end
|
|
686
895
|
|
|
896
|
+
def definition_build_failures_snapshot
|
|
897
|
+
@definition_build_failures_snapshot_reader.call
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
def hkt_scan_failure_snapshot
|
|
901
|
+
@hkt_scan_failure_snapshot_reader.call
|
|
902
|
+
end
|
|
903
|
+
|
|
687
904
|
def conformance_results_snapshot
|
|
688
905
|
@conformance_results_snapshot_reader.call
|
|
689
906
|
end
|