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
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
4
|
class Environment
|
|
5
|
-
# Frozen
|
|
5
|
+
# Frozen read-only RBS query facade.
|
|
6
6
|
# [ADR-15](../../../docs/adr/15-ractor-concurrency.md) Phase 2b extracts the read-only surface of
|
|
7
7
|
# {RbsLoader} into this carrier so future Ractor-isolated workers can share one Reflection across the
|
|
8
8
|
# pool while keeping the per-Ractor mutable accelerator state (per-process memo Hashes) where it belongs.
|
|
9
9
|
#
|
|
10
10
|
# Backing tables (all frozen at construction):
|
|
11
11
|
#
|
|
12
|
-
# - `known_class_names` —
|
|
13
|
-
#
|
|
14
|
-
# - `instance_definitions` — `
|
|
12
|
+
# - `known_class_names` — every class / module / alias name in the loaded RBS environment.
|
|
13
|
+
# Top-level prefixed (`"::Hash"`); the query methods accept either form.
|
|
14
|
+
# - `instance_definitions` — `RBS::Definition` per class, keyed on `RBS::TypeName#to_s` (top-level
|
|
15
15
|
# prefixed).
|
|
16
16
|
# - `singleton_definitions` — same shape, singleton side.
|
|
17
|
-
# - `type_param_names` —
|
|
18
|
-
# - `constant_types` —
|
|
19
|
-
# - `ancestor_names` —
|
|
17
|
+
# - `type_param_names` — declared type parameters per class.
|
|
18
|
+
# - `constant_types` — translated constant declarations.
|
|
19
|
+
# - `ancestor_names` — normalised ancestor chains per class.
|
|
20
20
|
#
|
|
21
21
|
# Each `Reflection` instance is `frozen?` at construction — every cached table is frozen, `self` is
|
|
22
22
|
# frozen. **NOT** `Ractor.shareable?`: the `instance_definitions` / `singleton_definitions` tables hold
|
|
@@ -296,17 +296,14 @@ module Rigor
|
|
|
296
296
|
name.start_with?(TOKEN_PREFIX) ? name.delete_prefix(TOKEN_PREFIX) : nil
|
|
297
297
|
end
|
|
298
298
|
|
|
299
|
-
# The vendored directory basenames a library list activates.
|
|
300
299
|
def active_dirs(library_names)
|
|
301
300
|
library_names.filter_map { |name| VENDORED_DIRS[feature_of_token(name)] }
|
|
302
301
|
end
|
|
303
302
|
|
|
304
|
-
# Whether `dir_basename` is one of the gated directories.
|
|
305
303
|
def gated_dir?(dir_basename)
|
|
306
304
|
VENDORED_DIRS.value?(dir_basename)
|
|
307
305
|
end
|
|
308
306
|
|
|
309
|
-
# The feature a gated directory loads for.
|
|
310
307
|
def feature_for_dir(dir_basename)
|
|
311
308
|
VENDORED_DIRS.key(dir_basename)
|
|
312
309
|
end
|
|
@@ -28,7 +28,7 @@ module Rigor
|
|
|
28
28
|
#
|
|
29
29
|
# The directories are resolved at load time, on the main Ractor: `RbConfig::CONFIG` and `Gem.default_dir`
|
|
30
30
|
# read non-shareable constants and raise `Ractor::IsolationError` inside a pool worker. The scan itself runs
|
|
31
|
-
# lazily (about 0.1 s), memoised per
|
|
31
|
+
# lazily (about 0.1 s), memoised per process, and only for a class about to be reported.
|
|
32
32
|
module RubyLibraryRoots
|
|
33
33
|
STDLIB_ROOT = begin
|
|
34
34
|
::RBS::Repository::DEFAULT_STDLIB_ROOT.to_s.dup.freeze
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbs"
|
|
4
|
+
require_relative "../rooted_glob"
|
|
5
|
+
require_relative "gated_signature_plan"
|
|
6
|
+
|
|
7
|
+
module Rigor
|
|
8
|
+
class Environment
|
|
9
|
+
# Issue #2470 — a `data/vendored_gem_sigs/<gem>/` member another signature source also declares stands down,
|
|
10
|
+
# so the other source's declaration binds instead of the two failing the class's definition build.
|
|
11
|
+
#
|
|
12
|
+
# The vendored directories load on `RBS::EnvironmentLoader`'s batch path, ahead of the project's
|
|
13
|
+
# `signature_paths:` (its own `sig/`, an `rbs collection install`, a gem's `sig/`). A file there that reopens
|
|
14
|
+
# a vendored class and declares one of its methods again — the activerecord 8.1 collection's `patch.rbs`
|
|
15
|
+
# writes `def async_exec` on `PG::Connection`, where the vendored `pg.rbs` has `alias async_exec exec` — made
|
|
16
|
+
# `RBS::DefinitionBuilder` raise `DuplicatedMethodDefinitionError` for the class, which Rigor keeps known, so
|
|
17
|
+
# every call into it read `Dynamic[top]`.
|
|
18
|
+
#
|
|
19
|
+
# {.build} is the #1713 member rule ({GatedSignaturePlan}) applied to the ungated directories, planned from
|
|
20
|
+
# the signature files themselves rather than from a trial build: the vendored copy is Rigor's guess at a gem's
|
|
21
|
+
# surface, and the project chose the other source, so the other source wins (`RbsLoader.build_env_for`'s
|
|
22
|
+
# stated precedence). Only a directory with a member to leave out is planned; the rest stay on the batch path.
|
|
23
|
+
# An overload continuation (`def m: ... | ...`) declares nothing of its own and keeps the vendored base.
|
|
24
|
+
#
|
|
25
|
+
# The plan is a pure function of the vendored files and the signature files, both of which the env-cache key
|
|
26
|
+
# digests, so a cold and a warm run build the same environment.
|
|
27
|
+
module VendoredSignaturePlan
|
|
28
|
+
# `dirs` — the vendored directories (Pathnames) to keep off the batch path; `sources` — their files as
|
|
29
|
+
# `[buffer, directives, decls]`, the taken members left out, to add right after the batch; `takers` — the
|
|
30
|
+
# signature files a member stood down to. A member stands down only to a file that stays in the env: the
|
|
31
|
+
# caller re-plans without each taker the build quarantined (`RbsLoader.build_env_attempt`), or the method
|
|
32
|
+
# would have no declaration at all.
|
|
33
|
+
Plan = Data.define(:dirs, :sources, :takers)
|
|
34
|
+
EMPTY = Plan.new(dirs: [].freeze, sources: [].freeze, takers: Set.new.freeze)
|
|
35
|
+
|
|
36
|
+
# A `class` / `module` header, after any `%a{...}` / `%a(...)` / `%a[...]` annotations on the same line.
|
|
37
|
+
ANNOTATED_HEADER = /^\s*(?:%a(?:\{[^}]*\}|\([^)]*\)|\[[^\]]*\])\s*)*(?:class|module)\s+(?:::)?/
|
|
38
|
+
|
|
39
|
+
module_function
|
|
40
|
+
|
|
41
|
+
# @param roots — the ungated vendored directories this build loads.
|
|
42
|
+
# @param signature_files — the absolute paths of the signature files that outrank them.
|
|
43
|
+
# @param excluded — signature files to plan without: takers a previous build of this env quarantined.
|
|
44
|
+
def build(roots, signature_files, excluded = Set.new)
|
|
45
|
+
files = signature_files.reject { |file| excluded.include?(file) }
|
|
46
|
+
return EMPTY if roots.empty? || files.empty?
|
|
47
|
+
|
|
48
|
+
parsed = roots.to_h { |root| [root, parsed_sources(root)] }
|
|
49
|
+
taken = taken_keys(files, header_pattern(parsed.values.flatten(1)))
|
|
50
|
+
return EMPTY if taken.empty?
|
|
51
|
+
|
|
52
|
+
takers = Set.new
|
|
53
|
+
planned = parsed.filter_map do |root, sources|
|
|
54
|
+
kept = plan_sources(sources, taken, takers)
|
|
55
|
+
[root, kept] if kept
|
|
56
|
+
end
|
|
57
|
+
return EMPTY if planned.empty?
|
|
58
|
+
|
|
59
|
+
Plan.new(dirs: planned.map(&:first), sources: planned.flat_map(&:last), takers: takers.freeze)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# A vendored directory's files, parsed, under the Pathname buffer names the loader's batch path gives them,
|
|
63
|
+
# in the set `RBS::EnvironmentLoader#add(path:)` reads: every `.rbs` under it.
|
|
64
|
+
def parsed_sources(root)
|
|
65
|
+
RootedGlob.glob(root, "**/*.rbs").sort.filter_map { |file| RbsLoader.parse_signature_file(Pathname(file)) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# `sources` with the taken members left out, or nil when nothing is taken from any of them.
|
|
69
|
+
def plan_sources(sources, taken, takers)
|
|
70
|
+
kept = sources.map do |buffer, directives, decls|
|
|
71
|
+
[buffer, directives, plan_decls(decls, nil, taken, takers)]
|
|
72
|
+
end
|
|
73
|
+
kept unless kept.zip(sources).all? { |(_, _, after), (_, _, before)| unchanged?(after, before) }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# A header naming one of the vendored top-level types, which every declaration of a vendored type (nested or
|
|
77
|
+
# `A::B`-qualified) starts from. A pre-filter only: the matches are parsed.
|
|
78
|
+
def header_pattern(parsed)
|
|
79
|
+
heads = parsed.flat_map do |_buffer, _directives, decls|
|
|
80
|
+
decls.filter_map { |decl| GatedSignaturePlan.type_declaration?(decl) && decl.name.to_s.delete_prefix("::") }
|
|
81
|
+
end
|
|
82
|
+
segments = heads.map { |name| Regexp.escape(name.split("::").first) }.uniq
|
|
83
|
+
return nil if segments.empty?
|
|
84
|
+
|
|
85
|
+
/#{ANNOTATED_HEADER}(?:#{segments.join('|')})\b/
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# `{type name => {[method, kind] => Set[file]}}` over the signature files that declare a vendored top-level
|
|
89
|
+
# type.
|
|
90
|
+
def taken_keys(signature_files, pattern)
|
|
91
|
+
taken = Hash.new { |hash, name| hash[name] = Hash.new { |keys, key| keys[key] = Set.new } }
|
|
92
|
+
return taken if pattern.nil?
|
|
93
|
+
|
|
94
|
+
signature_files.sort.each do |file|
|
|
95
|
+
text = RbsLoader.read_signature_text(file)
|
|
96
|
+
next if text.nil? || !text.match?(pattern)
|
|
97
|
+
|
|
98
|
+
decls = RbsLoader.parse_signature_source(file, text)
|
|
99
|
+
collect_keys(decls, nil, taken, file) if decls
|
|
100
|
+
end
|
|
101
|
+
taken
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def collect_keys(decls, namespace, taken, file)
|
|
105
|
+
decls.each do |decl|
|
|
106
|
+
next unless GatedSignaturePlan.type_declaration?(decl)
|
|
107
|
+
|
|
108
|
+
name = GatedSignaturePlan.qualify(namespace, decl.name)
|
|
109
|
+
decl.members.each do |member|
|
|
110
|
+
RbsLoader.member_method_keys(member).each { |key| taken[name][key] << file }
|
|
111
|
+
end
|
|
112
|
+
collect_keys(decl.members, name, taken, file)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# `decls` with every member `taken` declares for its type left out, nested types planned the same way, and
|
|
117
|
+
# the files each left-out member stood down to added to `takers`. A declaration nothing is taken from is
|
|
118
|
+
# returned as itself, which is how {.build} tells a directory unchanged.
|
|
119
|
+
def plan_decls(decls, namespace, taken, takers)
|
|
120
|
+
decls.map do |decl|
|
|
121
|
+
next decl unless GatedSignaturePlan.type_declaration?(decl)
|
|
122
|
+
|
|
123
|
+
plan_type(decl, GatedSignaturePlan.qualify(namespace, decl.name), taken, takers)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def unchanged?(after, before)
|
|
128
|
+
after.size == before.size && after.zip(before).all? { |a, b| a.equal?(b) }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def plan_type(decl, name, taken, takers)
|
|
132
|
+
keys = taken.fetch(name, nil)
|
|
133
|
+
members = decl.members.filter_map do |member|
|
|
134
|
+
if GatedSignaturePlan.type_declaration?(member)
|
|
135
|
+
plan_type(member, GatedSignaturePlan.qualify(name, member.name), taken, takers)
|
|
136
|
+
elsif keys
|
|
137
|
+
plan_member(member, keys, takers)
|
|
138
|
+
else
|
|
139
|
+
member
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
return decl if unchanged?(members, decl.members)
|
|
143
|
+
|
|
144
|
+
GatedSignaturePlan.rebuild(decl, members: members)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def plan_member(member, keys, takers)
|
|
148
|
+
RbsLoader.member_method_keys(member).each { |key| takers.merge(keys[key]) if keys.key?(key) }
|
|
149
|
+
GatedSignaturePlan.untaken(member, keys)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
data/lib/rigor/environment.rb
CHANGED
|
@@ -16,6 +16,8 @@ require_relative "environment/bundle_sig_discovery"
|
|
|
16
16
|
require_relative "environment/lockfile_resolver"
|
|
17
17
|
require_relative "environment/installed_gem_set"
|
|
18
18
|
require_relative "environment/rbs_collection_discovery"
|
|
19
|
+
require_relative "library_probe"
|
|
20
|
+
require_relative "environment/project_path_gems"
|
|
19
21
|
require_relative "environment/source_rbs_synthesis"
|
|
20
22
|
require_relative "plugin/isolation"
|
|
21
23
|
require_relative "cache/engine_source"
|
|
@@ -39,7 +41,7 @@ module Rigor
|
|
|
39
41
|
DEFAULT_PROJECT_SIG_DIR = "sig"
|
|
40
42
|
private_constant :DEFAULT_PROJECT_SIG_DIR
|
|
41
43
|
|
|
42
|
-
# `DEFAULT_LIBRARIES` is defined in the light `environment/default_libraries.rb` (required
|
|
44
|
+
# `DEFAULT_LIBRARIES` is defined in the light `environment/default_libraries.rb` (required above) so the
|
|
43
45
|
# ADR-87 WD4 boot-slimming probe can read it without loading the inference engine.
|
|
44
46
|
|
|
45
47
|
# ADR-72 — a Gemfile.lock gem name mapped to the opt-in plugin id that ships the SAME core-ext RBS. When
|
|
@@ -48,6 +50,19 @@ module Rigor
|
|
|
48
50
|
# `RbsCoverageReport` reports.
|
|
49
51
|
GEM_OVERLAY_PLUGIN_IDS = { "activesupport" => "activesupport-core-ext" }.freeze
|
|
50
52
|
|
|
53
|
+
# Issue #2857 — the `RbsCoverageReport` sources each gem's bundled overlay may load under, when they
|
|
54
|
+
# differ from the ADR-72 `:missing` default every unlisted overlay keeps. `addressable` is the first
|
|
55
|
+
# exception: its overlay exists to CORRECT the `Addressable::URI.parse` signature `rbs collection`
|
|
56
|
+
# ships (`parse(nil)` returns nil; the collection declares `(String | URI) -> URI`), so it loads only
|
|
57
|
+
# under `:rbs_collection` coverage, where the deferred-signature plan composes it over the collection
|
|
58
|
+
# copy as an overload continuation. Under `:missing` coverage — no sigs at all — it stays unloaded:
|
|
59
|
+
# the overlay's partial `Addressable::URI` declaration would make every member it omits a false
|
|
60
|
+
# `call.undefined-method`, a worse answer than the `Dynamic` silence a sig-less gem already has.
|
|
61
|
+
# Frozen arrays, not Sets: `Ractor.shareable?` rejects a Set even frozen (ractor_readiness_spec).
|
|
62
|
+
GEM_OVERLAY_COVERAGE_SOURCES = { "addressable" => [:rbs_collection].freeze }.freeze
|
|
63
|
+
GEM_OVERLAY_DEFAULT_COVERAGE_SOURCES = [:missing].freeze
|
|
64
|
+
private_constant :GEM_OVERLAY_DEFAULT_COVERAGE_SOURCES
|
|
65
|
+
|
|
51
66
|
attr_reader :class_registry, :rbs_loader, :plugin_registry, :dependency_source_index,
|
|
52
67
|
:reporters, :name_scope,
|
|
53
68
|
:synthetic_method_index, :project_patched_methods
|
|
@@ -117,6 +132,13 @@ module Rigor
|
|
|
117
132
|
# stage that failed and the other stage still runs, so this getter never raises into its callers —
|
|
118
133
|
# neither into a file's `analyze_body` rescue nor out of the run-owned demands, which have no rescue
|
|
119
134
|
# above them at all.
|
|
135
|
+
# Issue #2883 — builds the RBS environment now, if it is not built yet, so typing never builds it. A no-op for an
|
|
136
|
+
# environment with no loader. Answers the environment.
|
|
137
|
+
def prepare_for_typing!
|
|
138
|
+
rbs_loader&.prepare_for_typing!
|
|
139
|
+
self
|
|
140
|
+
end
|
|
141
|
+
|
|
120
142
|
def hkt_registry
|
|
121
143
|
@hkt_registry_holder.fetch do
|
|
122
144
|
pre_scan = pre_scan_hkt_registry
|
|
@@ -146,7 +168,7 @@ module Rigor
|
|
|
146
168
|
# code (`Plugin::Registry#hkt_overlay_registry` reads each manifest); before this it sat one line ABOVE
|
|
147
169
|
# the #784 rescue, so a raise there escaped {#hkt_registry} entirely. Post-#788 that is not a per-file
|
|
148
170
|
# crash storm but an uncaught abort: {HktRegistryHolder#fetch} memoises only on success, so the raise
|
|
149
|
-
# is re-attempted at every demand, and the run-owned demands (`Runner::
|
|
171
|
+
# is re-attempted at every demand, and the run-owned demands (`Runner::RunLevelFacts::Collect.hkt_scan_failure`
|
|
150
172
|
# after the file loop, `Analysis::WorkerSession#drain_reporters`) sit outside any rescue.
|
|
151
173
|
#
|
|
152
174
|
# The degradation is narrower than the scan's: only the plugin overlay is dropped, and the RBS scan
|
|
@@ -246,11 +268,14 @@ module Rigor
|
|
|
246
268
|
end
|
|
247
269
|
|
|
248
270
|
class << self
|
|
271
|
+
# Issue #2883 — the shared default environment is built here too, not on the first `type_of` that needs it, so
|
|
272
|
+
# code that types against it (`Scope.empty`, the narrowing defaults, the incremental session's summary
|
|
273
|
+
# evaluator) never builds it from inside typing. A non-main Ractor keeps the lazy build.
|
|
249
274
|
def default
|
|
250
275
|
@default ||= new(
|
|
251
276
|
rbs_loader: RbsLoader.default,
|
|
252
277
|
hkt_registry: Builtins::HktBuiltins.registry
|
|
253
|
-
).freeze
|
|
278
|
+
).freeze.tap { |environment| environment.prepare_for_typing! if Ractor.main? }
|
|
254
279
|
end
|
|
255
280
|
|
|
256
281
|
# Builds an Environment that consults the project's local signatures and any opt-in stdlib libraries on
|
|
@@ -265,8 +290,14 @@ module Rigor
|
|
|
265
290
|
# `nil` (the default), the canonical project layout `<root>/sig` is used if it exists, otherwise no
|
|
266
291
|
# signature path is loaded.
|
|
267
292
|
# @param cache_store — persistent cache threaded into the underlying
|
|
268
|
-
# {Environment::RbsLoader} so constant lookups
|
|
269
|
-
#
|
|
293
|
+
# {Environment::RbsLoader} so constant lookups consult the cache. Pass `nil` (the default) to skip
|
|
294
|
+
# caching for this environment.
|
|
295
|
+
# @param core_root — issue #2517 — a core signature directory loaded in place of the `rbs` gem's `core/`
|
|
296
|
+
# ({Configuration#core_root}); nil (the default) loads the gem's core.
|
|
297
|
+
# @param eager — issue #2883 — whether the RBS environment is built here, before anything types. Typing then
|
|
298
|
+
# never builds it, so the core-root Frame the build reads (ADR-129 G1') is never read inside a `type_of`. The
|
|
299
|
+
# one caller that passes `false` is the runner's pre-cache build, which a warm result-cache hit must not pay
|
|
300
|
+
# for; it calls {#prepare_for_typing!} on the analysis path.
|
|
270
301
|
# rubocop:disable-next Metrics/MethodLength, Metrics/ParameterLists
|
|
271
302
|
def for_project(root: Dir.pwd, libraries: [], signature_paths: nil, cache_store: nil, # rubocop:disable Metrics/AbcSize
|
|
272
303
|
plugin_registry: nil, dependency_source_index: nil,
|
|
@@ -276,7 +307,8 @@ module Rigor
|
|
|
276
307
|
bundler_lockfile: nil,
|
|
277
308
|
rbs_collection_lockfile: nil, rbs_collection_auto_detect: false,
|
|
278
309
|
synthetic_method_index: nil, project_patched_methods: nil,
|
|
279
|
-
source_files: [], locked_gems: nil, required_features: nil
|
|
310
|
+
source_files: [], locked_gems: nil, required_features: nil, core_root: nil,
|
|
311
|
+
paths: nil, exclude_patterns: nil, exclude_base: nil, eager: true)
|
|
280
312
|
resolved_paths = project_signature_roots(signature_paths, root: root)
|
|
281
313
|
# O4 MVP — append per-gem `sig/` directories discovered under the target project's bundler install
|
|
282
314
|
# root. Empty array when neither an explicit path nor auto-detection finds a bundle. Order: user
|
|
@@ -309,38 +341,55 @@ module Rigor
|
|
|
309
341
|
)
|
|
310
342
|
# O4 Layer 3 slice 2 — when `rbs collection install` has been run for the target project, parse the
|
|
311
343
|
# resulting `rbs_collection.lock.yaml` and feed each gem's `<collection_path>/<name>/<version>/`
|
|
312
|
-
# directory into `signature_paths:`. Stdlib-typed entries
|
|
313
|
-
#
|
|
344
|
+
# directory into `signature_paths:`. Stdlib-typed entries have no such directory; they load as libraries
|
|
345
|
+
# (issue #2946, below). Skipped too are gems whose RBS rigor already loads from another source —
|
|
314
346
|
# stdlib-extracted default gems (`cgi`, `logger`, …, shipped by the collection under a `git` source)
|
|
315
347
|
# and the `data/vendored_gem_sigs/` bundle (`redis`, `nokogiri`, `pg`, …). `skip_gem_names:` passes
|
|
316
348
|
# both sets so the collection copy doesn't double-declare against rigor's bundled RBS (the
|
|
317
349
|
# `RBS::DuplicatedDeclarationError` hazard).
|
|
318
350
|
# Issue #1700 — plus the gated vendored directories this run's source activates ({#feature_tokens}).
|
|
319
|
-
|
|
351
|
+
# Issue #2946 — plus the lockfile's `source: { type: stdlib }` entries, as libraries ({BaseLibraries.resolve}).
|
|
352
|
+
merged_libraries = (BaseLibraries.resolve(libraries, rbs_collection_lockfile: rbs_collection_lockfile,
|
|
353
|
+
rbs_collection_auto_detect: rbs_collection_auto_detect,
|
|
354
|
+
root: root) +
|
|
320
355
|
feature_tokens(required_features, source_files, libraries)).uniq
|
|
321
|
-
|
|
356
|
+
# Issue #2441 — plus the project's own path gems ({ProjectPathGems}), whose collection copy would
|
|
357
|
+
# double-declare the project's `sig/`.
|
|
358
|
+
project_gems = ProjectPathGems.names(locked, paths: paths, root: root, exclude_patterns: exclude_patterns,
|
|
359
|
+
exclude_base: exclude_base || root)
|
|
360
|
+
skip_gem_names = collection_skip_gem_names(merged_libraries) + project_gems.to_a
|
|
322
361
|
collection_paths = RbsCollectionDiscovery.discover(
|
|
323
362
|
lockfile_path: rbs_collection_lockfile,
|
|
324
363
|
project_root: root,
|
|
325
364
|
auto_detect: rbs_collection_auto_detect,
|
|
326
365
|
skip_gem_names: skip_gem_names
|
|
327
366
|
).map(&:to_s)
|
|
367
|
+
# Issue #3030 — a gem the project's `signature_paths:` already loads a copy of (a gem_rbs_collection working
|
|
368
|
+
# tree next to its `_test/` lockfile) loads from there alone. The coverage classification below still sees
|
|
369
|
+
# the whole list: the gem has RBS either way.
|
|
370
|
+
covered_collection_paths = collection_paths
|
|
371
|
+
collection_paths = RbsCollectionDiscovery.without_signature_path_copies(collection_paths, resolved_paths)
|
|
372
|
+
# Issue #2978 — the collection copies of the locked gems whose own `sig/` the bundle discovery loaded.
|
|
373
|
+
behind_gem_sig_paths = collection_paths_behind_gem_sigs(collection_paths, gem_sig_paths, locked)
|
|
328
374
|
# ADR-25 — RBS signature directories contributed by loaded plugins via their manifest
|
|
329
375
|
# `signature_paths:`. Resolved to absolute dirs by `Plugin::Base#signature_paths`; additive, ranked
|
|
330
376
|
# below the user's explicit `signature_paths:` and above the opportunistic bundle / collection
|
|
331
377
|
# discovery. A duplicate-declaration conflict degrades through the same O7 failure-memo path.
|
|
332
378
|
plugin_sig_paths = plugin_registry ? plugin_registry.signature_paths.map(&:to_s) : []
|
|
333
|
-
# ADR-72 — Gemfile.lock-gated bundled RBS overlays. For each locked gem
|
|
334
|
-
#
|
|
335
|
-
#
|
|
336
|
-
#
|
|
337
|
-
#
|
|
338
|
-
#
|
|
339
|
-
#
|
|
340
|
-
#
|
|
379
|
+
# ADR-72 — Gemfile.lock-gated bundled RBS overlays. For each locked gem whose coverage source its
|
|
380
|
+
# overlay may load under ({GEM_OVERLAY_COVERAGE_SOURCES} — `:missing` for every overlay but
|
|
381
|
+
# addressable's `:rbs_collection` correction, #2857) and that has a Rigor-bundled overlay, load that
|
|
382
|
+
# overlay so its core-class extensions resolve (e.g. `Integer#minutes` on a Rails project) —
|
|
383
|
+
# turning a systematic false `call.undefined-method` into a no-op while a project WITHOUT the gem
|
|
384
|
+
# still sees the genuine diagnostic. Appended last so any RBS the project already supplies wins,
|
|
385
|
+
# and skipped for a gem whose opt-in plugin twin is REACHABLE — loaded as a plugin, or wired in by
|
|
386
|
+
# `signature_paths:` (#672) — so the two never both declare the methods. The paths ride in
|
|
387
|
+
# `loader_signature_paths`, so the env cache descriptor digests them for free.
|
|
388
|
+
# Issue #2441 — the project's own path gems are neither missing RBS nor overlay-eligible: the project's
|
|
389
|
+
# `sig/` declares them, and an overlay (`data/gem_overlay/activesupport`) would collide with it.
|
|
341
390
|
missing_gems, overlay_paths = missing_gems_and_overlay_paths(
|
|
342
|
-
locked: locked, default_libraries: merged_libraries, bundle_sig_paths: gem_sig_paths,
|
|
343
|
-
rbs_collection_paths:
|
|
391
|
+
locked: locked.except(*project_gems), default_libraries: merged_libraries, bundle_sig_paths: gem_sig_paths,
|
|
392
|
+
rbs_collection_paths: covered_collection_paths, plugin_registry: plugin_registry,
|
|
344
393
|
signature_paths: resolved_paths, bundle_root: bundle_root
|
|
345
394
|
)
|
|
346
395
|
loader_signature_paths = resolved_paths + plugin_sig_paths + gem_sig_paths +
|
|
@@ -364,9 +413,19 @@ module Rigor
|
|
|
364
413
|
# Issue #610 — the plugin-contributed subset is loaded LAST and may stand down against a colliding
|
|
365
414
|
# generic arity. Only the bundled plugins' own `sig/` is deferred: the user's `signature_paths:`,
|
|
366
415
|
# the bundle walk and `rbs collection install` all stay authoritative.
|
|
367
|
-
|
|
416
|
+
# Issue #2974 — the ADR-72 gem overlays are Rigor-shipped too, and deferred with them: an overlay member
|
|
417
|
+
# the project's `sig/` also declares (`Integer#ordinalize`, `ActiveSupport::NumericWithFormat#to_fs`)
|
|
418
|
+
# stands down member by member (#2422) instead of failing the class's definition build.
|
|
419
|
+
deferred_signature_paths: plugin_sig_paths + overlay_paths,
|
|
368
420
|
project_signature_paths: resolved_paths,
|
|
369
|
-
|
|
421
|
+
# Issue #2978 — a gem's collection copy loads behind the gem's own `sig/`: each member that `sig/` (or any
|
|
422
|
+
# other eagerly loaded signature file) declares stands down from the copy (#2422), and the rest loads.
|
|
423
|
+
subordinate_signature_paths: behind_gem_sig_paths,
|
|
424
|
+
# Issue #3030 — the collection gem directories, loaded as rbs loads a library: without the files below a
|
|
425
|
+
# `_`-prefixed directory (each gem's `_test/` fixtures).
|
|
426
|
+
collection_signature_paths: collection_paths,
|
|
427
|
+
required_features: required_features || RequiredFeatures.scan(source_files, sig_paths: resolved_paths),
|
|
428
|
+
core_root: core_root
|
|
370
429
|
)
|
|
371
430
|
# Issues #824 / #1075 — the rows ADR-112 WD5's consistency rule reports for members the project's
|
|
372
431
|
# own `sig/` and an inline source both declare: an error per contradiction (or per refinement that
|
|
@@ -376,6 +435,12 @@ module Rigor
|
|
|
376
435
|
# on every run, so the member-level outcome needs no plumbing of its own. Costs nothing for a project
|
|
377
436
|
# with no inline RBS: the loader's reader short-circuits on an empty `virtual_rbs`.
|
|
378
437
|
record_member_consistency(loader, source_rbs_synthesis_reporter, root)
|
|
438
|
+
# Issue #2517 — a selected core is built here, not lazily. The env is first demanded from inside a file's
|
|
439
|
+
# analysis, under rescues that turn any raise into one `internal analyzer error` row per file; building it
|
|
440
|
+
# now raises the {CoreRootError} once, before analysis, where the CLI reports it as a configuration error.
|
|
441
|
+
# Issue #2883 — the default core is built here too (`eager:`), so no `type_of` builds the environment.
|
|
442
|
+
# A non-main Ractor worker keeps the lazy build: the `rbs` gem's unshareable constants are unreadable there.
|
|
443
|
+
eager && Ractor.main? ? loader.prepare_for_typing! : loader.verify_core_root!
|
|
379
444
|
# ADR-20 slice 2c + 2e — seed hkt_registry with the bundled builtins. The Environment's
|
|
380
445
|
# `#hkt_registry` getter then LAZILY merges in the RBS env scan on first call so fast paths that
|
|
381
446
|
# don't consult HKT (e.g. `rigor check --cache-stats --no-stats`) don't pay the eager env-build cost
|
|
@@ -399,10 +464,20 @@ module Rigor
|
|
|
399
464
|
# The project-owned `sig/` roots a run reads: the explicit `signature_paths:` when given, else the
|
|
400
465
|
# auto-detected `<root>/sig` (or none). Public so {Cache::IncrementalSnapshot} digests exactly the
|
|
401
466
|
# directories the environment loads, including the auto-detected one a `nil` `signature_paths:` hides.
|
|
467
|
+
# The default branch is {project_signature_root_candidates} narrowed to the directories that exist.
|
|
402
468
|
def project_signature_roots(signature_paths, root: Dir.pwd)
|
|
403
469
|
signature_paths || default_signature_paths(root)
|
|
404
470
|
end
|
|
405
471
|
|
|
472
|
+
# Issue #1619 — the single spelling of "the configured `signature_paths:`, else the conventional `sig`
|
|
473
|
+
# directory", as the CANDIDATES a run watches whether or not they exist yet. {project_signature_roots}
|
|
474
|
+
# narrows this to what the loader reads (a default only once it is a directory); the run slot's presence
|
|
475
|
+
# rows and the incremental write guard take it whole, because a `sig/` appearing mid-run must move the
|
|
476
|
+
# fingerprint and refuse the slot write — a question only a row for a path that need not exist can ask.
|
|
477
|
+
def project_signature_root_candidates(signature_paths)
|
|
478
|
+
signature_paths || [DEFAULT_PROJECT_SIG_DIR]
|
|
479
|
+
end
|
|
480
|
+
|
|
406
481
|
private
|
|
407
482
|
|
|
408
483
|
# Issue #1700 — the `RequiredFeatures` library tokens for the gated vendored directories this run asks for:
|
|
@@ -416,13 +491,31 @@ module Rigor
|
|
|
416
491
|
# The gem names an `rbs collection` copy must not double-declare against: the library list and every
|
|
417
492
|
# vendored directory except a `RequiredFeatures`-gated one. A gated directory stands down for any other
|
|
418
493
|
# copy of its declarations (`GatedSignatureGuard`), so the collection's copy is kept and wins.
|
|
494
|
+
#
|
|
495
|
+
# Issue #2971 — a `libraries:` name that is not an RBS library (`foogem`, collection-installed) is dropped by
|
|
496
|
+
# the loader's `has_library?` filter, so it declares nothing to double-declare against; it stays out of the
|
|
497
|
+
# skip set so the collection's copy still loads. Issue #2978 — that holds for a gem whose own `sig/` the bundle
|
|
498
|
+
# loaded too: its collection copy loads behind that `sig/` ({.collection_paths_behind_gem_sigs}).
|
|
419
499
|
def collection_skip_gem_names(library_names)
|
|
420
|
-
library_names + RbsLoader.vendored_gem_names.reject
|
|
500
|
+
LibraryProbe.loadable(library_names) + RbsLoader.vendored_gem_names.reject do |name|
|
|
501
|
+
RequiredFeatures.gated_dir?(name)
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
# Issue #2978 — the `collection_paths` (`<collection>/<name>/<version>/`) of the locked gems whose own `sig/` is
|
|
506
|
+
# among `gem_sig_paths` ({BundleSigDiscovery.locked_names_of}, keyed by name and version).
|
|
507
|
+
def collection_paths_behind_gem_sigs(collection_paths, gem_sig_paths, locked)
|
|
508
|
+
return [] if collection_paths.empty? || gem_sig_paths.empty?
|
|
509
|
+
|
|
510
|
+
names = BundleSigDiscovery.locked_names_of(gem_sig_paths.map { |dir| Pathname.new(dir) }, locked).to_set
|
|
511
|
+
collection_paths.select { |path| names.include?(Pathname.new(path).parent.basename.to_s) }
|
|
421
512
|
end
|
|
422
513
|
|
|
423
514
|
def default_signature_paths(root)
|
|
424
|
-
|
|
425
|
-
|
|
515
|
+
project_signature_root_candidates(nil).filter_map do |candidate|
|
|
516
|
+
path = Pathname(root) / candidate.to_s
|
|
517
|
+
path if path.directory?
|
|
518
|
+
end
|
|
426
519
|
end
|
|
427
520
|
|
|
428
521
|
# ADR-82 WD9 — the resolved bundle root for the missing-gem constant index, doubling (ADR-90) as the
|
|
@@ -445,9 +538,12 @@ module Rigor
|
|
|
445
538
|
bundle_root
|
|
446
539
|
end
|
|
447
540
|
|
|
448
|
-
# The
|
|
449
|
-
# and consumed twice:
|
|
450
|
-
# index, and
|
|
541
|
+
# The per-gem RBS coverage classification (locked gems against every resolution path), computed
|
|
542
|
+
# once and consumed twice: its `:missing` rows become `[gem_name, version, variants]` entries for
|
|
543
|
+
# the ADR-82 WD9 constant-ownership index, and the full row set feeds the ADR-72 overlay resolution,
|
|
544
|
+
# which admits a gem when its row's source is one the gem's overlay may load under
|
|
545
|
+
# ({GEM_OVERLAY_COVERAGE_SOURCES} — `:missing` by default, `:rbs_collection` for addressable).
|
|
546
|
+
# Returns `[entries, overlay_paths]`.
|
|
451
547
|
def missing_gems_and_overlay_paths(locked:, default_libraries:, bundle_sig_paths:,
|
|
452
548
|
rbs_collection_paths:, plugin_registry:, signature_paths: [],
|
|
453
549
|
bundle_root: nil)
|
|
@@ -455,10 +551,10 @@ module Rigor
|
|
|
455
551
|
return unlocked_missing_gems(default_libraries, bundle_sig_paths, rbs_collection_paths, bundle_root)
|
|
456
552
|
end
|
|
457
553
|
|
|
458
|
-
|
|
554
|
+
coverage = coverage_rows(locked, default_libraries, bundle_sig_paths, rbs_collection_paths)
|
|
555
|
+
rows = coverage.select { |row| row.source == :missing }
|
|
459
556
|
overlays = gem_overlay_paths(
|
|
460
|
-
|
|
461
|
-
signature_paths: signature_paths
|
|
557
|
+
coverage: coverage, plugin_registry: plugin_registry, signature_paths: signature_paths
|
|
462
558
|
)
|
|
463
559
|
[index_entries(rows, locked), overlays]
|
|
464
560
|
end
|
|
@@ -485,14 +581,20 @@ module Rigor
|
|
|
485
581
|
end
|
|
486
582
|
|
|
487
583
|
def missing_rows(gems, default_libraries, bundle_sig_paths, rbs_collection_paths)
|
|
584
|
+
coverage_rows(gems, default_libraries, bundle_sig_paths, rbs_collection_paths)
|
|
585
|
+
.select { |row| row.source == :missing }
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
def coverage_rows(gems, default_libraries, bundle_sig_paths, rbs_collection_paths)
|
|
488
589
|
RbsCoverageReport.classify(
|
|
489
590
|
locked_gems: gems, default_libraries: default_libraries,
|
|
490
591
|
bundle_sig_paths: bundle_sig_paths, rbs_collection_paths: rbs_collection_paths
|
|
491
|
-
)
|
|
592
|
+
)
|
|
492
593
|
end
|
|
493
594
|
|
|
494
595
|
# ADR-72 — resolve the bundled RBS overlay directories to load for this project. A gem is eligible when
|
|
495
|
-
#
|
|
596
|
+
# its coverage row's source is one the gem's overlay may load under ({GEM_OVERLAY_COVERAGE_SOURCES};
|
|
597
|
+
# `:missing` for every overlay the map does not name) and its conflicting opt-in plugin twin (if
|
|
496
598
|
# any) is NOT already reachable. Returns `[Pathname]`, deterministically ordered, or `[]` when no
|
|
497
599
|
# eligible gem.
|
|
498
600
|
#
|
|
@@ -506,20 +608,29 @@ module Rigor
|
|
|
506
608
|
# all); `RbsLoader.bundled_overlay_twin_signatures_loaded?` answers the filesystem half, beside the
|
|
507
609
|
# overlay-side answer to the same question, and carries the reasoning for why it asks what an entry
|
|
508
610
|
# LOADS rather than what it looks like.
|
|
509
|
-
def gem_overlay_paths(
|
|
510
|
-
return [] if
|
|
611
|
+
def gem_overlay_paths(coverage:, plugin_registry:, signature_paths: [])
|
|
612
|
+
return [] if coverage.empty?
|
|
511
613
|
|
|
512
614
|
loaded_ids = plugin_registry ? plugin_registry.ids.to_set : Set.new
|
|
513
|
-
eligible =
|
|
514
|
-
|
|
515
|
-
|
|
615
|
+
eligible = coverage.filter_map do |row|
|
|
616
|
+
next unless overlay_coverage_source?(row.gem_name, row.source)
|
|
617
|
+
|
|
618
|
+
plugin_id = GEM_OVERLAY_PLUGIN_IDS[row.gem_name]
|
|
619
|
+
next if plugin_id &&
|
|
620
|
+
(loaded_ids.include?(plugin_id) ||
|
|
621
|
+
RbsLoader.bundled_overlay_twin_signatures_loaded?(plugin_id, signature_paths))
|
|
516
622
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
end.sort
|
|
623
|
+
row.gem_name
|
|
624
|
+
end.uniq.sort
|
|
520
625
|
RbsLoader.gem_overlay_sig_paths(eligible)
|
|
521
626
|
end
|
|
522
627
|
|
|
628
|
+
# Whether `source` — a `RbsCoverageReport` source — is one `gem_name`'s bundled overlay may load
|
|
629
|
+
# under: the gem's {GEM_OVERLAY_COVERAGE_SOURCES} entry when it has one, else ADR-72's `:missing`.
|
|
630
|
+
def overlay_coverage_source?(gem_name, source)
|
|
631
|
+
(GEM_OVERLAY_COVERAGE_SOURCES[gem_name] || GEM_OVERLAY_DEFAULT_COVERAGE_SOURCES).include?(source)
|
|
632
|
+
end
|
|
633
|
+
|
|
523
634
|
# ADR-32 WD4 + WD5 — for each project source file, invoke every plugin-registered synthesizer once and
|
|
524
635
|
# collect non-nil returns. The returned array is `[[virtual_filename, rbs_source], ...]`; the loader
|
|
525
636
|
# threads it through to `RbsLoader.new(virtual_rbs: ...)`.
|
|
@@ -644,6 +755,8 @@ module Rigor
|
|
|
644
755
|
def record_member_undecided(reporter, record, root)
|
|
645
756
|
plugin_id, path = split_virtual_source_name(record.virtual_name)
|
|
646
757
|
return if path.nil?
|
|
758
|
+
return record_variable_undecided(reporter, record, root, plugin_id, path) if
|
|
759
|
+
MemberConsistency.variable_kind?(record.kind)
|
|
647
760
|
|
|
648
761
|
reporter.record(
|
|
649
762
|
plugin_id: plugin_id, path: path, kind: :not_honoured,
|
|
@@ -656,8 +769,22 @@ module Rigor
|
|
|
656
769
|
)
|
|
657
770
|
end
|
|
658
771
|
|
|
772
|
+
# Issue #2440 — an instance variable declared by both sides with different types. `sig/` binds
|
|
773
|
+
# (the coordinator's ruling on #2440, ADR-5): the row is `:info`, never `rbs.contradicting-signature`.
|
|
774
|
+
def record_variable_undecided(reporter, record, root, plugin_id, path)
|
|
775
|
+
reporter.record(
|
|
776
|
+
plugin_id: plugin_id, path: path, kind: :not_honoured,
|
|
777
|
+
message: "`#{member_label(record)}` is also declared in " \
|
|
778
|
+
"`#{path_relative_to(record.signature_path, root)}` with a different type " \
|
|
779
|
+
"(#{record.detail}), so the `.rbs` declaration binds and the inline one was dropped. " \
|
|
780
|
+
"RBS rejects two declarations of one instance variable, so only one can stay; " \
|
|
781
|
+
"regenerate the committed `.rbs` (`rbs-inline --output`) or align the two types."
|
|
782
|
+
)
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
# `Demo#m` / `Demo.m` for a method, `Demo#@x` / `Demo.@x` for an instance / class instance variable.
|
|
659
786
|
def member_label(record)
|
|
660
|
-
separator = record.kind
|
|
787
|
+
separator = %i[singleton class_instance_variable].include?(record.kind) ? "." : "#"
|
|
661
788
|
"#{record.class_name}#{separator}#{record.method_name}"
|
|
662
789
|
end
|
|
663
790
|
|
|
@@ -26,13 +26,13 @@ module Rigor
|
|
|
26
26
|
#
|
|
27
27
|
# ## Composition rules (ADR-2)
|
|
28
28
|
#
|
|
29
|
-
# - `:return_type` — Intersect via `Type::Combinator.intersection`; collapse to bot
|
|
30
|
-
# `:return_type_collapse
|
|
29
|
+
# - `:return_type` — Intersect via `Type::Combinator.intersection`; collapse to bot records a
|
|
30
|
+
# `:return_type_collapse` conflict.
|
|
31
31
|
# - `:truthy_fact` / `:falsey_fact` / `:post_return_fact` — Edge-local; accumulate while deduping by
|
|
32
32
|
# payload equality.
|
|
33
33
|
# - `:mutation` / `:invalidation` / `:role` — Union; dedupe by equality.
|
|
34
|
-
# - `:exception` — Single-valued. Two non-`nil` non-equal exceptional effects
|
|
35
|
-
# `:exceptional_disagreement
|
|
34
|
+
# - `:exception` — Single-valued. Two non-`nil` non-equal exceptional effects record an
|
|
35
|
+
# `:exceptional_disagreement` conflict.
|
|
36
36
|
#
|
|
37
37
|
# ## Cross-tier contradictions
|
|
38
38
|
#
|