rigortype 0.4.6 → 0.4.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 +4 -2
- data/data/core_overlay/bigdecimal.rbs +33 -0
- data/data/core_overlay/resolv.rbs +30 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +45 -13
- data/data/gem_overlay/addressable/addressable.rbs +40 -0
- 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 +6 -3
- data/docs/handbook/11-sig-gen.md +85 -3
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/install.md +20 -0
- data/docs/manual/01-installation.md +67 -26
- data/docs/manual/02-cli-reference.md +455 -113
- data/docs/manual/03-configuration.md +76 -5
- data/docs/manual/04-diagnostics.md +5 -4
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/08-skills.md +11 -0
- data/docs/manual/09-editor-integration.md +21 -2
- data/docs/manual/10-mcp-server.md +38 -2
- data/docs/manual/12-caching.md +4 -3
- data/docs/manual/14-rails-quickstart.md +1 -1
- data/docs/manual/19-effect-labels.md +3 -4
- data/docs/manual/plugins/rigor-actionpack.md +32 -15
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +23 -1
- data/docs/manual/plugins/rigor-sorbet.md +17 -3
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/check_rules/always_raises_shield.rb +147 -0
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/call_facts.rb +58 -0
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +12 -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 +16 -4
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +6 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/plugin_api_surface.rb +195 -0
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +41 -12
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +27 -1
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +3 -3
- data/lib/rigor/analysis/check_rules/replaced_singleton_defs.rb +96 -0
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/rule_ids.rb +9 -2
- 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 +2 -2
- data/lib/rigor/analysis/check_rules.rb +720 -141
- data/lib/rigor/analysis/crash_signature.rb +45 -3
- data/lib/rigor/analysis/dependency_recorder.rb +237 -80
- 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.rb +11 -1
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +4 -3
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +306 -53
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -3
- data/lib/rigor/analysis/rule_catalog.rb +39 -3
- data/lib/rigor/analysis/run_cache_key.rb +27 -3
- data/lib/rigor/analysis/run_disclosure_credit.rb +26 -6
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -2
- data/lib/rigor/analysis/runner/declaration_position.rb +8 -8
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +264 -112
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +4 -9
- data/lib/rigor/analysis/runner/pool_coordinator.rb +173 -328
- data/lib/rigor/analysis/runner/project_pre_passes.rb +4 -37
- 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 +298 -109
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +62 -23
- 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 +65 -71
- data/lib/rigor/bleeding_edge.rb +22 -10
- 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/file_digest.rb +39 -31
- data/lib/rigor/cache/incremental_snapshot.rb +95 -17
- 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 +90 -4
- data/lib/rigor/cache/rbs_environment.rb +8 -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 +160 -57
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +112 -104
- 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 +26 -18
- 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 +29 -10
- 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 +92 -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 +2 -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 +214 -56
- data/lib/rigor/config_audit.rb +33 -19
- data/lib/rigor/configuration/severity_profile.rb +14 -5
- data/lib/rigor/configuration.rb +104 -35
- data/lib/rigor/effects/collector.rb +53 -21
- 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 +64 -33
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/constant_type_cache_holder.rb +5 -0
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +18 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +381 -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/hkt_registry_holder.rb +6 -0
- 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_collection_discovery.rb +123 -8
- data/lib/rigor/environment/rbs_coverage_report.rb +12 -11
- data/lib/rigor/environment/rbs_hierarchy.rb +12 -15
- data/lib/rigor/environment/rbs_loader.rb +772 -110
- 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 +169 -42
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +136 -40
- data/lib/rigor/inference/alias_mutation_floor/foreign_locals.rb +117 -0
- data/lib/rigor/inference/alias_mutation_floor/memos.rb +85 -0
- data/lib/rigor/inference/alias_mutation_floor/reach.rb +119 -0
- data/lib/rigor/inference/alias_mutation_floor/site_collector.rb +252 -0
- data/lib/rigor/inference/alias_mutation_floor.rb +339 -0
- data/lib/rigor/inference/anonymous_meta_class.rb +18 -0
- data/lib/rigor/inference/block_auto_splat.rb +1 -1
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +185 -0
- data/lib/rigor/inference/budget_trace.rb +8 -2
- data/lib/rigor/inference/builtins/array_catalog.rb +2 -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/captured_locals.rb +2 -0
- data/lib/rigor/inference/census_foreign_block.rb +354 -0
- data/lib/rigor/inference/clause_widening.rb +1 -1
- data/lib/rigor/inference/closure_escape_analyzer.rb +11 -4
- data/lib/rigor/inference/construction_escape.rb +258 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- data/lib/rigor/inference/declaration_walk.rb +4 -0
- 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 +33 -15
- data/lib/rigor/inference/def_return_typer.rb +47 -5
- data/lib/rigor/inference/definer_resolution.rb +19 -9
- data/lib/rigor/inference/definers_index.rb +162 -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/error_info.rb +16 -0
- data/lib/rigor/inference/expression_typer.rb +1559 -320
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/flow_tracer.rb +31 -14
- data/lib/rigor/inference/fork_map.rb +3 -0
- data/lib/rigor/inference/fresh_frame_blocks.rb +52 -1
- data/lib/rigor/inference/global_write_census.rb +81 -5
- 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/in_effect_refinements.rb +7 -0
- data/lib/rigor/inference/indexed_narrowing.rb +61 -15
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +154 -8
- data/lib/rigor/inference/key_presence_guard.rb +51 -24
- data/lib/rigor/inference/last_line/self_evidence.rb +30 -0
- data/lib/rigor/inference/last_line.rb +5 -2
- data/lib/rigor/inference/loop_value_record.rb +66 -14
- data/lib/rigor/inference/match_rebinding/frame.rb +57 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +101 -0
- data/lib/rigor/inference/match_rebinding.rb +28 -5
- 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 +44 -30
- data/lib/rigor/inference/method_dispatcher/class_keyed_block_params.rb +65 -0
- 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/core_enumerable_receiver.rb +44 -0
- data/lib/rigor/inference/method_dispatcher/declared_constructor.rb +151 -0
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/imprecise_argument.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/interface_shape.rb +181 -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 +51 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +606 -78
- 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 +3 -3
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +9 -7
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +467 -84
- 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/singleton_type_params.rb +104 -0
- 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 +123 -25
- data/lib/rigor/inference/method_parameter_binder.rb +136 -56
- data/lib/rigor/inference/module_function_state/spellings.rb +2 -2
- data/lib/rigor/inference/module_function_state.rb +24 -3
- data/lib/rigor/inference/multi_target_binder.rb +2 -2
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +199 -29
- data/lib/rigor/inference/narrowing.rb +238 -50
- data/lib/rigor/inference/operand_effects.rb +43 -2
- data/lib/rigor/inference/optimistic_origin.rb +134 -9
- data/lib/rigor/inference/origin_lookup.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/precision_scanner.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +30 -9
- data/lib/rigor/inference/project_patched_methods.rb +65 -13
- data/lib/rigor/inference/project_patched_scanner.rb +120 -25
- data/lib/rigor/inference/project_patched_visibility.rb +39 -3
- data/lib/rigor/inference/project_yielder.rb +11 -17
- data/lib/rigor/inference/rbs_type_translator.rb +68 -15
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/receiver_writer_call.rb +67 -0
- data/lib/rigor/inference/recursion_rebinding.rb +157 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +57 -17
- data/lib/rigor/inference/refined_dispatch/own_method.rb +51 -16
- data/lib/rigor/inference/refined_dispatch.rb +13 -0
- data/lib/rigor/inference/reflective_ivar_write.rb +19 -11
- data/lib/rigor/inference/remover_holder_scan.rb +287 -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/class_cvars_collector.rb +13 -6
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +70 -26
- 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 +295 -0
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +136 -9
- data/lib/rigor/inference/scope_indexer.rb +2213 -226
- data/lib/rigor/inference/self_call_ivar_writes.rb +103 -12
- data/lib/rigor/inference/self_preserving_block.rb +87 -0
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +42 -8
- data/lib/rigor/inference/singleton_object_constant.rb +32 -2
- data/lib/rigor/inference/statement_evaluator.rb +3268 -358
- data/lib/rigor/inference/string_mutation.rb +14 -0
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_scanner.rb +40 -17
- data/lib/rigor/inference/toplevel_def_census.rb +67 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/untyped_rejoin.rb +1 -1
- data/lib/rigor/inference/void_tail_summary.rb +29 -9
- 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/claims/comparison.rb +78 -0
- data/lib/rigor/lens/claims/request.rb +131 -0
- data/lib/rigor/lens/claims/type_reader.rb +216 -0
- data/lib/rigor/lens/claims.rb +208 -0
- data/lib/rigor/lens/contract_reader.rb +5 -0
- data/lib/rigor/lens/document.rb +1 -1
- data/lib/rigor/lens/file_reader.rb +21 -8
- data/lib/rigor/lens/plugins.rb +1 -1
- data/lib/rigor/lens/run.rb +8 -0
- data/lib/rigor/lens.rb +1 -1
- data/lib/rigor/library_probe.rb +68 -0
- data/lib/rigor/mcp/server.rb +73 -2
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/memo_audit.rb +282 -0
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/base.rb +15 -2
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +26 -4
- 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 +16 -16
- data/lib/rigor/plugin/registry.rb +16 -5
- 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 +48 -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/mutation_cache.rb +4 -1
- 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 +81 -22
- data/lib/rigor/reflection/declaration_collectors.rb +55 -0
- data/lib/rigor/reflection/declarations.rb +58 -0
- data/lib/rigor/reflection/project_method.rb +177 -0
- data/lib/rigor/reflection.rb +2 -0
- data/lib/rigor/rooted_glob.rb +32 -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 +168 -8
- data/lib/rigor/scope/resolution_chain/relevance.rb +14 -1
- data/lib/rigor/scope/resolution_chain.rb +901 -54
- data/lib/rigor/scope.rb +644 -37
- data/lib/rigor/sig_gen/bot_proposal_guard.rb +306 -0
- data/lib/rigor/sig_gen/classification.rb +18 -1
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +588 -66
- 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 +37 -4
- data/lib/rigor/sig_gen/observation_collector.rb +14 -7
- 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/platform_guarded_files.rb +184 -0
- data/lib/rigor/sig_gen/renderer.rb +15 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +62 -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 +238 -37
- data/lib/rigor/sig_gen.rb +1 -0
- data/lib/rigor/source/forwardable_delegators.rb +122 -0
- data/lib/rigor/source/node_children.rb +13 -0
- 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 +173 -21
- data/lib/rigor/type/constant.rb +4 -5
- data/lib/rigor/type/hash_shape.rb +21 -40
- data/lib/rigor/type/interface.rb +60 -0
- data/lib/rigor/type/union.rb +1 -1
- data/lib/rigor/type.rb +1 -0
- 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/type_of_memo/serving.rb +99 -0
- data/lib/rigor/type_of_memo/stats.rb +43 -0
- data/lib/rigor/type_of_memo.rb +337 -0
- data/lib/rigor/typing_state.rb +1094 -0
- 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 +3 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +115 -36
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +3 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +25 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +16 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +4 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +4 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +2 -1
- 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 +132 -33
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +20 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +7 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +54 -17
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +19 -5
- 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 +11 -14
- 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 +30 -9
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +55 -13
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_collector.rb +15 -21
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +1 -6
- 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 +8 -7
- 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-graphql/lib/rigor/plugin/graphql.rb +12 -2
- 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 +8 -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 +200 -4
- 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 +4 -3
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +5 -5
- 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 +210 -3
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +146 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +52 -34
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +97 -24
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_collector.rb +16 -16
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +4 -8
- 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/check_rules/rule_walk.rbs +6 -0
- data/sig/rigor/analysis/fact_store.rbs +2 -2
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- data/sig/rigor/cache/descriptor.rbs +14 -0
- 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/environment.rbs +4 -1
- data/sig/rigor/inference.rbs +4 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +53 -18
- 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/interfaces.rbs +51 -0
- data/sig/rigor/plugin/io_boundary.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +9 -9
- data/sig/rigor/plugin/node_context.rbs +21 -0
- data/sig/rigor/plugin/protocol_contract.rbs +3 -7
- data/sig/rigor/reflection.rbs +37 -0
- data/sig/rigor/scope.rbs +43 -4
- data/sig/rigor/trinary.rbs +1 -0
- data/sig/rigor/type.rbs +9 -3
- data/sig/rigor.rbs +3 -2
- data/skills/rigor-ask/SKILL.md +1 -0
- 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/01-detect.md +1 -0
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +17 -2
- data/skills/rigor-project-init/references/06-agent-contract.md +4 -4
- data/skills/rigor-rbs-contract/SKILL.md +147 -0
- data/skills/rigor-rbs-contract/references/01-finding-candidates.md +212 -0
- data/skills/rigor-rbs-contract/references/02-contract-rules.md +157 -0
- data/skills/rigor-rbs-contract/references/03-target-own-code.md +90 -0
- data/skills/rigor-rbs-contract/references/04-target-gem-rbs-collection.md +210 -0
- data/skills/rigor-rbs-contract/references/05-declaration-mutants.md +182 -0
- data/skills/rigor-rbs-setup/SKILL.md +3 -1
- data/skills/rigor-type-oracle/SKILL.md +26 -1
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +4 -3
- metadata +82 -3
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../typing_state"
|
|
4
|
+
|
|
3
5
|
module Rigor
|
|
4
6
|
module Analysis
|
|
5
7
|
# ADR-24 slice 4a — records every *implicit-self* method call the inference engine could not resolve to any
|
|
@@ -18,15 +20,32 @@ module Rigor
|
|
|
18
20
|
# recompute" lesson applied to self-calls.
|
|
19
21
|
#
|
|
20
22
|
# ADR-24 slice 4 (`call.self-undefined-method`) consumes the recorded misses behind a confidently-closed-class
|
|
21
|
-
# gate (see `CheckRules`
|
|
23
|
+
# gate (see `CheckRules`). The rule ships `:off` by default — {active?} is false on a normal run, so
|
|
22
24
|
# the instrumented choke-point pays a single integer read and records nothing. Recording is purely
|
|
23
25
|
# observational; it never changes a diagnostic.
|
|
24
26
|
#
|
|
25
27
|
# Modelled on {DependencyRecorder}: process-thread-local accumulator, a cheap disabled fast path, and a
|
|
26
28
|
# frozen snapshot for consumers.
|
|
27
29
|
module SelfCallResolutionRecorder
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
# ADR-129 WD1 — the installed accumulator is a Frame; its contents are the bound Table {CALLS}. The activation
|
|
31
|
+
# count below is a process switch, outside the typing state (WD5).
|
|
32
|
+
RECORDER = TypingState.frame(
|
|
33
|
+
:self_call_resolution_recorder,
|
|
34
|
+
contents: :table, reason: "the accumulator a recording installs; each unresolved call records into it",
|
|
35
|
+
# G1′ witness: the memo journals and replays the records, so it is not a shut switch (unlike the tracers).
|
|
36
|
+
witness: "spec/fixtures/typing_state_witnesses/self_call_resolution_recorder.rb"
|
|
37
|
+
)
|
|
38
|
+
private_constant :RECORDER
|
|
39
|
+
|
|
40
|
+
# ADR-129 WD1 — the recorded misses are a bound Table: each installed accumulator is one of its stores, keyed by
|
|
41
|
+
# the call tuple (deduplicated, so the first record of a tuple is its only write), journaled while a capture is
|
|
42
|
+
# open so a later `type_of` memo can validate the reads and replay the writes in order.
|
|
43
|
+
CALLS = TypingState.table(
|
|
44
|
+
:self_call_misses,
|
|
45
|
+
bound: true,
|
|
46
|
+
reason: "UnresolvedSelfCall => true per consumer accumulator, appended in first-record order"
|
|
47
|
+
)
|
|
48
|
+
private_constant :CALLS
|
|
30
49
|
|
|
31
50
|
# One unresolved implicit-self call. `class_name` is the receiver's statically known class (the
|
|
32
51
|
# enclosing `self` type); `method_name` the called name; `node` the Prism `CallNode` (held in-memory so
|
|
@@ -45,10 +64,28 @@ module Rigor
|
|
|
45
64
|
@seen = Set.new
|
|
46
65
|
end
|
|
47
66
|
|
|
48
|
-
def add(call)
|
|
49
|
-
return unless @seen.add?(call)
|
|
67
|
+
def add?(call)
|
|
68
|
+
return false unless @seen.add?(call)
|
|
50
69
|
|
|
51
70
|
@calls << call
|
|
71
|
+
true
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Whether `call` is already recorded.
|
|
75
|
+
def recorded?(call) = @seen.include?(call)
|
|
76
|
+
|
|
77
|
+
# The bound Table's store protocol ({CALLS}): `true` for a recorded call, else `default`.
|
|
78
|
+
def fetch(call, default) = @seen.include?(call) || default
|
|
79
|
+
|
|
80
|
+
# The bound Table's store protocol: an undone write (G1's stage-4 form) forgets `call`.
|
|
81
|
+
def delete(call)
|
|
82
|
+
@calls.delete(call) if @seen.delete?(call)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# The bound Table's store protocol: a replayed write records `call` as {#add?} does, so the replay order of a
|
|
86
|
+
# write slice is the order of {#calls}.
|
|
87
|
+
def []=(call, _value)
|
|
88
|
+
add?(call)
|
|
52
89
|
end
|
|
53
90
|
|
|
54
91
|
def snapshot
|
|
@@ -69,15 +106,16 @@ module Rigor
|
|
|
69
106
|
# Activates recording for `consumer` (the path being analyzed) for the duration of the block and returns
|
|
70
107
|
# the frozen {Record}. Nests safely; restores the previous recorder on exit.
|
|
71
108
|
def record_for(consumer)
|
|
72
|
-
previous = Thread.current[KEY]
|
|
73
109
|
accumulator = Accumulator.new(consumer.to_s)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
TypingState.current.with(RECORDER, accumulator) do
|
|
111
|
+
@mutex.synchronize { @active_count += 1 }
|
|
112
|
+
begin
|
|
113
|
+
yield
|
|
114
|
+
accumulator.snapshot
|
|
115
|
+
ensure
|
|
116
|
+
@mutex.synchronize { @active_count -= 1 }
|
|
117
|
+
end
|
|
118
|
+
end
|
|
81
119
|
end
|
|
82
120
|
|
|
83
121
|
# Plain integer read (GVL-atomic) — no `Thread.current` lookup on the disabled fast path.
|
|
@@ -88,19 +126,20 @@ module Rigor
|
|
|
88
126
|
# Records one unresolved implicit-self call. No-op when no consumer is active on this thread (another
|
|
89
127
|
# thread may have flipped {active?}).
|
|
90
128
|
def record(class_name:, method_name:, node:, path:, line:, column:)
|
|
91
|
-
|
|
129
|
+
state = TypingState.current
|
|
130
|
+
accumulator = state[RECORDER]
|
|
92
131
|
return if accumulator.nil?
|
|
93
132
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
column: column
|
|
102
|
-
)
|
|
133
|
+
call = UnresolvedSelfCall.new(
|
|
134
|
+
class_name: class_name.to_s,
|
|
135
|
+
method_name: method_name.to_sym,
|
|
136
|
+
node: node,
|
|
137
|
+
path: path,
|
|
138
|
+
line: line,
|
|
139
|
+
column: column
|
|
103
140
|
)
|
|
141
|
+
state.log_bound_read(CALLS, accumulator, call, accumulator.fetch(call, TypingState::ABSENT)) if state.capturing?
|
|
142
|
+
state.log_bound_write(CALLS, accumulator, call, true, TypingState::ABSENT) if accumulator.add?(call)
|
|
104
143
|
end
|
|
105
144
|
end
|
|
106
145
|
end
|
|
@@ -173,9 +173,8 @@ module Rigor
|
|
|
173
173
|
# copies one tag body once, and the second `@author` is the same copy seen from the other end, not a
|
|
174
174
|
# second reading. Only a node OUTSIDE the winning run's own compiled span counts, which is what keeps
|
|
175
175
|
# the busy lines of a real view answerable while the cross-tag repeat (`<%= v %> <%= v.to_s %>`, or
|
|
176
|
-
# `<%= v %><%= "v" %>` probed at the STRING's `v`) still declines
|
|
177
|
-
# span would answer instead
|
|
178
|
-
# (see the PR), and the follow-up this rule is deliberately conservative ahead of.
|
|
176
|
+
# `<%= v %><%= "v" %>` probed at the STRING's `v`) still declines. That family is what a plugin-exported
|
|
177
|
+
# tag span would answer instead, and it is the follow-up this rule is deliberately conservative ahead of.
|
|
179
178
|
#
|
|
180
179
|
# `spill` is the nearest NON-BLANK compiled line above this template line's own, where a hoisted
|
|
181
180
|
# leading-text literal lives. Only a string literal the run does NOT contain counts there. A code
|
|
@@ -189,6 +189,15 @@ module Rigor
|
|
|
189
189
|
@entries.keys.sort
|
|
190
190
|
end
|
|
191
191
|
|
|
192
|
+
# Issue #2233 — whether a plugin claims `path` by one of its `template_globs:`, in any spelling a caller holds it
|
|
193
|
+
# (absolute, `./`-prefixed, relative). A claimed template is analysed as a unit, never as a plain `.rb` file, so
|
|
194
|
+
# the runner keeps the buffer's logical path out of the `.rb` targets, so it is not analysed twice.
|
|
195
|
+
def claims?(path)
|
|
196
|
+
return false if @claimed_globs.empty?
|
|
197
|
+
|
|
198
|
+
TemplateUnitPaths.claims?(@claimed_globs, TemplateUnitPaths.relative(path, @root))
|
|
199
|
+
end
|
|
200
|
+
|
|
192
201
|
def [](path)
|
|
193
202
|
entry_for(path)
|
|
194
203
|
end
|
|
@@ -293,7 +302,6 @@ module Rigor
|
|
|
293
302
|
[entry.locals.keys.map(&:to_sym)]
|
|
294
303
|
end
|
|
295
304
|
|
|
296
|
-
# The `view:<logical_name>` effect-unit key for a path, or nil.
|
|
297
305
|
# The file whose bytes a unit's path was READ from: the editor's buffer when one is bound to it, the
|
|
298
306
|
# project file otherwise. Read by the run's dependency descriptor, so it digests what the run read.
|
|
299
307
|
def physical_path(path, buffer)
|
|
@@ -25,6 +25,7 @@ require_relative "dependency_source_inference"
|
|
|
25
25
|
require_relative "diagnostic"
|
|
26
26
|
require_relative "erb_template_detector"
|
|
27
27
|
require_relative "template_units"
|
|
28
|
+
require_relative "runner/run_level_facts"
|
|
28
29
|
|
|
29
30
|
module Rigor
|
|
30
31
|
module Analysis
|
|
@@ -39,8 +40,8 @@ module Rigor
|
|
|
39
40
|
# - `configuration` — Phase 2a ({Rigor::Configuration} is `Ractor.shareable?`).
|
|
40
41
|
# - `cache_store` — the fork backend passes the parent runner's pre-built Store (`cache_store:
|
|
41
42
|
# @cache_store` in PoolCoordinator); workers share it rather than building their own at `cache_root`.
|
|
42
|
-
# - `plugin_blueprints` — Phase 3a (`
|
|
43
|
-
# - `explain` —
|
|
43
|
+
# - `plugin_blueprints` — Phase 3a (a list of `Plugin::Blueprint` is `Ractor.shareable?`).
|
|
44
|
+
# - `explain` — a flag.
|
|
44
45
|
# - `synthetic_method_index` / `project_patched_methods` / `project_scope_seed` — optional (default `nil`
|
|
45
46
|
# / `{}`). NOT `Ractor.shareable?` (the seed tables carry Prism def nodes), so the Ractor pool path
|
|
46
47
|
# leaves them unset; the fork backend (ADR-15 Amendment), which builds the session pre-fork on the
|
|
@@ -109,7 +110,7 @@ module Rigor
|
|
|
109
110
|
# above: a worker and the parent agree without a flag to keep in sync.
|
|
110
111
|
@effect_attribution = Effects::Attribution.build(configuration.effects_attribution)
|
|
111
112
|
@file_effects = {}
|
|
112
|
-
# ADR-32 WD4 — full project file list (frozen
|
|
113
|
+
# ADR-32 WD4 — full project file list (frozen) for env-build-time invocation of any
|
|
113
114
|
# loaded plugin's `source_rbs_synthesizer` callable.
|
|
114
115
|
@source_files = source_files
|
|
115
116
|
# #392 — the run's template units, synthesised on the PARENT before the fork and inherited here as
|
|
@@ -162,12 +163,20 @@ module Rigor
|
|
|
162
163
|
end
|
|
163
164
|
|
|
164
165
|
# Equivalent of {Rigor::Analysis::Runner#analyze_file} + `plugin_emitted_diagnostics` +
|
|
165
|
-
# `explain_diagnostics`. Returns a flat
|
|
166
|
+
# `explain_diagnostics`. Returns a flat list of diagnostics for the file. Severity profile re-stamping
|
|
166
167
|
# is intentionally NOT applied — that is a per-run aggregate concern handled by the caller. When
|
|
167
168
|
# `record_dependencies:` was set, wraps the analysis in a {DependencyRecorder} window (ADR-46) so the
|
|
168
169
|
# worker captures the file's cross-file reads for {#drain_dependencies}; the recorder's own disabled
|
|
169
170
|
# fast path makes the unwrapped case free.
|
|
170
171
|
def analyze(path)
|
|
172
|
+
diagnostics = analyze_attributed(path)
|
|
173
|
+
return diagnostics unless Inference::MemoAudit.enabled?
|
|
174
|
+
|
|
175
|
+
# ADR-129 WD5 (#2785) — the audit's mismatches this file raised, as `Runner#analyze_file` reports them.
|
|
176
|
+
CrashSignature.with_swallowed(path, diagnostics, Inference::MemoAudit.drain)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def analyze_attributed(path)
|
|
171
180
|
return analyze_with_effects(path) unless @record_dependencies
|
|
172
181
|
|
|
173
182
|
diagnostics = nil
|
|
@@ -203,6 +212,7 @@ module Rigor
|
|
|
203
212
|
diagnostics
|
|
204
213
|
end
|
|
205
214
|
private :analyze_with_effects
|
|
215
|
+
private :analyze_attributed
|
|
206
216
|
|
|
207
217
|
# ADR-103 WD6 / #386 — the worker-side mirror of `Runner#effect_envelope_index`. Derived from the
|
|
208
218
|
# same configuration and the session's own environment, so a worker's `≤` lane is the one the
|
|
@@ -226,6 +236,20 @@ module Rigor
|
|
|
226
236
|
end
|
|
227
237
|
private :effect_envelope_index
|
|
228
238
|
|
|
239
|
+
# The scope a file's analysis starts from: the project seed, with its template units.
|
|
240
|
+
def seeded_scope(path)
|
|
241
|
+
@template_units.seed(seed_project_scope(Scope.empty(environment: @environment, source_path: path)), path)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# The main pass over `root`, which the ADR-129 stage-3 shadow ({TypeOfMemo}) counts apart from the rule walk
|
|
245
|
+
# that follows it.
|
|
246
|
+
def index_main_pass(root, scope)
|
|
247
|
+
TypeOfMemo.begin_file
|
|
248
|
+
index = Inference::ScopeIndexer.index(root, default_scope: scope, widen_clauses: true)
|
|
249
|
+
TypeOfMemo.phase!(:rule)
|
|
250
|
+
index
|
|
251
|
+
end
|
|
252
|
+
|
|
229
253
|
def analyze_body(path)
|
|
230
254
|
parse_result = parse_source(path)
|
|
231
255
|
unless parse_result.errors.empty?
|
|
@@ -236,12 +260,10 @@ module Rigor
|
|
|
236
260
|
|
|
237
261
|
root = parse_result.value
|
|
238
262
|
Effects::Collector.record_root(root)
|
|
239
|
-
scope =
|
|
240
|
-
|
|
241
|
-
)
|
|
242
|
-
index = Inference::ScopeIndexer.index(root, default_scope: scope, widen_clauses: true)
|
|
263
|
+
scope = seeded_scope(path)
|
|
264
|
+
index = index_main_pass(root, scope)
|
|
243
265
|
# ADR-53 B4 — built-in collectors + plugin node rules share one walk.
|
|
244
|
-
node_collectors =
|
|
266
|
+
node_collectors = built_in_collectors(path, index, root)
|
|
245
267
|
node_results = node_rule_results_by_plugin(path, root, scope, node_collectors, index)
|
|
246
268
|
diagnostics = CheckRules.diagnose(
|
|
247
269
|
path: path,
|
|
@@ -257,11 +279,21 @@ module Rigor
|
|
|
257
279
|
diagnostics + explain_diagnostics(path, parse_result.value, scope)
|
|
258
280
|
rescue Errno::ENOENT => e
|
|
259
281
|
[analyzer_error(path, e.message)]
|
|
260
|
-
rescue StandardError => e
|
|
261
|
-
[analyzer_error(path, CrashSignature.
|
|
282
|
+
rescue StandardError, SystemStackError => e
|
|
283
|
+
[analyzer_error(path, CrashSignature.contained_message!(e, parse_result))]
|
|
284
|
+
ensure
|
|
285
|
+
TypeOfMemo.end_file
|
|
262
286
|
end
|
|
263
287
|
private :analyze_body
|
|
264
288
|
|
|
289
|
+
# The built-in collectors for one file; `plugin.api-surface`'s joins only when the rule can report.
|
|
290
|
+
def built_in_collectors(path, index, root)
|
|
291
|
+
CheckRules.build_node_collectors(
|
|
292
|
+
path, index, root, plugin_api_surface: CheckRules::PluginApiSurface.active?(@configuration)
|
|
293
|
+
)
|
|
294
|
+
end
|
|
295
|
+
private :built_in_collectors
|
|
296
|
+
|
|
265
297
|
# Read-once snapshot of the per-worker reporters so the caller (or the eventual Phase 4b pool
|
|
266
298
|
# aggregator) can merge into a single coordinator-side reporter. Both reporters dedupe at write time,
|
|
267
299
|
# so a post-hoc concat + de-dup at the entry-key level is sound.
|
|
@@ -271,7 +303,7 @@ module Rigor
|
|
|
271
303
|
# definition and never enters the failing build; a diagnostic wired off the parent's loader would
|
|
272
304
|
# appear at `--workers=0` and vanish at `--workers=N`, which is the same "reports less depending on
|
|
273
305
|
# how you ran it" defect the diagnostic exists to end. Draining it out of the workers is what makes
|
|
274
|
-
# the two paths say the same thing. The payload is
|
|
306
|
+
# the two paths say the same thing. The payload is a list of plain tuples —
|
|
275
307
|
# Marshal-clean for the fork backend and shareable for the Ractor one.
|
|
276
308
|
#
|
|
277
309
|
# Issue #784 — `hkt_scan_failure` rides the same channel for the same reason: the PARENT's own
|
|
@@ -284,33 +316,25 @@ module Rigor
|
|
|
284
316
|
# project whose `sig/` produced a single such event killed each worker HERE — after its files were
|
|
285
317
|
# analysed — and the run degraded to in-process re-analysis with a `pool-degraded` row. All three
|
|
286
318
|
# streams now carry `(path, line, column)` primitives.
|
|
319
|
+
#
|
|
320
|
+
# ADR-116 WD3 (#1195) — both halves are declared rather than listed here: each reporter snapshots its
|
|
321
|
+
# own streams ({Runner::RunLevelFacts::REPORTERS}), and the `:analysis` facts come from
|
|
322
|
+
# {Runner::RunLevelFacts.drain}, the same read the coordinator makes of an environment it analysed on.
|
|
323
|
+
# The facts are read first: their HKT demand (#784, made once per worker so a worker whose share of
|
|
324
|
+
# files demanded nothing still reports the run's outcome) is what fills the hkt-directive stream (#785).
|
|
325
|
+
# On a worker that analysed a file the demand is a memoised read; the fork backend never hands a worker
|
|
326
|
+
# an empty slice, so no idle worker pays the env load.
|
|
287
327
|
def drain_reporters
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
@
|
|
295
|
-
|
|
296
|
-
rbs_extended: {
|
|
297
|
-
unresolved_payloads: @rbs_extended_reporter.unresolved_payloads,
|
|
298
|
-
lossy_projections: @rbs_extended_reporter.lossy_projections,
|
|
299
|
-
# Issue #785 — the HKT directive stream rides the same channel for the same reason
|
|
300
|
-
# `hkt_scan_failure` does: the directives are read by the registry scan, and under the pool the
|
|
301
|
-
# PARENT never demands that scan, so a diagnostic wired off the parent's reporter would appear
|
|
302
|
-
# at `--workers=0` and vanish at `--workers=N`. The demand above is what fills this.
|
|
303
|
-
hkt_directive_errors: @rbs_extended_reporter.hkt_directive_errors,
|
|
304
|
-
# ADR-109 WD3 — the deprecated-form stream rides the same channel: the payload is read where
|
|
305
|
-
# the annotated method is dispatched, which under the pool is only ever inside a worker.
|
|
306
|
-
deprecated_forms: @rbs_extended_reporter.deprecated_forms
|
|
307
|
-
},
|
|
308
|
-
boundary_cross: @boundary_cross_reporter.entries,
|
|
309
|
-
source_rbs_synthesis: @source_rbs_synthesis_reporter.entries,
|
|
310
|
-
definition_build_failures: @environment&.rbs_loader&.definition_build_failures || [],
|
|
311
|
-
hkt_scan_failure: @environment&.hkt_scan_failure
|
|
312
|
-
}
|
|
328
|
+
facts = Runner::RunLevelFacts.drain(@environment)
|
|
329
|
+
Runner::RunLevelFacts.snapshot_reporters(reporters).merge(facts)
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# The per-worker reporter accumulators, by {Runner::RunLevelFacts::REPORTERS} key.
|
|
333
|
+
def reporters
|
|
334
|
+
{ rbs_extended: @rbs_extended_reporter, boundary_cross: @boundary_cross_reporter,
|
|
335
|
+
source_rbs_synthesis: @source_rbs_synthesis_reporter }
|
|
313
336
|
end
|
|
337
|
+
private :reporters
|
|
314
338
|
|
|
315
339
|
# ADR-46 — the per-file {DependencyRecorder::Record}s captured by this session's `#analyze` calls (empty
|
|
316
340
|
# unless `record_dependencies:` was set). Marshal-clean (Data of frozen Sets / String Hashes), so the
|
|
@@ -426,40 +450,10 @@ module Rigor
|
|
|
426
450
|
Prism.parse(File.read(physical), filepath: path, version: @configuration.target_ruby)
|
|
427
451
|
end
|
|
428
452
|
|
|
429
|
-
#
|
|
430
|
-
#
|
|
453
|
+
# {Rigor::Plugin::TrustPolicy.for_configuration} is the single derivation `rigor check`, pooled
|
|
454
|
+
# workers and `rigor unused`'s plugin roots share (#2586); configuration is already Ractor-shareable.
|
|
431
455
|
def build_trust_policy
|
|
432
|
-
|
|
433
|
-
roots = [Dir.pwd]
|
|
434
|
-
Array(@configuration.signature_paths).each { |sp| roots << File.absolute_path(sp) }
|
|
435
|
-
trusted_gems.each do |gem_name|
|
|
436
|
-
path = trusted_gem_root(gem_name)
|
|
437
|
-
roots << path if path
|
|
438
|
-
end
|
|
439
|
-
@configuration.plugins_io_allowed_paths.each { |p| roots << File.absolute_path(p) }
|
|
440
|
-
|
|
441
|
-
Plugin::TrustPolicy.new(
|
|
442
|
-
trusted_gems: trusted_gems,
|
|
443
|
-
allowed_read_roots: roots,
|
|
444
|
-
network_policy: @configuration.plugins_io_network,
|
|
445
|
-
allowed_url_hosts: @configuration.plugins_io_allowed_url_hosts
|
|
446
|
-
)
|
|
447
|
-
end
|
|
448
|
-
|
|
449
|
-
def trusted_gem_name(entry)
|
|
450
|
-
case entry
|
|
451
|
-
when String then entry
|
|
452
|
-
when Hash then entry["gem"] || entry["id"]
|
|
453
|
-
end
|
|
454
|
-
end
|
|
455
|
-
|
|
456
|
-
def trusted_gem_root(gem_name)
|
|
457
|
-
return nil if gem_name.nil? || gem_name.empty?
|
|
458
|
-
|
|
459
|
-
spec = Gem.loaded_specs[gem_name]
|
|
460
|
-
spec&.full_gem_path # rigor:disable undefined-method
|
|
461
|
-
rescue StandardError
|
|
462
|
-
nil
|
|
456
|
+
Plugin::TrustPolicy.for_configuration(@configuration)
|
|
463
457
|
end
|
|
464
458
|
|
|
465
459
|
def run_plugin_prepare
|
|
@@ -480,7 +474,7 @@ module Rigor
|
|
|
480
474
|
def plugin_prepare_error_diagnostic(plugin, error)
|
|
481
475
|
plugin_id = safe_plugin_id(plugin)
|
|
482
476
|
Diagnostic.new(
|
|
483
|
-
path:
|
|
477
|
+
path: @configuration.config_display_path,
|
|
484
478
|
line: 1,
|
|
485
479
|
column: 1,
|
|
486
480
|
message: "plugin #{plugin_id.inspect} raised during prepare: " \
|
data/lib/rigor/bleeding_edge.rb
CHANGED
|
@@ -9,11 +9,9 @@ module Rigor
|
|
|
9
9
|
# *today's* rules are) and is versioned with the gem, NOT a user-supplied file: the
|
|
10
10
|
# inspectable counterpart to PHPStan's `bleedingEdge` include.
|
|
11
11
|
#
|
|
12
|
-
# The
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# {FEATURES} entry with no engine plumbing — as the first one,
|
|
16
|
-
# `reject-unparseable-signatures`, does.
|
|
12
|
+
# The surface is wired end-to-end (`bleeding_edge:` config, `rigor show-bleedingedge`, the
|
|
13
|
+
# severity-composition hook in {Configuration::SeverityProfile.resolve}), so a *severity*
|
|
14
|
+
# discipline is a single {FEATURES} entry with no engine plumbing.
|
|
17
15
|
#
|
|
18
16
|
# A queued change whose effect is not a severity move — a measurement, an algorithm, or a
|
|
19
17
|
# default that changes while every rule keeps its severity — is a `:behaviour` feature
|
|
@@ -40,7 +38,6 @@ module Rigor
|
|
|
40
38
|
# {Configuration#bleeding_edge_active?}.
|
|
41
39
|
KINDS = %i[severity behaviour].freeze
|
|
42
40
|
|
|
43
|
-
# The severity map a `:behaviour` feature carries: none.
|
|
44
41
|
NO_SEVERITY_OVERRIDES = {}.freeze
|
|
45
42
|
|
|
46
43
|
# One queued change.
|
|
@@ -129,6 +126,20 @@ module Rigor
|
|
|
129
126
|
"static.value-use.void" => :warning
|
|
130
127
|
}.freeze
|
|
131
128
|
),
|
|
129
|
+
# ADR-128 WD6 / ADR-130 slice 2 (#2686). Off by default because a new required diagnostic is an ADR-50
|
|
130
|
+
# Decision 3 new discipline; it graduates at the next hard break.
|
|
131
|
+
Feature.new(
|
|
132
|
+
id: "plugin-api-surface",
|
|
133
|
+
kind: :severity,
|
|
134
|
+
summary: "In plugin source (code inside a class that inherits `Rigor::Plugin::Base`), a call on a value " \
|
|
135
|
+
"typed by a `Rigor::Plugin` interface (`_Scope`, `_Environment`, `_Services`, ...) to a member " \
|
|
136
|
+
"the interface does not declare becomes a `:warning` (`plugin.api-surface`). The engine object " \
|
|
137
|
+
"answers such a call today, so it is not `call.undefined-method`; it is outside the plugin API " \
|
|
138
|
+
"Rigor promises to keep (ADR-128).",
|
|
139
|
+
severity_overrides: {
|
|
140
|
+
"plugin.api-surface" => :warning
|
|
141
|
+
}.freeze
|
|
142
|
+
),
|
|
132
143
|
Feature.new(
|
|
133
144
|
id: "discovery-seeded-mutation-sites",
|
|
134
145
|
kind: :behaviour,
|
|
@@ -159,7 +170,7 @@ module Rigor
|
|
|
159
170
|
"kills — every surviving breakage there is one the analyzer reports nowhere at all, not one " \
|
|
160
171
|
"it reports in a caller."
|
|
161
172
|
),
|
|
162
|
-
# ADR-103 WD15 — the owner-ruled preview of the v0.
|
|
173
|
+
# ADR-103 WD15 — the owner-ruled preview of the v0.5.0 default. `:behaviour` because it moves no rule's
|
|
163
174
|
# severity; safe under the header comment's cache-identity rule for a reason specific to this feature
|
|
164
175
|
# rather than the generic WD13 argument, so it is spelled out here: `effects:` collection is
|
|
165
176
|
# OBSERVATIONAL (ADR-103 WD13) and the `effects:` block itself is deliberately absent from the
|
|
@@ -177,9 +188,10 @@ module Rigor
|
|
|
177
188
|
"it had written `effects: {}` — effect collection, the `rigor effects` verbs' cache sharing, " \
|
|
178
189
|
"and `effects.check` all turn on with every sub-key at its default. Writing `effects: false` " \
|
|
179
190
|
"explicitly still opts out, and a project that writes its own `effects:` block keeps that " \
|
|
180
|
-
"block's shape untouched either way. Graduates to default-on at v0.
|
|
181
|
-
"2026-08-17): ADR-50 § WD7 reads \"at a major\" as
|
|
182
|
-
"evaluation line. See ADR-103 § WD15
|
|
191
|
+
"block's shape untouched either way. Graduates to default-on at v0.5.0 (owner ruling, " \
|
|
192
|
+
"2026-10-26, moving the v0.4.0 date of 2026-08-17): ADR-50 § WD7 reads \"at a major\" as the " \
|
|
193
|
+
"version that ruling names, for this feature on the 0.x evaluation line. See ADR-103 § WD15 " \
|
|
194
|
+
"for the preconditions that gate the flip and § WD18 for the move."
|
|
183
195
|
)
|
|
184
196
|
].freeze
|
|
185
197
|
|
|
@@ -113,9 +113,8 @@ module Rigor
|
|
|
113
113
|
},
|
|
114
114
|
# ADR-13 § "Canonical type-function additions" — five shape-projection type functions
|
|
115
115
|
# that the `rigor-typescript-utility-types` plugin (and any other plugin that ships a
|
|
116
|
-
# shape-projection vocabulary) maps onto.
|
|
117
|
-
#
|
|
118
|
-
# in slice 5).
|
|
116
|
+
# shape-projection vocabulary) maps onto. Non-shape inputs return the input unchanged;
|
|
117
|
+
# the Resolver records `dynamic.shape.lossy-projection` for them.
|
|
119
118
|
"pick_of" => lambda { |args|
|
|
120
119
|
return nil unless args.size == 2
|
|
121
120
|
|
|
@@ -148,7 +147,7 @@ module Rigor
|
|
|
148
147
|
# `Class[range]` — a numeric class head bounded by a Ruby range literal (ADR-109). The
|
|
149
148
|
# builder receives the `Range` value and returns the carrier, or `nil` when the range is
|
|
150
149
|
# empty or its endpoints are not literals of the head class; `nil` surfaces as the ordinary
|
|
151
|
-
# unresolved-payload diagnostic. `Float`
|
|
150
|
+
# unresolved-payload diagnostic. `Float` builds a `FloatRange` carrier.
|
|
152
151
|
RANGE_HEAD_BUILDERS = {
|
|
153
152
|
"Integer" => lambda { |range|
|
|
154
153
|
lo = range.begin
|
|
@@ -186,8 +185,7 @@ module Rigor
|
|
|
186
185
|
# `Array<Integer>` and returns a `Rigor::Type` (or `nil`). Bounds are signed integer
|
|
187
186
|
# literals. A reversed pair (`min` > `max`) is declined as `nil` like every other shape
|
|
188
187
|
# mismatch, so the caller surfaces `dynamic.rbs-extended.unresolved` at the annotation;
|
|
189
|
-
# `Type::IntegerRange`
|
|
190
|
-
# `internal analyzer error` that abandoned the whole Ruby file.
|
|
188
|
+
# `Type::IntegerRange` would raise on it instead, which must not escape the analyzer.
|
|
191
189
|
PARAMETERISED_INT_BUILDERS = {
|
|
192
190
|
"int" => lambda { |bounds|
|
|
193
191
|
return nil unless bounds.size == 2
|
|
@@ -276,14 +274,14 @@ module Rigor
|
|
|
276
274
|
# grammar:
|
|
277
275
|
#
|
|
278
276
|
# type := simple_name | parametric
|
|
279
|
-
# simple_name := /[a-z][a-z0-
|
|
277
|
+
# simple_name := /[a-z][a-z0-9_-]*/
|
|
280
278
|
# parametric := simple_name '[' type_arg_list ']'
|
|
281
279
|
# | simple_name '<' int_bound_list '>'
|
|
282
280
|
# type_arg_list := type_arg (',' type_arg)*
|
|
283
281
|
# type_arg := range_literal | type | class_name
|
|
284
282
|
# class_name := /[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*/
|
|
285
283
|
# range_literal := endpoint? ('..' | '...') endpoint? (at least one side written)
|
|
286
|
-
# endpoint := signed_int | 'nil'
|
|
284
|
+
# endpoint := signed_int | float_literal | 'nil' | 'Float::INFINITY' | 'Float::MAX'
|
|
287
285
|
# int_bound_list := signed_int (',' signed_int)*
|
|
288
286
|
# signed_int := /-?\d+/
|
|
289
287
|
#
|
|
@@ -62,7 +62,7 @@ module Rigor
|
|
|
62
62
|
# `RBS::VERSION` while Rigor checks itself, rubygems and Bundler internals while it checks
|
|
63
63
|
# CRuby's `lib/` — and that is worse than no answer: identical source would type differently
|
|
64
64
|
# depending on how the analyzer was installed. Removing an ad hoc `Object.const_get` from an
|
|
65
|
-
# analysis path is the same move ADR-4
|
|
65
|
+
# analysis path is the same move ADR-4 already made for predicate narrowing.
|
|
66
66
|
#
|
|
67
67
|
# This module is consulted by `Environment#constant_for_name` BEFORE the RBS
|
|
68
68
|
# constant-type table (widest types) but AFTER in-source constant writes (the user's own
|
|
@@ -8,13 +8,11 @@ module Rigor
|
|
|
8
8
|
# carriers Rigor already ships (`decimal-int-string`, `hex-int-string`,
|
|
9
9
|
# `octal-int-string`, `lowercase-string`, `uppercase-string`, `numeric-string`). See
|
|
10
10
|
# `docs/type-specification/imported-built-in-types.md` for the registry the refinements
|
|
11
|
-
# come from
|
|
12
|
-
# scope of this recogniser.
|
|
11
|
+
# come from.
|
|
13
12
|
#
|
|
14
|
-
# The
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# whenever the named-capture body matches one of the rows in {RULES}.
|
|
13
|
+
# The consumer is `Inference::Narrowing.analyse_match_write`: given `if /(?<year>\d+)/ =~ str;
|
|
14
|
+
# year; end`, `year` narrows to `decimal-int-string` when the named-capture body matches a row
|
|
15
|
+
# in {RULES}, and stays plain `String` otherwise.
|
|
18
16
|
#
|
|
19
17
|
# Recognised body shapes (each row admits the `+` quantifier and the bounded `{n}` /
|
|
20
18
|
# `{n,m}` forms with `n >= 1`):
|
|
@@ -10,7 +10,8 @@ module Rigor
|
|
|
10
10
|
module Cache
|
|
11
11
|
# Cache invalidation descriptor — the typed-slot schema fixed by
|
|
12
12
|
# [`docs/design/20260505-cache-slice-taxonomy.md`](../../../docs/design/20260505-cache-slice-taxonomy.md).
|
|
13
|
-
#
|
|
13
|
+
# Value object, fully immutable after construction. Filesystem reads happen only in the `FileEntry.stat`,
|
|
14
|
+
# `FileEntry.kind` and `GlobEntry.compute` builders and in {#fresh?}. The storage layer
|
|
14
15
|
# ([`Rigor::Cache::Store`](store.rb), v0.0.8 slice 2) consumes descriptors but does not extend them.
|
|
15
16
|
#
|
|
16
17
|
# The descriptor has six slots (`files`, `gems`, `plugins`, `configs`, `dependencies`, `globs`); every slot is
|
|
@@ -462,10 +463,10 @@ module Rigor
|
|
|
462
463
|
|
|
463
464
|
# ADR-45 — re-validates this descriptor's recorded {FileEntry}s against the current filesystem. Used by
|
|
464
465
|
# the record-and-validate run-result cache: a value cached alongside its dependency descriptor is fresh
|
|
465
|
-
# iff every recorded file still matches. Only `files` are checked — non-file inputs (config / gems /
|
|
466
|
+
# iff every recorded file still matches. Only `files` and `globs` are checked — non-file inputs (config / gems /
|
|
466
467
|
# version) belong in the cache *key*, not the validated dependency set — so a descriptor carrying any
|
|
467
468
|
# non-file slot is never considered fresh (it was built wrong for this use). ADR-60 WD3 adds `globs`
|
|
468
|
-
# alongside `files` as a re-validatable slot: a {GlobEntry} is fresh when re-globbing
|
|
469
|
+
# alongside `files` as a re-validatable slot: a {GlobEntry} is fresh when re-globbing
|
|
469
470
|
# reproduces its recorded value. ADR-45 WD1 (#577): an absence row ({FileEntry.absent}) is fresh
|
|
470
471
|
# while its path is still missing — the negative half of the dependency set.
|
|
471
472
|
def fresh?
|
|
@@ -581,8 +582,8 @@ module Rigor
|
|
|
581
582
|
false
|
|
582
583
|
end
|
|
583
584
|
|
|
584
|
-
# ADR-60 WD3 / ADR-87 WD2 —
|
|
585
|
-
#
|
|
585
|
+
# ADR-60 WD3 / ADR-87 WD2 — recomputes the entry's signature over the live tree and compares it. Any
|
|
586
|
+
# failure reads as stale (recompute), never a crash.
|
|
586
587
|
def glob_entry_fresh?(entry)
|
|
587
588
|
GlobEntry.fresh?(entry)
|
|
588
589
|
end
|