rigortype 0.4.6 → 0.4.7
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/gem_overlay/activesupport/core_ext.rbs +16 -13
- data/data/vendored_gem_sigs/bundler/bundler.rbs +1 -1
- data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +4 -3
- data/docs/handbook/01-getting-started.md +5 -2
- data/docs/handbook/11-sig-gen.md +50 -3
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/manual/02-cli-reference.md +152 -26
- data/docs/manual/03-configuration.md +36 -3
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/09-editor-integration.md +13 -2
- data/docs/manual/10-mcp-server.md +38 -2
- data/docs/manual/12-caching.md +4 -3
- data/docs/manual/plugins/rigor-actionpack.md +19 -11
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +20 -1
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +4 -4
- data/lib/rigor/analysis/check_rules/duplicate_hash_key_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +85 -13
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +3 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +0 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +1 -1
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +3 -3
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +9 -7
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +3 -4
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +3 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules.rb +124 -44
- data/lib/rigor/analysis/crash_signature.rb +2 -2
- data/lib/rigor/analysis/dependency_recorder.rb +4 -4
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +14 -3
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/index.rb +6 -8
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/edit_replay.rb +93 -6
- data/lib/rigor/analysis/fact_store.rb +3 -3
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +2 -2
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +27 -16
- data/lib/rigor/analysis/rule_catalog.rb +2 -2
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +2 -2
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -1
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +193 -93
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +1 -1
- data/lib/rigor/analysis/runner/pool_coordinator.rb +147 -323
- data/lib/rigor/analysis/runner/project_pre_passes.rb +3 -3
- data/lib/rigor/analysis/runner/run_level_facts.rb +304 -0
- data/lib/rigor/analysis/runner/run_snapshots.rb +44 -54
- data/lib/rigor/analysis/runner/worker_payload.rb +36 -0
- data/lib/rigor/analysis/runner.rb +77 -71
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +1 -1
- data/lib/rigor/analysis/template_unit_positions.rb +2 -3
- data/lib/rigor/analysis/template_units.rb +9 -1
- data/lib/rigor/analysis/worker_session.rb +24 -31
- data/lib/rigor/bleeding_edge.rb +3 -6
- data/lib/rigor/builtins/imported_refinements.rb +6 -8
- data/lib/rigor/builtins/predefined_constant_refinements.rb +1 -1
- data/lib/rigor/builtins/regex_refinement.rb +4 -6
- data/lib/rigor/cache/descriptor.rb +6 -5
- data/lib/rigor/cache/incremental_snapshot.rb +31 -12
- data/lib/rigor/cache/rbs_cache_producer.rb +2 -2
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +1 -1
- data/lib/rigor/cache/rbs_class_type_param_names.rb +2 -2
- data/lib/rigor/cache/rbs_constant_table.rb +1 -1
- data/lib/rigor/cache/rbs_descriptor.rb +54 -3
- data/lib/rigor/cache/rbs_environment.rb +4 -1
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +2 -2
- data/lib/rigor/cache/rbs_known_class_names.rb +1 -1
- data/lib/rigor/cache/store.rb +11 -10
- data/lib/rigor/ci_detector.rb +1 -1
- data/lib/rigor/cli/annotate_command.rb +24 -19
- data/lib/rigor/cli/baseline_command.rb +145 -55
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +108 -102
- data/lib/rigor/cli/check_runner_factory.rb +2 -2
- data/lib/rigor/cli/command.rb +15 -1
- data/lib/rigor/cli/coverage_command.rb +21 -8
- data/lib/rigor/cli/coverage_mutation.rb +5 -7
- data/lib/rigor/cli/coverage_renderer.rb +2 -1
- data/lib/rigor/cli/coverage_scan.rb +3 -5
- data/lib/rigor/cli/diff_command.rb +25 -20
- data/lib/rigor/cli/docs_command.rb +1 -2
- data/lib/rigor/cli/doctor_command.rb +12 -12
- data/lib/rigor/cli/effects_command.rb +50 -40
- data/lib/rigor/cli/effects_diff_renderer.rb +18 -17
- data/lib/rigor/cli/effects_explain_renderer.rb +13 -12
- data/lib/rigor/cli/effects_renderer.rb +2 -1
- data/lib/rigor/cli/effects_snapshot_command.rb +18 -17
- data/lib/rigor/cli/explain_command.rb +18 -8
- data/lib/rigor/cli/fused_protection_renderer.rb +2 -1
- data/lib/rigor/cli/json_document.rb +41 -0
- data/lib/rigor/cli/lens_command.rb +12 -8
- data/lib/rigor/cli/lsp_command.rb +250 -23
- data/lib/rigor/cli/mcp_command.rb +12 -7
- data/lib/rigor/cli/mutation_fork_scan.rb +1 -1
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -2
- data/lib/rigor/cli/options.rb +40 -1
- data/lib/rigor/cli/plugin_command.rb +93 -46
- data/lib/rigor/cli/plugins_command.rb +17 -18
- data/lib/rigor/cli/plugins_renderer.rb +10 -6
- data/lib/rigor/cli/protection_fork_scan.rb +2 -2
- data/lib/rigor/cli/protection_renderer.rb +2 -1
- data/lib/rigor/cli/show_bleedingedge_command.rb +21 -15
- data/lib/rigor/cli/sig_gen_command.rb +84 -27
- data/lib/rigor/cli/skill_command.rb +32 -3
- data/lib/rigor/cli/skill_deep_probe.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +1 -1
- data/lib/rigor/cli/trace_command.rb +14 -9
- data/lib/rigor/cli/triage_command.rb +10 -11
- data/lib/rigor/cli/triage_renderer.rb +2 -1
- data/lib/rigor/cli/type_of_command.rb +16 -11
- data/lib/rigor/cli/type_of_project_scope.rb +1 -4
- data/lib/rigor/cli/type_of_renderer.rb +4 -1
- data/lib/rigor/cli/type_scan_command.rb +14 -9
- data/lib/rigor/cli/type_scan_renderer.rb +2 -1
- data/lib/rigor/cli/unused_command.rb +27 -17
- data/lib/rigor/cli/upgrade_command.rb +5 -0
- data/lib/rigor/cli.rb +209 -54
- data/lib/rigor/config_audit.rb +1 -1
- data/lib/rigor/configuration/severity_profile.rb +5 -5
- data/lib/rigor/configuration.rb +72 -30
- data/lib/rigor/effects/definition_context.rb +0 -2
- data/lib/rigor/effects/envelope.rb +1 -1
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/mutation_classifier.rb +4 -7
- data/lib/rigor/effects/propagator.rb +1 -1
- data/lib/rigor/effects/registry.rb +2 -2
- data/lib/rigor/effects/snapshot.rb +1 -1
- data/lib/rigor/effects/taint_cause.rb +0 -2
- data/lib/rigor/effects/unit_scan.rb +9 -13
- data/lib/rigor/environment/bundle_sig_discovery.rb +5 -9
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +1 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +283 -0
- data/lib/rigor/environment/gated_signature_guard.rb +1 -1
- data/lib/rigor/environment/gated_signature_plan.rb +5 -2
- data/lib/rigor/environment/lockfile_resolver.rb +28 -12
- data/lib/rigor/environment/member_consistency/comparator.rb +18 -1
- data/lib/rigor/environment/member_consistency.rb +56 -7
- data/lib/rigor/environment/missing_gem_constant_index.rb +3 -2
- data/lib/rigor/environment/project_path_gems.rb +124 -0
- data/lib/rigor/environment/rbs_hierarchy.rb +6 -15
- data/lib/rigor/environment/rbs_loader.rb +480 -67
- data/lib/rigor/environment/reflection.rb +7 -7
- data/lib/rigor/environment/required_features.rb +0 -3
- data/lib/rigor/environment/ruby_library_roots.rb +1 -1
- data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
- data/lib/rigor/environment.rb +41 -10
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +93 -32
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +178 -0
- data/lib/rigor/inference/budget_trace.rb +8 -2
- data/lib/rigor/inference/builtins/exception_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/numeric_catalog.rb +2 -5
- data/lib/rigor/inference/builtins/random_catalog.rb +2 -2
- data/lib/rigor/inference/callee_mutation_chain.rb +88 -77
- data/lib/rigor/inference/callee_write_census.rb +815 -0
- data/lib/rigor/inference/construction_escape.rb +217 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- data/lib/rigor/inference/deep_erasure.rb +39 -7
- data/lib/rigor/inference/def_handle.rb +1 -1
- data/lib/rigor/inference/def_node_resolver.rb +1 -1
- data/lib/rigor/inference/def_return_typer.rb +46 -4
- data/lib/rigor/inference/definer_resolution.rb +4 -2
- data/lib/rigor/inference/definers_index.rb +106 -0
- data/lib/rigor/inference/direct_ivar_writes.rb +300 -0
- data/lib/rigor/inference/element_read_widening.rb +49 -3
- data/lib/rigor/inference/expression_typer.rb +116 -49
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/global_write_census.rb +76 -2
- data/lib/rigor/inference/global_writer_reach.rb +260 -0
- data/lib/rigor/inference/hkt_body.rb +1 -2
- data/lib/rigor/inference/hkt_body_parser.rb +3 -5
- data/lib/rigor/inference/hkt_reducer.rb +2 -2
- data/lib/rigor/inference/hkt_registry.rb +3 -5
- data/lib/rigor/inference/indexed_narrowing.rb +4 -7
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +51 -0
- data/lib/rigor/inference/key_presence_guard.rb +2 -1
- data/lib/rigor/inference/loop_value_record.rb +8 -4
- data/lib/rigor/inference/match_rebinding/frame.rb +46 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +45 -0
- data/lib/rigor/inference/match_rebinding.rb +11 -1
- data/lib/rigor/inference/memo_audit.rb +55 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/argument_distribution.rb +40 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +3 -3
- data/lib/rigor/inference/method_dispatcher/contested_overloads.rb +89 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/no_match_fallback.rb +54 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +39 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +203 -17
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +9 -7
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +83 -20
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +0 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +50 -17
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +4 -6
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +64 -14
- data/lib/rigor/inference/module_function_state.rb +11 -1
- data/lib/rigor/inference/multi_target_binder.rb +1 -1
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +157 -27
- data/lib/rigor/inference/narrowing.rb +47 -33
- data/lib/rigor/inference/optimistic_origin.rb +1 -1
- data/lib/rigor/inference/out_buffer_mutation.rb +72 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +6 -3
- data/lib/rigor/inference/project_yielder.rb +11 -17
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +3 -1
- data/lib/rigor/inference/refined_dispatch/own_method.rb +2 -1
- data/lib/rigor/inference/remover_holder_scan.rb +233 -0
- data/lib/rigor/inference/remover_narrowing.rb +224 -0
- data/lib/rigor/inference/rewrite_mutation.rb +53 -2
- data/lib/rigor/inference/scope_indexer/certainty.rb +0 -1
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +58 -15
- data/lib/rigor/inference/scope_indexer/derived_param_value.rb +112 -0
- data/lib/rigor/inference/scope_indexer/empty_seed.rb +99 -0
- data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +135 -0
- data/lib/rigor/inference/scope_indexer.rb +137 -46
- data/lib/rigor/inference/self_call_ivar_writes.rb +84 -12
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +1 -2
- data/lib/rigor/inference/statement_evaluator.rb +2328 -138
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_scanner.rb +5 -6
- data/lib/rigor/inference/toplevel_def_census.rb +59 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -1
- data/lib/rigor/language_server/buffer_table.rb +3 -3
- data/lib/rigor/language_server/completion_provider.rb +26 -20
- data/lib/rigor/language_server/config_warning_announcer.rb +28 -0
- data/lib/rigor/language_server/diagnostic_publisher.rb +8 -3
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -2
- data/lib/rigor/language_server/hover_provider.rb +1 -7
- data/lib/rigor/language_server/hover_renderer.rb +6 -8
- data/lib/rigor/language_server/project_context.rb +39 -1
- data/lib/rigor/language_server/publish_batcher.rb +3 -4
- data/lib/rigor/language_server/selection_range_provider.rb +2 -4
- data/lib/rigor/language_server/server.rb +7 -3
- data/lib/rigor/language_server/signature_help_provider.rb +4 -4
- data/lib/rigor/lens/plugins.rb +1 -1
- data/lib/rigor/mcp/server.rb +73 -2
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +1 -1
- data/lib/rigor/plugin/loader.rb +25 -8
- data/lib/rigor/plugin/macro/heredoc_template.rb +7 -8
- data/lib/rigor/plugin/macro/trait_registry.rb +6 -9
- data/lib/rigor/plugin/manifest.rb +9 -13
- data/lib/rigor/plugin/registry.rb +3 -3
- data/lib/rigor/plugin/services.rb +2 -3
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -2
- data/lib/rigor/plugin/type_node_resolver.rb +2 -4
- data/lib/rigor/plugin.rb +6 -8
- data/lib/rigor/plugin_gap_advisory.rb +5 -1
- data/lib/rigor/project_environment.rb +16 -2
- data/lib/rigor/protection/analysis_guard.rb +1 -1
- data/lib/rigor/protection/discovery_seed.rb +44 -5
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/hkt_directives.rb +6 -10
- data/lib/rigor/rbs_extended/reporter.rb +27 -3
- data/lib/rigor/rbs_extended.rb +2 -3
- data/lib/rigor/reflection/constant_ancestors.rb +5 -3
- data/lib/rigor/rooted_glob.rb +15 -1
- data/lib/rigor/run_scoped_slots.rb +38 -0
- data/lib/rigor/runtime/jit.rb +1 -1
- data/lib/rigor/scope/discovery_index.rb +19 -6
- data/lib/rigor/scope/resolution_chain.rb +3 -1
- data/lib/rigor/scope.rb +365 -31
- data/lib/rigor/sig_gen/classification.rb +4 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +371 -58
- data/lib/rigor/sig_gen/generic_header_scan.rb +189 -0
- data/lib/rigor/sig_gen/inline_declarations.rb +2 -2
- data/lib/rigor/sig_gen/layout_index.rb +3 -3
- data/lib/rigor/sig_gen/method_candidate.rb +23 -4
- data/lib/rigor/sig_gen/observation_collector.rb +3 -5
- data/lib/rigor/sig_gen/observed_call.rb +1 -1
- data/lib/rigor/sig_gen/path_mapper.rb +6 -0
- data/lib/rigor/sig_gen/renderer.rb +15 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +15 -2
- data/lib/rigor/sig_gen/type_name_qualification.rb +69 -0
- data/lib/rigor/sig_gen/write_reporter.rb +63 -14
- data/lib/rigor/sig_gen/write_result.rb +23 -12
- data/lib/rigor/sig_gen/writer.rb +217 -37
- data/lib/rigor/type/acceptance_router.rb +2 -2
- data/lib/rigor/type/accepts_result.rb +1 -1
- data/lib/rigor/type/app.rb +4 -6
- data/lib/rigor/type/combinator.rb +9 -13
- data/lib/rigor/type/constant.rb +4 -5
- data/lib/rigor/type/hash_shape.rb +21 -40
- data/lib/rigor/type/union.rb +1 -1
- data/lib/rigor/type_node/identifier.rb +1 -2
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node/string_literal.rb +1 -2
- data/lib/rigor/type_node/symbol_literal.rb +1 -2
- data/lib/rigor/type_node/union.rb +3 -6
- data/lib/rigor/value_semantics.rb +1 -10
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +2 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +2 -3
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +38 -36
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +6 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -5
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +2 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +66 -19
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +4 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +3 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +2 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +21 -31
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +10 -16
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +2 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +0 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +5 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +3 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +7 -12
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/symbolize_keys.rb +102 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +19 -6
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +26 -13
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +3 -3
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +1 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +6 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +5 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +1 -1
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/params_shape.rb +2 -3
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -8
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +10 -18
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +0 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +0 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +4 -5
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +0 -2
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +6 -7
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +2 -4
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +2 -5
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -2
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +6 -6
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +2 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +3 -8
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +2 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -8
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +4 -11
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +2 -2
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +3 -4
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +6 -8
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +3 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +6 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +1 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +17 -21
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +3 -2
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +4 -4
- data/sig/rigor/analysis/baseline.rbs +0 -3
- data/sig/rigor/analysis/fact_store.rbs +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- data/sig/rigor/cli/diff_command.rbs +1 -1
- data/sig/rigor/cli/explain_command.rbs +1 -1
- data/sig/rigor/effects/registry.rbs +2 -2
- data/sig/rigor/inference.rbs +4 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +1 -0
- data/sig/rigor/plugin/effect_attribution.rbs +3 -3
- data/sig/rigor/plugin/effect_edge.rbs +1 -1
- data/sig/rigor/plugin/effect_entry_points.rbs +3 -3
- data/sig/rigor/plugin/io_boundary.rbs +2 -1
- data/sig/rigor/plugin/manifest.rbs +9 -9
- data/sig/rigor/plugin/protocol_contract.rbs +3 -7
- data/sig/rigor/scope.rbs +23 -3
- data/skills/rigor-plugin-author/SKILL.md +4 -4
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +5 -5
- data/skills/rigor-plugin-review/SKILL.md +3 -3
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +12 -1
- metadata +36 -3
data/lib/rigor/plugin.rb
CHANGED
|
@@ -21,14 +21,12 @@ require_relative "plugin/first_party"
|
|
|
21
21
|
module Rigor
|
|
22
22
|
module Plugin
|
|
23
23
|
@registered = {}
|
|
24
|
-
# ADR-88 WD4b — process-global map `gem name (String) => [
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
# in-process analysis (the `--verify-incremental` full-run oracle, the incremental session's subset
|
|
31
|
-
# re-analysis, the LSP's re-loads) load the same plugins the first run did.
|
|
24
|
+
# ADR-88 WD4b — process-global map `gem name (String) => [plugin id, ...]`, recorded by the loader on a gem's
|
|
25
|
+
# first `require`. A second in-process `Loader.load` of the same bare-string entry sees `require` return false
|
|
26
|
+
# and an empty newly-registered delta; the loader then recovers the ids from this memo instead of failing with
|
|
27
|
+
# "did not register any plugin". Populated by {.record_gem_registration}, read by {.ids_for_gem}. This is what
|
|
28
|
+
# lets a second in-process analysis (the `--verify-incremental` oracle, the incremental subset re-analysis,
|
|
29
|
+
# the LSP's re-loads) load the same plugins the first run did.
|
|
32
30
|
@gem_registrations = {}
|
|
33
31
|
@mutex = Mutex.new
|
|
34
32
|
|
|
@@ -26,7 +26,11 @@ module Rigor
|
|
|
26
26
|
"rails" => %w[
|
|
27
27
|
actioncable actionmailer actionpack actiontext actionview activejob activemodel
|
|
28
28
|
activerecord activestorage activesupport railties
|
|
29
|
-
].freeze
|
|
29
|
+
].freeze,
|
|
30
|
+
# `rspec` and `rspec-rails` are the same shape: a project names the umbrella and never `rspec-core`, the
|
|
31
|
+
# gem rigor-rspec targets. rspec-rails depends on the three rspec gems listed here.
|
|
32
|
+
"rspec" => %w[rspec-core rspec-expectations rspec-mocks].freeze,
|
|
33
|
+
"rspec-rails" => %w[rspec-core rspec-expectations rspec-mocks].freeze
|
|
30
34
|
}.freeze
|
|
31
35
|
|
|
32
36
|
class << self
|
|
@@ -72,6 +72,9 @@ module Rigor
|
|
|
72
72
|
required_features: features,
|
|
73
73
|
**dependency_discovery_options(configuration)
|
|
74
74
|
)
|
|
75
|
+
rescue Environment::CoreRootError
|
|
76
|
+
# Issue #2517 — an unusable selected core is the user's to fix, never a reason to type against the default.
|
|
77
|
+
raise
|
|
75
78
|
rescue StandardError
|
|
76
79
|
bare(configuration, features)
|
|
77
80
|
end
|
|
@@ -111,8 +114,15 @@ module Rigor
|
|
|
111
114
|
# The dependency-discovery axes `check` reads off the configuration, as a keyword hash. Extracted so the
|
|
112
115
|
# list lives in one place: every command that types against the project's real dependencies passes exactly
|
|
113
116
|
# these, and adding an axis to `Environment.for_project` means adding it here once.
|
|
117
|
+
#
|
|
118
|
+
# Issue #2517 — `core_root:` rides here too although it is not discovered: it is the other half of the RBS
|
|
119
|
+
# universe `check` reads off the configuration, and every site that builds one already passes this hash.
|
|
114
120
|
def dependency_discovery_options(configuration)
|
|
115
121
|
{
|
|
122
|
+
core_root: configuration.core_root,
|
|
123
|
+
paths: configuration.paths,
|
|
124
|
+
exclude_patterns: configuration.exclude_patterns,
|
|
125
|
+
exclude_base: configuration.exclude_base,
|
|
116
126
|
bundler_bundle_path: configuration.bundler_bundle_path,
|
|
117
127
|
bundler_auto_detect: configuration.bundler_auto_detect,
|
|
118
128
|
bundler_lockfile: configuration.bundler_lockfile,
|
|
@@ -166,17 +176,21 @@ module Rigor
|
|
|
166
176
|
required_features: features,
|
|
167
177
|
**dependency_discovery_options(configuration)
|
|
168
178
|
)
|
|
179
|
+
rescue Environment::CoreRootError
|
|
180
|
+
raise
|
|
169
181
|
rescue StandardError
|
|
170
182
|
minimal(configuration, features)
|
|
171
183
|
end
|
|
172
184
|
|
|
173
185
|
# The last floor: RBS core plus the project's own signature paths, which cannot fail on anything outside
|
|
174
|
-
# the project itself.
|
|
186
|
+
# the project itself. The core is still the selected one (issue #2517): a floor that dropped it would type
|
|
187
|
+
# the project against APIs its Ruby does not have.
|
|
175
188
|
def minimal(configuration, features = [])
|
|
176
189
|
Environment.for_project(
|
|
177
190
|
libraries: configuration.libraries,
|
|
178
191
|
signature_paths: configuration.signature_paths,
|
|
179
|
-
required_features: features
|
|
192
|
+
required_features: features,
|
|
193
|
+
core_root: configuration.core_root
|
|
180
194
|
)
|
|
181
195
|
end
|
|
182
196
|
end
|
|
@@ -8,7 +8,7 @@ module Rigor
|
|
|
8
8
|
# nothing about the code that was analysed.
|
|
9
9
|
#
|
|
10
10
|
# A named class, not a bare RuntimeError: {MutationScanner#classify} already folds a per-mutant
|
|
11
|
-
# `StandardError` into the
|
|
11
|
+
# `StandardError` into the `harness_errors` bucket, and the scanner's file-level rescue must catch THIS
|
|
12
12
|
# and nothing else, so the two failure modes stay distinguishable at every site that handles either.
|
|
13
13
|
#
|
|
14
14
|
# Issue #790 — it says WHICH of the two refusals below fired, because they want different recovery. A
|
|
@@ -4,6 +4,7 @@ require_relative "../inference/parameter_inference_collector"
|
|
|
4
4
|
require_relative "../inference/scope_indexer"
|
|
5
5
|
require_relative "../inference/project_seed_tables"
|
|
6
6
|
require_relative "../cache/incremental_snapshot"
|
|
7
|
+
require_relative "../cache/file_digest"
|
|
7
8
|
require_relative "../analysis/path_expansion"
|
|
8
9
|
require_relative "../analysis/buffer_binding"
|
|
9
10
|
|
|
@@ -107,11 +108,40 @@ module Rigor
|
|
|
107
108
|
paths = Analysis::PathExpansion.configured_files(configuration)
|
|
108
109
|
return nil if paths.empty?
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
payload = snapshot_payload(configuration)
|
|
112
|
+
bundles = payload&.seed_bundles
|
|
111
113
|
return nil if bundles.nil? || bundles.empty?
|
|
112
114
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
spelled = respell_for_buffer(paths, buffer)
|
|
116
|
+
tables = tables_for_buffer(paths: spelled, bundles: bundles, buffer: buffer, constant_sources: true)
|
|
117
|
+
with_snapshot_param_table(tables, payload.param_table, configuration,
|
|
118
|
+
paths: spelled, bundles: bundles, buffer: buffer)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Issue #2282 — under `parameter_inference: true` the snapshot also carries the call-site parameter table the
|
|
122
|
+
# writing run seeded its analysis from (`param_table`, ADR-67 WD6c), so a probe reads `@v = v` as `check`
|
|
123
|
+
# does. The table is whole-project (a callee's parameter type comes from callers in other files), so it is
|
|
124
|
+
# only as fresh as every file: it rides along ONLY when the fold re-walked nothing, that is, every path is a
|
|
125
|
+
# snapshot bundle with an unchanged digest and no path was added, removed or replaced by the editor buffer.
|
|
126
|
+
# Otherwise it is dropped, as {Analysis::IncrementalSession#fresh_param_table} recomputes rather than reuses
|
|
127
|
+
# it. Absent when the gate is off or the table is empty, which keeps the bundle-only seed.
|
|
128
|
+
def with_snapshot_param_table(tables, param_table, configuration, paths:, bundles:, buffer:)
|
|
129
|
+
return tables unless configuration.parameter_inference
|
|
130
|
+
return tables if param_table.nil? || param_table.empty?
|
|
131
|
+
return tables unless snapshot_current?(paths, bundles, buffer)
|
|
132
|
+
|
|
133
|
+
tables.merge(param_inferred_types: param_table).freeze
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def snapshot_current?(paths, bundles, buffer)
|
|
137
|
+
return false unless paths.size == bundles.size
|
|
138
|
+
|
|
139
|
+
paths.all? do |path|
|
|
140
|
+
cached = bundles[path]
|
|
141
|
+
cached && cached[:digest] == Cache::FileDigest.hexdigest(buffer ? buffer.resolve(path) : path)
|
|
142
|
+
end
|
|
143
|
+
rescue SystemCallError
|
|
144
|
+
false
|
|
115
145
|
end
|
|
116
146
|
|
|
117
147
|
# The configured file list with the entry that reaches `buffer`'s file respelled as the buffer's logical
|
|
@@ -128,12 +158,21 @@ module Rigor
|
|
|
128
158
|
end
|
|
129
159
|
end
|
|
130
160
|
|
|
131
|
-
|
|
161
|
+
# The bare single-file scope, or that scope with `seed`'s tables folded in. The one place `rigor type-of` and the
|
|
162
|
+
# language server's editor queries (#2282) fold a seed into a scope.
|
|
163
|
+
def seeded_scope(environment:, seed:)
|
|
164
|
+
base = Scope.empty(environment: environment)
|
|
165
|
+
return base if seed.nil? || seed.empty?
|
|
166
|
+
|
|
167
|
+
base.with_discovery(base.discovery.with(**seed))
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def snapshot_payload(configuration)
|
|
132
171
|
fingerprint = Cache::IncrementalSnapshot.fingerprint(configuration: configuration, roots: configuration.paths)
|
|
133
172
|
return nil if fingerprint.nil?
|
|
134
173
|
|
|
135
174
|
loaded = Cache::IncrementalSnapshot.new(root: configuration.cache_path).load_any(fingerprints: [fingerprint])
|
|
136
|
-
loaded&.last
|
|
175
|
+
loaded&.last
|
|
137
176
|
end
|
|
138
177
|
|
|
139
178
|
# The whole-project discovery tables, from the single-walk combined pass (one parse per file) that
|
|
@@ -138,7 +138,7 @@ module Rigor
|
|
|
138
138
|
QUOTES = ['"', "'"].freeze
|
|
139
139
|
# Mutating an argument to a universal-equality method is always an equivalent mutant: Ruby's `==` / `<=>`
|
|
140
140
|
# family returns false / nil on a type mismatch rather than raising, so the engine exempts them
|
|
141
|
-
# (`UNIVERSAL_EQUALITY_METHODS
|
|
141
|
+
# (`CheckRules::UNIVERSAL_EQUALITY_METHODS`; keep the two in step). Skip them to keep survivors meaningful.
|
|
142
142
|
UNIVERSAL_EQUALITY = %w[== != eql? equal? <=>].freeze
|
|
143
143
|
|
|
144
144
|
# Every operator the mutator knows. Each maps to the diagnostic rule family it is *engineered* to trip when
|
|
@@ -52,11 +52,9 @@ module Rigor
|
|
|
52
52
|
# `.rbs` files, plus the virtual entries rbs-inline and plugin `source_rbs` synthesis contribute.
|
|
53
53
|
# @param registry — the vocabulary an unknown label is judged against.
|
|
54
54
|
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
# documentation promises, and what every warm envelope-lane run was paying a full
|
|
59
|
-
# `RBS::Parser.parse_signature` per file for.
|
|
55
|
+
# A source with no honoured payload can contribute neither an envelope nor an unresolved report, so the
|
|
56
|
+
# `ANNOTATION_HINT` test skips it before any parse: one regex per file, not a full
|
|
57
|
+
# `RBS::Parser.parse_signature`.
|
|
60
58
|
def scan(sources:, registry:)
|
|
61
59
|
reporter = Reporter.new
|
|
62
60
|
methods = {}
|
|
@@ -128,7 +126,7 @@ module Rigor
|
|
|
128
126
|
def walk(decl, prefix, methods, classes, registry, reporter)
|
|
129
127
|
return unless decl.is_a?(::RBS::AST::Declarations::Class) || decl.is_a?(::RBS::AST::Declarations::Module)
|
|
130
128
|
|
|
131
|
-
nested =
|
|
129
|
+
nested = ::Rigor::Environment::RbsLoader.declared_class_path(decl, prefix)
|
|
132
130
|
class_name = nested.join("::")
|
|
133
131
|
envelope = RbsExtended.read_effect_envelope(
|
|
134
132
|
decl.annotations, owner_key: class_name, source: :class_annotation,
|
|
@@ -287,17 +287,13 @@ module Rigor
|
|
|
287
287
|
source_location.respond_to?(:start_line) ? source_location.start_line : nil
|
|
288
288
|
end
|
|
289
289
|
|
|
290
|
-
# Issue #785 — routes a declined directive to the per-run reporter. The
|
|
291
|
-
#
|
|
292
|
-
#
|
|
293
|
-
#
|
|
294
|
-
# dropped in every real run, while the doc comments claimed an `:info` entry was recorded. The
|
|
295
|
-
# position is flattened at record time through {RbsExtended::Reporter.position_of}, the one place
|
|
296
|
-
# every stream flattens through since #805, because the entry has to reach the pool drain channel as
|
|
297
|
-
# primitives (see {RbsExtended::Reporter}).
|
|
290
|
+
# Issue #785 — routes a declined directive to the per-run reporter. The first arm matters: the production
|
|
291
|
+
# {RbsExtended::Reporter} has `record_hkt_error` and neither `#record` nor `#<<`, so before this arm existed
|
|
292
|
+
# every malformed HKT directive was dropped in real runs. The position is flattened at record time through
|
|
293
|
+
# {RbsExtended::Reporter.position_of} (see {RbsExtended::Reporter} on why the entry carries primitives).
|
|
298
294
|
#
|
|
299
|
-
# The `#record` / `#<<` arms
|
|
300
|
-
#
|
|
295
|
+
# The `#record` / `#<<` arms serve the collecting doubles the directive specs and plugin authors use; the
|
|
296
|
+
# contract is the one `scan_rbs_loader` documents for its `reporter` parameter.
|
|
301
297
|
def record_hkt_error(reporter, message, source_location)
|
|
302
298
|
return if reporter.nil?
|
|
303
299
|
|
|
@@ -48,6 +48,16 @@ module Rigor
|
|
|
48
48
|
HktDirectiveEntry = Data.define(:message, :path, :line, :column)
|
|
49
49
|
DeprecatedFormEntry = Data.define(:payload, :replacement, :path, :line, :column)
|
|
50
50
|
|
|
51
|
+
# Every stream, by its reader, with the record method that replays one of its entries: an entry's
|
|
52
|
+
# members are that method's keywords. {#snapshot} and {#absorb} walk this table, so a new stream is
|
|
53
|
+
# declared here and nowhere else in the pool drain (ADR-116 WD3).
|
|
54
|
+
STREAMS = {
|
|
55
|
+
unresolved_payloads: :record_unresolved,
|
|
56
|
+
lossy_projections: :record_lossy_projection,
|
|
57
|
+
hkt_directive_errors: :record_hkt_error,
|
|
58
|
+
deprecated_forms: :record_deprecated_form
|
|
59
|
+
}.freeze
|
|
60
|
+
|
|
51
61
|
# Flattens an `RBS::Location` (or anything answering the same readers) to the `(path, line, column)`
|
|
52
62
|
# triple every entry carries. `column` is 1-based, since `RBS::Location#start_column` is 0-based and
|
|
53
63
|
# diagnostics are not. Each component is `nil` when the location cannot supply it, and the diagnostic
|
|
@@ -160,9 +170,23 @@ module Rigor
|
|
|
160
170
|
# True when no events have accumulated. Used by callers that want to skip the diagnostic-emission pass
|
|
161
171
|
# entirely on the common no-event path.
|
|
162
172
|
def empty?
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
173
|
+
STREAMS.each_key.all? { |stream| public_send(stream).empty? }
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# The drain a pool worker hands back: every stream's frozen entries by reader name. Marshal-clean and
|
|
177
|
+
# shareable, since each entry carries `(path, line, column)` primitives (#785, #805).
|
|
178
|
+
def snapshot
|
|
179
|
+
STREAMS.each_key.to_h { |stream| [stream, public_send(stream)] }
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Replays one worker's {#snapshot} through the record methods, whose dedup collapses the copies every
|
|
183
|
+
# worker hands over to the single row a `--workers=0` run prints. A missing stream (an older drain
|
|
184
|
+
# shape) or a nil snapshot records nothing.
|
|
185
|
+
def absorb(snapshot)
|
|
186
|
+
return if snapshot.nil?
|
|
187
|
+
|
|
188
|
+
STREAMS.each do |stream, record|
|
|
189
|
+
Array(snapshot[stream]).each { |entry| public_send(record, **entry.to_h) }
|
|
166
190
|
end
|
|
167
191
|
end
|
|
168
192
|
|
data/lib/rigor/rbs_extended.rb
CHANGED
|
@@ -513,7 +513,7 @@ module Rigor
|
|
|
513
513
|
Type::Nominal.new(normalized)
|
|
514
514
|
end
|
|
515
515
|
|
|
516
|
-
# Returned for `rigor:v1:param: <name> <refinement>`. The parameter name is a Ruby identifier
|
|
516
|
+
# Returned for `rigor:v1:param: <name> <refinement>`. The parameter name is a Ruby identifier; the
|
|
517
517
|
# type is any `Rigor::Type` the refinement parser resolves (bare kebab-case name, parameterised form, or
|
|
518
518
|
# `Integer[a..b]` range, or the deprecated `int<a, b>` — the same grammar the `return:` directive accepts).
|
|
519
519
|
ParamOverride = Data.define(:param_name, :type)
|
|
@@ -554,7 +554,7 @@ module Rigor
|
|
|
554
554
|
end
|
|
555
555
|
|
|
556
556
|
# Convenience reader for call sites that want to look up a single override by parameter name. Returns a
|
|
557
|
-
# frozen
|
|
557
|
+
# frozen map from parameter name to type; missing keys mean "use the RBS-declared type". Callers MUST treat the
|
|
558
558
|
# hash as read-only.
|
|
559
559
|
def param_type_override_map(method_def, environment: nil)
|
|
560
560
|
overrides = read_param_type_overrides(method_def, environment: environment)
|
|
@@ -728,7 +728,6 @@ module Rigor
|
|
|
728
728
|
NO_EFFECT_LABELS = [].freeze
|
|
729
729
|
private_constant :NO_EFFECT_LABELS
|
|
730
730
|
|
|
731
|
-
# Whether `string` is the bare `%a{pure}` annotation.
|
|
732
731
|
def pure_annotation?(string)
|
|
733
732
|
!string.nil? && PURE_ANNOTATION_PATTERN.match?(string)
|
|
734
733
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../run_scoped_slots"
|
|
4
|
+
|
|
3
5
|
module Rigor
|
|
4
6
|
# {Reflection}'s constant-ancestor walk ([#354](https://github.com/rigortype/rigor/issues/354)), split out for
|
|
5
7
|
# the reader rather than for the loader: the whole-spelling ladder's step 2 (`reflection.rb`) and the
|
|
@@ -8,11 +10,11 @@ module Rigor
|
|
|
8
10
|
# keeps the walk behind the facade its callers already read.
|
|
9
11
|
module Reflection
|
|
10
12
|
# #354 — thread-local slot for the per-run ancestor-scope memo. See {.ancestor_constant_scopes}.
|
|
11
|
-
ANCESTOR_SCOPES_KEY = :__rigor_ancestor_constant_scopes__
|
|
13
|
+
ANCESTOR_SCOPES_KEY = RunScopedSlots.register(:__rigor_ancestor_constant_scopes__)
|
|
12
14
|
private_constant :ANCESTOR_SCOPES_KEY
|
|
13
15
|
|
|
14
16
|
# The recording run's slot. See {.recorded_ancestor_constant_scopes}.
|
|
15
|
-
RECORDED_ANCESTOR_SCOPES_KEY = :__rigor_recorded_ancestor_constant_scopes__
|
|
17
|
+
RECORDED_ANCESTOR_SCOPES_KEY = RunScopedSlots.register(:__rigor_recorded_ancestor_constant_scopes__)
|
|
16
18
|
private_constant :RECORDED_ANCESTOR_SCOPES_KEY
|
|
17
19
|
|
|
18
20
|
module_function
|
|
@@ -228,7 +230,7 @@ module Rigor
|
|
|
228
230
|
end
|
|
229
231
|
private_class_method :ancestry_unknown_before?
|
|
230
232
|
|
|
231
|
-
# Ruby places these after every entry of a chain, so a constant they own is the top level's
|
|
233
|
+
# Ruby places these after every entry of a chain, so a constant they own is the top level's.
|
|
232
234
|
IMPLICIT_ANCESTORS = %w[Object Kernel BasicObject].freeze
|
|
233
235
|
private_constant :IMPLICIT_ANCESTORS
|
|
234
236
|
|
data/lib/rigor/rooted_glob.rb
CHANGED
|
@@ -20,7 +20,7 @@ module Rigor
|
|
|
20
20
|
|
|
21
21
|
module_function
|
|
22
22
|
|
|
23
|
-
# @param root — a directory path
|
|
23
|
+
# @param root — a directory path, taken literally
|
|
24
24
|
# @param pattern — a `Dir.glob` pattern relative to `root`
|
|
25
25
|
# @return the matches spelled under `root`, in `Dir.glob` order; empty when `root` is not a directory
|
|
26
26
|
def glob(root, pattern)
|
|
@@ -32,5 +32,19 @@ module Rigor
|
|
|
32
32
|
def literal(name)
|
|
33
33
|
name.to_s.gsub(METACHARACTERS, "\\\\\\0")
|
|
34
34
|
end
|
|
35
|
+
|
|
36
|
+
# A configured file path (#2222), absolute or relative to the working directory, as the `[root, pattern]` pair
|
|
37
|
+
# that `glob(root, pattern)` reads as exactly that file. A relative path stays under the working directory, as
|
|
38
|
+
# it always did. An absolute one is split into its own directory and a literal basename: `File.join(".", "/abs")`
|
|
39
|
+
# reads `./abs`, so an absolute path joined under `"."` matched nothing.
|
|
40
|
+
#
|
|
41
|
+
# @param path — a file path, taken literally
|
|
42
|
+
# @return `[root, pattern]`: `"."` and the literal path when relative, else the directory and the literal basename
|
|
43
|
+
def split_file(path)
|
|
44
|
+
path = path.to_s
|
|
45
|
+
return [".", literal(path)] unless File.absolute_path?(path)
|
|
46
|
+
|
|
47
|
+
[File.dirname(path), literal(File.basename(path))]
|
|
48
|
+
end
|
|
35
49
|
end
|
|
36
50
|
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
# Issues #2412 and #2399 — the registry of per-thread memo slots whose contents belong to one analysis run. An
|
|
5
|
+
# owner registers its `Thread.current` key where it names it (`KEY = RunScopedSlots.register(:key)`), and each
|
|
6
|
+
# entry point that runs an analysis calls {.release} in its `ensure`, so a finished run, or one that raised,
|
|
7
|
+
# leaves none of its scopes, discovery tables or environment behind on the thread.
|
|
8
|
+
#
|
|
9
|
+
# A slot that holds its run until the next run overwrites it retains one run per thread. A slot whose value
|
|
10
|
+
# reaches its own key retains every run, as `LoopValueRecord`'s `ObjectSpace::WeakKeyMap` did: the map holds
|
|
11
|
+
# its values strongly, and a recorded scope reaches the parse tree that holds the key node. Releasing at run end
|
|
12
|
+
# bounds both. Inside a run nothing changes: every memo keeps its key and its hit rate, and a slot read outside
|
|
13
|
+
# a run (a language-server hover on the main thread) refills on its first miss.
|
|
14
|
+
#
|
|
15
|
+
# Only memo slots belong here. A slot a `with_*` frame installs and restores around a block is already empty
|
|
16
|
+
# when the frame returns, and clearing it from inside a frame would break the frame.
|
|
17
|
+
#
|
|
18
|
+
# The registry is a module-level array filled at require time, so it is for the main Ractor only.
|
|
19
|
+
module RunScopedSlots
|
|
20
|
+
@keys = []
|
|
21
|
+
|
|
22
|
+
# Adds `key` to the registry and returns it, so the owner's constant keeps its value.
|
|
23
|
+
def self.register(key)
|
|
24
|
+
@keys << key unless @keys.include?(key)
|
|
25
|
+
key
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Every registered key, in registration order.
|
|
29
|
+
def self.keys = @keys.dup.freeze
|
|
30
|
+
|
|
31
|
+
# Empties every registered slot on the calling thread.
|
|
32
|
+
def self.release
|
|
33
|
+
thread = Thread.current
|
|
34
|
+
@keys.each { |key| thread[key] = nil }
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/rigor/runtime/jit.rb
CHANGED
|
@@ -37,7 +37,7 @@ module Rigor
|
|
|
37
37
|
# *remaining* deadline rather than restarting the window; see its own
|
|
38
38
|
# comment for why that distinction is worth the bookkeeping.
|
|
39
39
|
module Jit
|
|
40
|
-
# Opt-out switch: `RIGOR_DISABLE_YJIT=1` disables
|
|
40
|
+
# Opt-out switch: `RIGOR_DISABLE_YJIT=1` disables every entry point.
|
|
41
41
|
DISABLE_ENV = "RIGOR_DISABLE_YJIT"
|
|
42
42
|
|
|
43
43
|
# Advanced / calibration override of the {enable_after} deadline, in
|
|
@@ -61,6 +61,13 @@ module Rigor
|
|
|
61
61
|
)
|
|
62
62
|
|
|
63
63
|
class DiscoveryIndex
|
|
64
|
+
# Issue #2330 — identity as a hash key. `Data` hashes and compares structurally, which over these project-sized
|
|
65
|
+
# tables is both costly and wrong for a per-thread memo keyed by "this very index" (an `ObjectSpace::WeakKeyMap`
|
|
66
|
+
# holds the memo while the index lives and drops it with it). `==` stays structural.
|
|
67
|
+
def hash = object_id.hash
|
|
68
|
+
|
|
69
|
+
def eql?(other) = equal?(other)
|
|
70
|
+
|
|
64
71
|
EMPTY_NODE_TABLE = {}.compare_by_identity.freeze
|
|
65
72
|
EMPTY_TABLE = {}.freeze
|
|
66
73
|
EMPTY_NAME_SET = Set.new.freeze
|
|
@@ -423,10 +430,9 @@ module Rigor
|
|
|
423
430
|
struct_member_layouts: EMPTY_TABLE,
|
|
424
431
|
# ADR-67 WD3 — the call-site parameter-inference table, keyed by `[class_name, method_name, kind]` (the
|
|
425
432
|
# same `(class, method, kind)` triple {Inference::ParameterInferenceCollector} records and that
|
|
426
|
-
# `build_method_entry_scope` reconstructs from the lexical class path). The value is
|
|
427
|
-
#
|
|
428
|
-
#
|
|
429
|
-
# leaves it empty and seeds nothing (byte-identical).
|
|
433
|
+
# `build_method_entry_scope` reconstructs from the lexical class path). The value is the
|
|
434
|
+
# union of resolved call-site argument types per parameter name. Empty unless `parameter_inference:` is
|
|
435
|
+
# on or the `coverage --protection` collection pass runs; a run with neither seeds nothing (byte-identical).
|
|
430
436
|
param_inferred_types: EMPTY_TABLE,
|
|
431
437
|
# ADR-84 WD2 — the run-scope identity token `Analysis::Runner#run_analysis` mints per run (a frozen
|
|
432
438
|
# bare Object) and seeds through `project_scope_seed_tables`. The user-method return memo keys its
|
|
@@ -474,7 +480,6 @@ module Rigor
|
|
|
474
480
|
# possible fact carries, and a Runner's initial state. Copy it (`dup`) before mutating.
|
|
475
481
|
EMPTY_SIBLINGS = SIBLINGS.each_value.to_h { |sibling| [sibling, EMPTY.public_send(sibling)] }.freeze
|
|
476
482
|
|
|
477
|
-
# The all-empty value of a paired member or sibling.
|
|
478
483
|
def self.empty_value(name)
|
|
479
484
|
EMPTY.public_send(name)
|
|
480
485
|
end
|
|
@@ -499,7 +504,6 @@ module Rigor
|
|
|
499
504
|
end
|
|
500
505
|
end
|
|
501
506
|
|
|
502
|
-
# Whether `name` is a member or sibling of {SIBLINGS}.
|
|
503
507
|
def self.paired?(name)
|
|
504
508
|
PARTNERS.key?(name)
|
|
505
509
|
end
|
|
@@ -522,6 +526,15 @@ module Rigor
|
|
|
522
526
|
recorded == kind || (!recorded.nil? && recorded == METHOD_KIND_BOTH)
|
|
523
527
|
end
|
|
524
528
|
|
|
529
|
+
# Issue #681 / #707 — the `Module.nesting` the declaration walk recorded for `def_node`, or nil when it recorded
|
|
530
|
+
# none: {#discovered_def_nestings} first, then its rehydration for a def served from an ADR-85 seed bundle, whose
|
|
531
|
+
# node {Inference::DefNodeResolver} mints from its own parse ({Inference::DefNodeResolver.rehydrated_nesting}).
|
|
532
|
+
# The one reader of the table outside its owners; `ExpressionTyper#recorded_def_nesting` says why the order is
|
|
533
|
+
# safe.
|
|
534
|
+
def recorded_def_nesting(def_node)
|
|
535
|
+
discovered_def_nestings[def_node] || Inference::DefNodeResolver.rehydrated_nesting(def_node)
|
|
536
|
+
end
|
|
537
|
+
|
|
525
538
|
# ADR-119 WD1 — whether `path` (`[class, name]`, or `[class, [kind, name]]` for an envelope) is a contested
|
|
526
539
|
# entry of `member`, one of the single-valued members {SIBLINGS} pairs. Internal to the candidate-set read.
|
|
527
540
|
def contested?(member, path)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../run_scoped_slots"
|
|
4
|
+
|
|
3
5
|
module Rigor
|
|
4
6
|
class Scope
|
|
5
7
|
# ADR-24 (amended for #1567, #1568, #1570 and #1571) — Ruby's method resolution order for one project class or
|
|
@@ -494,7 +496,7 @@ module Rigor
|
|
|
494
496
|
end
|
|
495
497
|
private :compute_levels
|
|
496
498
|
|
|
497
|
-
MEMO_KEY = :__rigor_resolution_chain__
|
|
499
|
+
MEMO_KEY = RunScopedSlots.register(:__rigor_resolution_chain__)
|
|
498
500
|
private_constant :MEMO_KEY
|
|
499
501
|
|
|
500
502
|
FLAVORS = %i[methods constants arity].freeze
|