rigortype 0.3.9 → 0.4.0
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 +2 -2
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +127 -4
- data/docs/handbook/03-narrowing.md +95 -10
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- data/docs/handbook/07-rbs-and-extended.md +16 -11
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +454 -13
- data/docs/manual/02-cli-reference.md +63 -2
- data/docs/manual/03-configuration.md +7 -0
- data/docs/manual/04-diagnostics.md +4 -0
- data/docs/manual/07-plugins.md +1 -1
- data/docs/manual/10-mcp-server.md +3 -2
- data/docs/manual/16-rbs-extended-annotations.md +40 -7
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +243 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +110 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +11 -5
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +212 -25
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +1 -1
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -3
- data/lib/rigor/analysis/check_rules/rule_ids.rb +20 -5
- data/lib/rigor/analysis/check_rules/rule_walk.rb +2 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +36 -2
- data/lib/rigor/analysis/check_rules.rb +520 -49
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- data/lib/rigor/analysis/fact_store.rb +9 -0
- data/lib/rigor/analysis/incremental.rb +26 -0
- data/lib/rigor/analysis/incremental_session.rb +36 -4
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/plugin_roots.rb +0 -1
- data/lib/rigor/analysis/reachability/scan_cache.rb +1 -0
- data/lib/rigor/analysis/rule_catalog.rb +127 -0
- data/lib/rigor/analysis/run_cache_key.rb +20 -11
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +167 -11
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -4
- data/lib/rigor/analysis/runner/pool_coordinator.rb +107 -15
- data/lib/rigor/analysis/runner/project_pre_passes.rb +26 -7
- data/lib/rigor/analysis/runner.rb +278 -20
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +53 -10
- data/lib/rigor/bleeding_edge.rb +0 -2
- data/lib/rigor/builtins/hkt_builtins.rb +1 -0
- data/lib/rigor/builtins/imported_refinements.rb +4 -0
- data/lib/rigor/builtins/regex_refinement.rb +17 -9
- data/lib/rigor/builtins/static_return_refinements.rb +2 -0
- data/lib/rigor/cache/descriptor.rb +6 -1
- data/lib/rigor/cache/engine_source.rb +29 -1
- data/lib/rigor/cache/incremental_snapshot.rb +33 -1
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- data/lib/rigor/cache/rbs_descriptor.rb +37 -7
- data/lib/rigor/cache/store.rb +0 -1
- data/lib/rigor/ci_detector.rb +1 -0
- data/lib/rigor/cli/doc_links.rb +1 -1
- data/lib/rigor/cli/docs_command.rb +4 -4
- data/lib/rigor/cli/plugin_command.rb +3 -3
- data/lib/rigor/cli/prism_colorizer.rb +0 -1
- data/lib/rigor/cli/sig_gen_command.rb +210 -29
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +0 -1
- data/lib/rigor/cli/type_of_command.rb +19 -5
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- data/lib/rigor/cli.rb +21 -3
- data/lib/rigor/configuration/severity_profile.rb +19 -3
- data/lib/rigor/configuration.rb +66 -3
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +11 -2
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +9 -2
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/effect_table.rb +11 -3
- data/lib/rigor/effects/envelope_check.rb +1 -1
- data/lib/rigor/effects/envelope_index.rb +15 -0
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/identity.rb +16 -0
- data/lib/rigor/effects/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +21 -0
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +43 -31
- data/lib/rigor/effects/propagator.rb +295 -16
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +121 -72
- data/lib/rigor/effects/signature_sources.rb +1 -1
- data/lib/rigor/effects/snapshot.rb +2 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +385 -30
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/lockfile_resolver.rb +17 -0
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- data/lib/rigor/environment/rbs_loader.rb +399 -133
- data/lib/rigor/environment.rb +103 -38
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +139 -9
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +73 -27
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +2 -1
- data/lib/rigor/inference/budget_trace.rb +2 -1
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +387 -15
- data/lib/rigor/inference/closure_escape_analyzer.rb +157 -13
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/element_read_widening.rb +22 -10
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +1532 -496
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/index_write_widening.rb +16 -3
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +167 -17
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +85 -24
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +4 -0
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +113 -73
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +881 -38
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +128 -53
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +214 -13
- data/lib/rigor/inference/method_parameter_binder.rb +8 -3
- data/lib/rigor/inference/multi_target_binder.rb +340 -52
- data/lib/rigor/inference/mutation_rejoin.rb +4 -1
- data/lib/rigor/inference/mutation_widening.rb +70 -48
- data/lib/rigor/inference/narrowing.rb +540 -120
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +152 -9
- data/lib/rigor/inference/parameter_inference_collector.rb +3 -2
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +7 -2
- data/lib/rigor/inference/project_patched_scanner.rb +7 -3
- data/lib/rigor/inference/receiver_alias.rb +90 -1
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +15 -11
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +4615 -551
- data/lib/rigor/inference/statement_evaluator.rb +3176 -490
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +44 -7
- data/lib/rigor/inference/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- data/lib/rigor/language_server/debouncer.rb +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +3 -2
- data/lib/rigor/language_server/hover_renderer.rb +3 -3
- data/lib/rigor/language_server/project_context.rb +5 -3
- data/lib/rigor/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +168 -5
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +1 -1
- data/lib/rigor/plugin/effect_attribution.rb +58 -4
- data/lib/rigor/plugin/loader.rb +2 -1
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- data/lib/rigor/plugin/manifest.rb +71 -10
- data/lib/rigor/plugin/registry.rb +35 -1
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +9 -3
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/protection/discovery_seed.rb +3 -1
- data/lib/rigor/protection/kill_signature.rb +0 -1
- data/lib/rigor/protection/mutation_cache.rb +1 -2
- data/lib/rigor/rbs_extended.rb +27 -0
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +19 -6
- data/lib/rigor/reflection.rb +72 -105
- data/lib/rigor/scope/discovery_index.rb +135 -2
- data/lib/rigor/scope.rb +859 -49
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +558 -31
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- data/lib/rigor/sig_gen/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +1 -1
- data/lib/rigor/sig_gen/renderer.rb +124 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +44 -1
- data/lib/rigor/sig_gen/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +166 -35
- data/lib/rigor/sig_gen.rb +3 -0
- data/lib/rigor/signature_path_audit.rb +1 -1
- data/lib/rigor/source/node_walker.rb +0 -3
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/type/combinator.rb +88 -12
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/hash_shape.rb +1 -1
- data/lib/rigor/type/refined.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +9 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +13 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +239 -4
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +9 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +380 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +281 -35
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +25 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +171 -5
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +2 -0
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +72 -2
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +11 -7
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +35 -37
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +1 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +9 -17
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +217 -36
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +9 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +0 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +46 -1
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +12 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +6 -4
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +1 -1
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +50 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +7 -6
- data/sig/rigor/scope.rbs +135 -20
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -7
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +6 -0
- data/sig/rigor.rbs +38 -20
- data/skills/rigor-ask/SKILL.md +8 -5
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +12 -25
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +9 -7
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +33 -8
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +4 -6
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +12 -8
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +0 -3
- data/skills/rigor-unused-adjudicate/SKILL.md +4 -2
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +108 -1
|
@@ -5,9 +5,11 @@ require "prism"
|
|
|
5
5
|
require_relative "../type"
|
|
6
6
|
require_relative "../source/node_children"
|
|
7
7
|
require_relative "content_join"
|
|
8
|
+
require_relative "hash_lookup_mutation"
|
|
8
9
|
require_relative "mutation_rejoin"
|
|
9
10
|
require_relative "receiver_alias"
|
|
10
11
|
require_relative "refinement_mutation"
|
|
12
|
+
require_relative "rewrite_mutation"
|
|
11
13
|
require_relative "string_mutation"
|
|
12
14
|
|
|
13
15
|
module Rigor
|
|
@@ -52,6 +54,8 @@ module Rigor
|
|
|
52
54
|
#
|
|
53
55
|
# - `arr.<mutator>(...)` where `arr` is a local variable.
|
|
54
56
|
# - `@arr.<mutator>(...)` where `@arr` is an instance variable.
|
|
57
|
+
# - `@@arr.<mutator>(...)` / `$arr.<mutator>(...)` where the receiver is a class variable or global, and
|
|
58
|
+
# `it.<mutator>(...)` on the Ruby 3.4 `it` parameter ({ReceiverAlias.mutated_reads}).
|
|
55
59
|
# - a receiver that *selects* among such variables rather than naming one —
|
|
56
60
|
# `(kind == :required ? required : optional)[key] = info`, an `if`/`else`, `||` / `&&`. Every
|
|
57
61
|
# variable the expression can evaluate to is a possible mutation target, so every one widens
|
|
@@ -89,19 +93,21 @@ module Rigor
|
|
|
89
93
|
].to_set.freeze
|
|
90
94
|
|
|
91
95
|
# Hash mutators that invalidate a `HashShape` carrier. Same principle as `ARRAY_MUTATORS`:
|
|
92
|
-
# only the receiver-mutating methods are listed.
|
|
96
|
+
# only the receiver-mutating methods are listed. A name both classes define is listed in
|
|
97
|
+
# both tables — being in `ARRAY_MUTATORS` does not put it here, and `shift`'s absence let
|
|
98
|
+
# `k = { a: 1 }; k.shift` keep the literal shape of a hash that is empty at runtime.
|
|
93
99
|
HASH_MUTATORS = %i[
|
|
94
100
|
[]= store
|
|
95
|
-
delete delete_if reject! select! filter! keep_if
|
|
101
|
+
shift delete delete_if reject! select! filter! keep_if
|
|
96
102
|
clear compact! merge! update transform_keys! transform_values!
|
|
97
103
|
replace
|
|
98
104
|
].to_set.freeze
|
|
99
105
|
|
|
100
106
|
# Every method name {#widen_for_mutator} responds to — the one set a body scan asks "could an
|
|
101
107
|
# in-place call on this name change its binding?" against (issue #587: the block-return
|
|
102
|
-
# threading gate). Derived from the
|
|
103
|
-
#
|
|
104
|
-
SHAPE_MUTATORS = (ARRAY_MUTATORS | HASH_MUTATORS | StringMutation::MUTATORS).freeze
|
|
108
|
+
# threading gate). Derived from the tables rather than spelled out, so the scan and the
|
|
109
|
+
# widening it predicts cannot drift apart.
|
|
110
|
+
SHAPE_MUTATORS = (ARRAY_MUTATORS | HASH_MUTATORS | HashLookupMutation::MUTATORS | StringMutation::MUTATORS).freeze
|
|
105
111
|
|
|
106
112
|
# Methods that return the receiver (or a shallow copy) and cannot mutate it. They must not
|
|
107
113
|
# trigger widening or any other receiver-fact invalidation. The list is intentionally
|
|
@@ -113,9 +119,7 @@ module Rigor
|
|
|
113
119
|
|
|
114
120
|
# True when `method_name` is a pure self-returner that must
|
|
115
121
|
# not invalidate the receiver's facts.
|
|
116
|
-
def pure_self_returner?(method_name)
|
|
117
|
-
PURE_SELF_RETURNERS.include?(method_name)
|
|
118
|
-
end
|
|
122
|
+
def pure_self_returner?(method_name) = PURE_SELF_RETURNERS.include?(method_name)
|
|
119
123
|
|
|
120
124
|
# Returns a scope with the call's receiver widened, for every variable the receiver expression
|
|
121
125
|
# can evaluate to ({ReceiverAlias.candidates}) whose current binding is a literal-shape carrier
|
|
@@ -141,13 +145,9 @@ module Rigor
|
|
|
141
145
|
def joinable_receiver?(receiver, scope)
|
|
142
146
|
return false if receiver.nil?
|
|
143
147
|
|
|
144
|
-
ReceiverAlias.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
when Prism::LocalVariableReadNode then scope.local(read.name)
|
|
148
|
-
when Prism::InstanceVariableReadNode then scope.ivar(read.name)
|
|
149
|
-
end
|
|
150
|
-
shape_carrier?(current)
|
|
148
|
+
ReceiverAlias.mutated_reads(receiver).any? do |read|
|
|
149
|
+
getter, = ALIAS_ACCESSORS[read.class]
|
|
150
|
+
getter && shape_carrier?(scope.public_send(getter, ReceiverAlias.read_name(read)))
|
|
151
151
|
end
|
|
152
152
|
end
|
|
153
153
|
|
|
@@ -172,11 +172,12 @@ module Rigor
|
|
|
172
172
|
end
|
|
173
173
|
end
|
|
174
174
|
|
|
175
|
-
# Widens every variable `receiver` can evaluate to, against `method_name`'s
|
|
175
|
+
# Widens every variable `receiver` can evaluate to ({ReceiverAlias.mutated_reads}), against `method_name`'s
|
|
176
|
+
# mutator table.
|
|
176
177
|
def widen_receiver_aliases(receiver, method_name, current_scope, arg_types: NO_ARG_TYPES)
|
|
177
178
|
return current_scope if receiver.nil?
|
|
178
179
|
|
|
179
|
-
ReceiverAlias.
|
|
180
|
+
ReceiverAlias.mutated_reads(receiver).reduce(current_scope) do |acc, read|
|
|
180
181
|
widen_alias_read(method_name, read, acc, arg_types: arg_types)
|
|
181
182
|
end
|
|
182
183
|
end
|
|
@@ -231,9 +232,10 @@ module Rigor
|
|
|
231
232
|
return scope if receiver.nil?
|
|
232
233
|
|
|
233
234
|
ReceiverAlias.candidates(receiver).reduce(scope) do |acc, read|
|
|
234
|
-
# A block-local read (`depth == 0`) is not a
|
|
235
|
-
# name against the OUTER scope would hit an
|
|
236
|
-
|
|
235
|
+
# A block-local read ({ReceiverAlias.block_local?}: a `depth == 0` local, or `it`) is not a
|
|
236
|
+
# capture of the outer scope, so widening its name against the OUTER scope would hit an
|
|
237
|
+
# unrelated same-named binding.
|
|
238
|
+
next acc if ReceiverAlias.block_local?(read)
|
|
237
239
|
|
|
238
240
|
# `values: :keep` — this is the block-capture path, and the slice-C content join that runs
|
|
239
241
|
# after it re-adds the appended values' types onto the widened seed, so the seed's own value
|
|
@@ -243,24 +245,30 @@ module Rigor
|
|
|
243
245
|
end
|
|
244
246
|
end
|
|
245
247
|
|
|
246
|
-
# The
|
|
247
|
-
# of one table rather than written
|
|
248
|
-
# kind of binding and left on
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
248
|
+
# The arms per kind of binding differ only in which pair of `Scope` accessors they use, so they are read out
|
|
249
|
+
# of one table rather than written once per kind: a carrier the widening responds to must not be widened on
|
|
250
|
+
# one kind of binding and left on another. `$g << x; $g == "k"` folded always-truthy on a `$g` Ruby holds
|
|
251
|
+
# as `"kx"` while the table had only the local and ivar rows. A local rebinds through `with_mutated_local`: the
|
|
252
|
+
# mutated binding names the same object, so it keeps the marks a write drops (issue #1287).
|
|
253
|
+
ALIAS_ACCESSORS = Ractor.make_shareable({
|
|
254
|
+
Prism::LocalVariableReadNode => %i[local with_mutated_local],
|
|
255
|
+
Prism::ItLocalVariableReadNode => %i[local with_mutated_local],
|
|
256
|
+
Prism::InstanceVariableReadNode => %i[ivar with_ivar],
|
|
257
|
+
Prism::ClassVariableReadNode => %i[cvar with_cvar],
|
|
258
|
+
Prism::GlobalVariableReadNode => %i[global with_global]
|
|
259
|
+
})
|
|
253
260
|
private_constant :ALIAS_ACCESSORS
|
|
254
261
|
|
|
255
262
|
def widen_alias_read(method_name, read, scope, values: :widen, arg_types: NO_ARG_TYPES)
|
|
256
263
|
getter, builder = ALIAS_ACCESSORS[read.class]
|
|
257
264
|
return scope if getter.nil?
|
|
258
265
|
|
|
259
|
-
|
|
266
|
+
name = ReceiverAlias.read_name(read)
|
|
267
|
+
current = scope.public_send(getter, name)
|
|
260
268
|
widened = widen_for_mutator(current, method_name, values: values, arg_types: arg_types)
|
|
261
269
|
return scope if widened.nil?
|
|
262
270
|
|
|
263
|
-
MutationRejoin.rebind(scope, builder,
|
|
271
|
+
MutationRejoin.rebind(scope, builder, name, widened, pre_state: current, kind: getter)
|
|
264
272
|
end
|
|
265
273
|
|
|
266
274
|
# Mutators that can land a NEW value in an EXISTING slot, falsifying that slot's value pinning
|
|
@@ -277,6 +285,7 @@ module Rigor
|
|
|
277
285
|
# nominal, whose element set is a claim this seam may not grow — see {MutationRejoin.regrowable_carrier?}).
|
|
278
286
|
def widen_for_mutator(type, method_name, values: :widen, arg_types: NO_ARG_TYPES)
|
|
279
287
|
values = :keep unless VALUE_REWRITING_MUTATORS.include?(method_name)
|
|
288
|
+
values = RewriteMutation.values_mode(type, method_name, values)
|
|
280
289
|
|
|
281
290
|
return nil if type.nil?
|
|
282
291
|
|
|
@@ -287,7 +296,7 @@ module Rigor
|
|
|
287
296
|
|
|
288
297
|
join_added_elements(widen_tuple(type, values: values), method_name, arg_types, type.elements)
|
|
289
298
|
when Type::HashShape
|
|
290
|
-
return
|
|
299
|
+
return HashLookupMutation.widen_shape(type, method_name) unless HASH_MUTATORS.include?(method_name)
|
|
291
300
|
|
|
292
301
|
join_added_pairs(widen_hash_shape(type, values: values), method_name, arg_types,
|
|
293
302
|
ContentJoin.hash_shape_key_values(type))
|
|
@@ -330,10 +339,12 @@ module Rigor
|
|
|
330
339
|
end
|
|
331
340
|
|
|
332
341
|
# True when the mutator's own class stands for `member` — the absorbed side of
|
|
333
|
-
# {ContentJoin.array_residue} / {ContentJoin.hash_residue}, whichever table names the call.
|
|
342
|
+
# {ContentJoin.array_residue} / {ContentJoin.hash_residue}, whichever table names the call. A
|
|
343
|
+
# {HashLookupMutation} name stands for a Hash member as a Hash mutator does.
|
|
334
344
|
def mutation_carrier?(member, method_name)
|
|
335
345
|
(ARRAY_MUTATORS.include?(method_name) && ContentJoin.array_residue(member).empty?) ||
|
|
336
|
-
(HASH_MUTATORS.include?(method_name)
|
|
346
|
+
((HASH_MUTATORS.include?(method_name) || HashLookupMutation::MUTATORS.include?(method_name)) &&
|
|
347
|
+
ContentJoin.hash_residue(member).empty?) ||
|
|
337
348
|
(StringMutation::MUTATORS.include?(method_name) && StringMutation.constant?(member))
|
|
338
349
|
end
|
|
339
350
|
|
|
@@ -360,7 +371,11 @@ module Rigor
|
|
|
360
371
|
# **The join records what it saw; it never CLOSES the parameter.** That is
|
|
361
372
|
# {#gradual_floor}'s job, and the reason is the seam this method sits on rather than anything
|
|
362
373
|
# about Array or Hash.
|
|
374
|
+
#
|
|
375
|
+
# A mutator whose arguments do not describe what it stores ({RewriteMutation}) takes that module's gradual
|
|
376
|
+
# arm first, on every path that reaches this join: the literal arms, the refinement arm, and the re-join.
|
|
363
377
|
def join_added_elements(widened, method_name, arg_types, seed_elements)
|
|
378
|
+
widened = RewriteMutation.arm(widened, method_name)
|
|
364
379
|
return widened unless ContentJoin::ARRAY_CONTENT_ADDERS.include?(method_name)
|
|
365
380
|
|
|
366
381
|
added = value_pin_widened(ContentJoin.array_added_elements(method_name, arg_types))
|
|
@@ -395,7 +410,10 @@ module Rigor
|
|
|
395
410
|
# BLOCK path (ADR-56 slice C) on the other side: `content_writeback_block_captures` scans the
|
|
396
411
|
# whole body and joins every mutator call in it before writing back, so its evidence IS
|
|
397
412
|
# complete for that body and its precise join stays justified — `acc = []; xs.each { |x|
|
|
398
|
-
# acc.push(x) }` keeps reading `Array[Integer]`.
|
|
413
|
+
# acc.push(x) }` keeps reading `Array[Integer]`. Seeing every store is only half of that
|
|
414
|
+
# claim: a store computed from the collection's own contents (`h[k] = h[k] + 1`) is
|
|
415
|
+
# complete evidence only once it holds past the first iteration, which is why that seam
|
|
416
|
+
# iterates such a store to a fixpoint instead of typing it once (ADR-56 WD2.13).
|
|
399
417
|
#
|
|
400
418
|
# `Array[Integer | Dynamic[top]]` still does everything issue #560 needs: a union carrying
|
|
401
419
|
# `Dynamic` cannot constant-fold, so every stale always-falsey the join was written to remove
|
|
@@ -406,12 +424,17 @@ module Rigor
|
|
|
406
424
|
|
|
407
425
|
# The Hash-side twin of {#join_added_elements}: `h[k] = v` / `h.store(k, v)` join the stored
|
|
408
426
|
# key and value into the widened `Hash[K, V]` carrier, each admitted against its OWN side's
|
|
409
|
-
# seed evidence (a foreign key does not make the value gradual, or the reverse).
|
|
427
|
+
# seed evidence (a foreign key does not make the value gradual, or the reverse). {RewriteMutation}'s arm lands
|
|
428
|
+
# first, as it does in {#join_added_elements}.
|
|
410
429
|
def join_added_pairs(widened, method_name, arg_types, seed_pairs)
|
|
430
|
+
widened = RewriteMutation.arm(widened, method_name)
|
|
411
431
|
return widened unless ContentJoin::HASH_CONTENT_ADDERS.include?(method_name)
|
|
412
432
|
return widened if arg_types.size < 2
|
|
413
433
|
|
|
414
|
-
|
|
434
|
+
# A `nil` index marks a splat for the Array splice classifier; the pair seam reads
|
|
435
|
+
# `arg_types.first` as the KEY, where the splat's expansion is an unknown key rather
|
|
436
|
+
# than absent arity — it degrades to untyped, not `nil` (issue #1140).
|
|
437
|
+
added = value_pin_widened([arg_types.first || Type::Combinator.untyped, arg_types.last])
|
|
415
438
|
return widened unless added.size == 2
|
|
416
439
|
|
|
417
440
|
seed_keys, seed_values = seed_pairs
|
|
@@ -493,7 +516,7 @@ module Rigor
|
|
|
493
516
|
# here, so a refinement joins the mutator's added content on exactly the terms the `Tuple` /
|
|
494
517
|
# `HashShape` arms above do (issue #936, ADR-56 WD2.9's deferred branch).
|
|
495
518
|
def widen_difference(difference, method_name, arg_types: NO_ARG_TYPES)
|
|
496
|
-
RefinementMutation.widen(difference, method_name) do |base|
|
|
519
|
+
RefinementMutation.widen(difference, method_name, arg_types) do |base|
|
|
497
520
|
if base.class_name == "Array"
|
|
498
521
|
ARRAY_MUTATORS.include?(method_name) &&
|
|
499
522
|
join_added_elements(base, method_name, arg_types, ContentJoin.collection_element_types(base))
|
|
@@ -522,16 +545,17 @@ module Rigor
|
|
|
522
545
|
Type::Combinator.nominal_of("Array", type_args: [element_type])
|
|
523
546
|
end
|
|
524
547
|
|
|
525
|
-
# `HashShape`
|
|
526
|
-
#
|
|
527
|
-
#
|
|
528
|
-
# `
|
|
529
|
-
# `
|
|
548
|
+
# Closed `HashShape` → `Nominal[Hash, [Kunion, Vunion]]`. An empty or an open shape degrades to
|
|
549
|
+
# a fully-untyped Hash: an open shape's unseen keys may hold any value, and one {HashLookupMutation}
|
|
550
|
+
# opened reads its DEFAULT for a missing key, so a bound built from the known values alone would
|
|
551
|
+
# pin that read to one of them (`{ a: 1 }` under `default = 0` then `delete(:a)` read `h[:b]` as
|
|
552
|
+
# `1`). Values widen their pinning the same way {#widen_tuple}'s elements do (issue #560):
|
|
553
|
+
# `opts = {headers: false}` then `opts[:encoding] = v` must not keep `false` as the whole value
|
|
554
|
+
# bound — redmine's `import.rb:274` read the stored key back through it and drew a false
|
|
555
|
+
# always-falsey.
|
|
530
556
|
def widen_hash_shape(shape, values: :widen)
|
|
531
|
-
if shape.pairs.empty?
|
|
532
|
-
return Type::Combinator.nominal_of("Hash",
|
|
533
|
-
type_args: [Type::Combinator.untyped,
|
|
534
|
-
Type::Combinator.untyped])
|
|
557
|
+
if shape.pairs.empty? || shape.open?
|
|
558
|
+
return Type::Combinator.nominal_of("Hash", type_args: [Type::Combinator.untyped, Type::Combinator.untyped])
|
|
535
559
|
end
|
|
536
560
|
|
|
537
561
|
key_type = key_union_for(shape.pairs.keys)
|
|
@@ -546,9 +570,7 @@ module Rigor
|
|
|
546
570
|
# `key_union_for` is delegated rather than duplicated: {#widen_hash_shape} and
|
|
547
571
|
# `ContentJoin.hash_shape_key_values` must map a literal key set the SAME way, or a widened
|
|
548
572
|
# carrier and the join that reads it back disagree about the key parameter.
|
|
549
|
-
def key_union_for(keys)
|
|
550
|
-
ContentJoin.key_union_for(keys)
|
|
551
|
-
end
|
|
573
|
+
def key_union_for(keys) = ContentJoin.key_union_for(keys)
|
|
552
574
|
end
|
|
553
575
|
end
|
|
554
576
|
end
|