rigortype 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +132 -14
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +19 -1
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +525 -13
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +95 -6
- data/docs/manual/03-configuration.md +18 -0
- data/docs/manual/04-diagnostics.md +15 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/10-mcp-server.md +3 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +46 -8
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +261 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +138 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +3 -3
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
- data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +718 -79
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +15 -1
- data/lib/rigor/analysis/incremental.rb +42 -0
- data/lib/rigor/analysis/incremental_session.rb +117 -26
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +3 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +131 -1
- data/lib/rigor/analysis/run_cache_key.rb +21 -12
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +340 -33
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
- data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
- data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +407 -51
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +62 -20
- data/lib/rigor/bleeding_edge.rb +10 -24
- data/lib/rigor/builtins/hkt_builtins.rb +3 -2
- data/lib/rigor/builtins/imported_refinements.rb +159 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +21 -13
- data/lib/rigor/builtins/static_return_refinements.rb +7 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +63 -20
- data/lib/rigor/cache/engine_source.rb +33 -5
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +72 -6
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +112 -14
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +76 -32
- data/lib/rigor/ci_detector.rb +1 -0
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +4 -4
- data/lib/rigor/cli/docs_command.rb +6 -6
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +4 -4
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +1 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +212 -31
- data/lib/rigor/cli/skill_command.rb +2 -2
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +35 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +29 -11
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +89 -9
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +25 -9
- data/lib/rigor/configuration.rb +109 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +12 -5
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +15 -10
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +11 -4
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +9 -9
- data/lib/rigor/effects/envelope_index.rb +20 -8
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +5 -7
- data/lib/rigor/effects/identity.rb +20 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +22 -1
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +47 -37
- data/lib/rigor/effects/propagator.rb +297 -19
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +122 -73
- data/lib/rigor/effects/signature_sources.rb +4 -6
- data/lib/rigor/effects/snapshot.rb +12 -11
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +393 -38
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +68 -4
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +674 -79
- data/lib/rigor/environment.rb +174 -24
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +292 -17
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +75 -30
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +7 -6
- data/lib/rigor/inference/budget_trace.rb +3 -6
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +389 -18
- data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +180 -0
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +2124 -468
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +16 -7
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +168 -21
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +165 -111
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -6
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +225 -25
- data/lib/rigor/inference/method_parameter_binder.rb +12 -9
- data/lib/rigor/inference/multi_target_binder.rb +341 -55
- data/lib/rigor/inference/mutation_rejoin.rb +171 -0
- data/lib/rigor/inference/mutation_widening.rb +156 -85
- data/lib/rigor/inference/narrowing.rb +835 -162
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +153 -16
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +9 -4
- data/lib/rigor/inference/project_patched_scanner.rb +10 -6
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +93 -4
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +76 -0
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +5228 -627
- data/lib/rigor/inference/statement_evaluator.rb +3452 -595
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +97 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +4 -4
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +7 -8
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +258 -26
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +65 -11
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +33 -13
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +94 -11
- data/lib/rigor/plugin/registry.rb +76 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +14 -12
- data/lib/rigor/protection/kill_signature.rb +1 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +7 -11
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +88 -21
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +139 -0
- data/lib/rigor/reflection.rb +93 -110
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +165 -2
- data/lib/rigor/scope.rb +1041 -32
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +673 -53
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +18 -16
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +128 -14
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +189 -41
- data/lib/rigor/sig_gen.rb +3 -0
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +0 -6
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +144 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +6 -6
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +4 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +14 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +10 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +322 -41
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +290 -19
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +2 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +12 -7
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +36 -37
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +10 -17
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +2 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +10 -5
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +17 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +9 -14
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +51 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +9 -6
- data/sig/rigor/scope.rbs +148 -12
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +33 -1
- data/sig/rigor.rbs +39 -20
- data/skills/rigor-ask/SKILL.md +16 -11
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +15 -10
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +43 -14
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +226 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +133 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
data/lib/rigor/rbs_extended.rb
CHANGED
|
@@ -92,23 +92,87 @@ module Rigor
|
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
+
# The shared empty answers of the per-method readers. Dispatch consults the three readers on every RBS
|
|
96
|
+
# method it resolves (~150k each on the lib self-check) and nearly every method carries no `rigor:v1:`
|
|
97
|
+
# annotation, so a fresh `[]` / `{}` per decline was pure allocation. Callers never mutate a reader's
|
|
98
|
+
# result (`read_flow_contribution` selects into fresh arrays; the override map is documented read-only).
|
|
99
|
+
NO_DIRECTIVES = [].freeze
|
|
100
|
+
private_constant :NO_DIRECTIVES
|
|
101
|
+
NO_OVERRIDES = {}.freeze
|
|
102
|
+
private_constant :NO_OVERRIDES
|
|
103
|
+
|
|
104
|
+
# `%a{rigor:v1:inferred-return}` — the declaration states the member's presence and its parameters and
|
|
105
|
+
# says nothing about what it returns, so the return comes from the body. Normative in
|
|
106
|
+
# `docs/type-specification/rbs-extended.md`.
|
|
107
|
+
INFERRED_RETURN_DIRECTIVE = "rigor:v1:inferred-return"
|
|
108
|
+
|
|
109
|
+
# `%a{rigor:v1:inferred-signature}` — every type slot on the member, parameters and return alike,
|
|
110
|
+
# is a placeholder: the author's comment block asserted nothing about this member's own contract.
|
|
111
|
+
# Strictly narrower than {INFERRED_RETURN_DIRECTIVE}, which also covers a member with an authored
|
|
112
|
+
# parameter and no authored return. Normative in `docs/type-specification/rbs-extended.md`.
|
|
113
|
+
INFERRED_SIGNATURE_DIRECTIVE = "rigor:v1:inferred-signature"
|
|
114
|
+
|
|
95
115
|
module_function
|
|
96
116
|
|
|
117
|
+
# Whether `method_def` declares its return type inferred rather than contracted (issue #823).
|
|
118
|
+
#
|
|
119
|
+
# The producer is `rigor-rbs-inline`: inside a file that carries one annotation, upstream rbs-inline
|
|
120
|
+
# emits a `(untyped, …) -> untyped` skeleton for every unannotated `def` too, and an accepted signature
|
|
121
|
+
# outranks body inference — so one annotation used to retype every sibling in its file to `untyped`.
|
|
122
|
+
# The plugin now marks exactly the type slots it DEFAULTED, and {MethodDispatcher::RbsDispatch} declines
|
|
123
|
+
# a marked member so the call takes the same body-inference tier an undeclared method takes. Nothing
|
|
124
|
+
# else about the declaration changes: the class keeps its full method surface, `new` keeps its arity,
|
|
125
|
+
# and cross-file references still resolve.
|
|
126
|
+
#
|
|
127
|
+
# Reads `RBS::Definition::Method#annotations`, so it answers for an inherited member too, and a
|
|
128
|
+
# hand-written `.rbs` may carry the annotation for the same effect.
|
|
129
|
+
#
|
|
130
|
+
# @param method_def — an `RBS::Definition::Method`, or anything else answering `#annotations`.
|
|
131
|
+
def inferred_return?(method_def)
|
|
132
|
+
return false if method_def.nil?
|
|
133
|
+
|
|
134
|
+
annotations = method_def.annotations
|
|
135
|
+
return false if annotations.nil? || annotations.empty?
|
|
136
|
+
|
|
137
|
+
annotations.any? { |annotation| annotation.string.to_s.strip == INFERRED_RETURN_DIRECTIVE }
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Whether `method_def` declares its ENTIRE signature inferred — every parameter and the return alike
|
|
141
|
+
# — rather than only its return (issue #991).
|
|
142
|
+
#
|
|
143
|
+
# `inferred_return?` alone cannot separate a fully bare `def` from one whose parameters ARE declared
|
|
144
|
+
# (`# @rbs num: Float`) and only its return defaulted: both trip the same return-only provenance,
|
|
145
|
+
# because no equivalent per-parameter survivor exists to tell them apart. This reads the plugin's
|
|
146
|
+
# narrower, member-level fact instead: true only when nothing at all was asserted about the member.
|
|
147
|
+
# `call.wrong-arity` declines on this rather than on {inferred_return?}, since a parameter the author
|
|
148
|
+
# DID annotate is an assertion about the parameter list, and the parameter list is exactly what arity
|
|
149
|
+
# is a question about (see the rule's own comment).
|
|
150
|
+
#
|
|
151
|
+
# @param method_def — an `RBS::Definition::Method`, or anything else answering `#annotations`.
|
|
152
|
+
def inferred_signature?(method_def)
|
|
153
|
+
return false if method_def.nil?
|
|
154
|
+
|
|
155
|
+
annotations = method_def.annotations
|
|
156
|
+
return false if annotations.nil? || annotations.empty?
|
|
157
|
+
|
|
158
|
+
annotations.any? { |annotation| annotation.string.to_s.strip == INFERRED_SIGNATURE_DIRECTIVE }
|
|
159
|
+
end
|
|
160
|
+
|
|
97
161
|
# Reads RBS::Extended predicate effects off `RBS::Definition::Method#annotations`. Returns the effects in
|
|
98
162
|
# source order; duplicates and unrecognised `rigor:v1:` directives are dropped. Returns an empty array (NEVER
|
|
99
163
|
# `nil`) for a method with no recognised annotations so callers can iterate unconditionally.
|
|
100
164
|
#
|
|
101
|
-
# @param environment
|
|
165
|
+
# @param environment — ADR-13 slice
|
|
102
166
|
# 3b. When provided, threads the plugin-supplied
|
|
103
167
|
# `name_scope:` and the per-run reporter through the
|
|
104
168
|
# annotation-parse path. `nil` (default) preserves the
|
|
105
169
|
# pre-slice-3b behaviour — no plugin resolvers consulted
|
|
106
170
|
# and no diagnostics accumulated.
|
|
107
171
|
def read_predicate_effects(method_def, environment: nil)
|
|
108
|
-
return
|
|
172
|
+
return NO_DIRECTIVES if method_def.nil?
|
|
109
173
|
|
|
110
174
|
annotations = method_def.annotations
|
|
111
|
-
return
|
|
175
|
+
return NO_DIRECTIVES if annotations.nil? || annotations.empty?
|
|
112
176
|
|
|
113
177
|
name_scope = environment&.name_scope
|
|
114
178
|
reporter = environment&.rbs_extended_reporter
|
|
@@ -127,10 +191,11 @@ module Rigor
|
|
|
127
191
|
end
|
|
128
192
|
|
|
129
193
|
# The right-hand side accepts either a Capitalised class name (with optional `~` negation, optional `::`
|
|
130
|
-
# prefix, qualified names) OR a
|
|
131
|
-
# `Builtins::ImportedRefinements::Parser` (bare names, `name[T]`,
|
|
132
|
-
#
|
|
133
|
-
# `refinement` capture
|
|
194
|
+
# prefix, qualified names) OR a refinement payload routed through
|
|
195
|
+
# `Builtins::ImportedRefinements::Parser` (bare kebab-case names, `name[T]`, the numeric range form
|
|
196
|
+
# `Integer[1..10]`, and the deprecated `name<min, max>`). The two arms share the same overall directive
|
|
197
|
+
# shape; the parser detects which form matched by looking at the `class_name` vs `refinement` capture
|
|
198
|
+
# groups. A class head followed by a bracketed range literal is a refinement (ADR-109), not a class name.
|
|
134
199
|
PREDICATE_DIRECTIVE_PATTERN = /
|
|
135
200
|
\A
|
|
136
201
|
rigor:v1:(?<directive>predicate-if-(?:true|false))
|
|
@@ -141,7 +206,7 @@ module Rigor
|
|
|
141
206
|
(?:
|
|
142
207
|
(?<class_name>(?:::)?[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*)
|
|
143
208
|
|
|
|
144
|
-
(?<refinement>[a-z][a-z0-9-]*(?:[\[<][^\]>]*[\]>])
|
|
209
|
+
(?<refinement>[a-z][a-z0-9-]*(?:[\[<][^\]>]*[\]>])?|[A-Z][A-Za-z0-9_]*\[[^\]]*\.\.[^\]]*\])
|
|
145
210
|
)
|
|
146
211
|
\s*
|
|
147
212
|
\z
|
|
@@ -183,10 +248,10 @@ module Rigor
|
|
|
183
248
|
#
|
|
184
249
|
# See {.read_predicate_effects} for the `environment:` keyword contract.
|
|
185
250
|
def read_assert_effects(method_def, environment: nil)
|
|
186
|
-
return
|
|
251
|
+
return NO_DIRECTIVES if method_def.nil?
|
|
187
252
|
|
|
188
253
|
annotations = method_def.annotations
|
|
189
|
-
return
|
|
254
|
+
return NO_DIRECTIVES if annotations.nil? || annotations.empty?
|
|
190
255
|
|
|
191
256
|
name_scope = environment&.name_scope
|
|
192
257
|
reporter = environment&.rbs_extended_reporter
|
|
@@ -214,7 +279,7 @@ module Rigor
|
|
|
214
279
|
(?:
|
|
215
280
|
(?<class_name>(?:::)?[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*)
|
|
216
281
|
|
|
|
217
|
-
(?<refinement>[a-z][a-z0-9-]*(?:[\[<][^\]>]*[\]>])
|
|
282
|
+
(?<refinement>[a-z][a-z0-9-]*(?:[\[<][^\]>]*[\]>])?|[A-Z][A-Za-z0-9_]*\[[^\]]*\.\.[^\]]*\])
|
|
218
283
|
)
|
|
219
284
|
\s*
|
|
220
285
|
\z
|
|
@@ -352,7 +417,8 @@ module Rigor
|
|
|
352
417
|
|
|
353
418
|
# The trailing payload supports the full refinement grammar in `Builtins::ImportedRefinements::Parser` — bare
|
|
354
419
|
# kebab-case names plus parameterised forms like `non-empty-array[Integer]`, `non-empty-hash[Symbol,
|
|
355
|
-
# Integer]`, and `int<5, 10>`. The directive head is consumed by the regex;
|
|
420
|
+
# Integer]`, `Integer[5..10]`, and the deprecated `int<5, 10>`. The directive head is consumed by the regex;
|
|
421
|
+
# the rest is forwarded to the
|
|
356
422
|
# refinement parser. Anything the parser cannot resolve falls back to nil so the call site keeps the
|
|
357
423
|
# RBS-declared return type.
|
|
358
424
|
RETURN_DIRECTIVE_PATTERN = /
|
|
@@ -449,7 +515,7 @@ module Rigor
|
|
|
449
515
|
|
|
450
516
|
# Returned for `rigor:v1:param: <name> <refinement>`. The parameter name is a Ruby identifier (Symbol); the
|
|
451
517
|
# type is any `Rigor::Type` the refinement parser resolves (bare kebab-case name, parameterised form, or
|
|
452
|
-
# `
|
|
518
|
+
# `Integer[a..b]` range, or the deprecated `int<a, b>` — the same grammar the `return:` directive accepts).
|
|
453
519
|
ParamOverride = Data.define(:param_name, :type)
|
|
454
520
|
|
|
455
521
|
# Reads every `rigor:v1:param: <name> <refinement>` directive off `RBS::Definition::Method#annotations` and
|
|
@@ -469,10 +535,10 @@ module Rigor
|
|
|
469
535
|
# argument-check purposes; passing a too-wide `Nominal[String]` argument is flagged as an argument-type
|
|
470
536
|
# mismatch at the call site.
|
|
471
537
|
def read_param_type_overrides(method_def, environment: nil)
|
|
472
|
-
return
|
|
538
|
+
return NO_DIRECTIVES if method_def.nil?
|
|
473
539
|
|
|
474
540
|
annotations = method_def.annotations
|
|
475
|
-
return
|
|
541
|
+
return NO_DIRECTIVES if annotations.nil? || annotations.empty?
|
|
476
542
|
|
|
477
543
|
name_scope = environment&.name_scope
|
|
478
544
|
reporter = environment&.rbs_extended_reporter
|
|
@@ -491,9 +557,10 @@ module Rigor
|
|
|
491
557
|
# frozen Hash<Symbol, Rigor::Type>; missing keys mean "use the RBS-declared type". Callers MUST treat the
|
|
492
558
|
# hash as read-only.
|
|
493
559
|
def param_type_override_map(method_def, environment: nil)
|
|
494
|
-
read_param_type_overrides(method_def, environment: environment)
|
|
495
|
-
|
|
496
|
-
|
|
560
|
+
overrides = read_param_type_overrides(method_def, environment: environment)
|
|
561
|
+
return NO_OVERRIDES if overrides.empty?
|
|
562
|
+
|
|
563
|
+
overrides.to_h { |o| [o.param_name, o.type] }.freeze
|
|
497
564
|
end
|
|
498
565
|
|
|
499
566
|
# The `is` glue word is optional so authors can write either `param: id is non-empty-string` (consistent with
|
|
@@ -708,9 +775,9 @@ module Rigor
|
|
|
708
775
|
# `RBS::Extended` conflict channel) rather than silently resolved. Returns `nil` when the list
|
|
709
776
|
# carries neither spelling.
|
|
710
777
|
#
|
|
711
|
-
# @param annotations
|
|
712
|
-
# @param owner_key
|
|
713
|
-
# @param source
|
|
778
|
+
# @param annotations — the node's annotations, in source order.
|
|
779
|
+
# @param owner_key — the method key (`Class#m` / `Class.m`) or class name the bound binds.
|
|
780
|
+
# @param source — {Effects::Envelope::SOURCES} member to stamp when the labelled spelling
|
|
714
781
|
# matched; `%a{pure}` always stamps `:pure_annotation`, and a class-level read overrides both.
|
|
715
782
|
def read_effect_envelope(annotations, owner_key:, source: :effect_annotation, registry: nil, reporter: nil)
|
|
716
783
|
return nil if annotations.nil? || annotations.empty?
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
# {Reflection}'s constant-ancestor walk ([#354](https://github.com/rigortype/rigor/issues/354)), split out for
|
|
5
|
+
# the reader rather than for the loader: the whole-spelling ladder's step 2 (`reflection.rb`) and the
|
|
6
|
+
# segment-wise path walk (`reflection/constant_path.rb`) both ask which project classes and modules a
|
|
7
|
+
# name's owner inherits constants from, and this file answers that once for both. Reopening the module
|
|
8
|
+
# keeps the walk behind the facade its callers already read.
|
|
9
|
+
module Reflection
|
|
10
|
+
# #354 — thread-local slot for the per-run ancestor-scope memo. See {.ancestor_constant_scopes}.
|
|
11
|
+
ANCESTOR_SCOPES_KEY = :__rigor_ancestor_constant_scopes__
|
|
12
|
+
private_constant :ANCESTOR_SCOPES_KEY
|
|
13
|
+
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
# #354 — the project classes and modules whose own constants `class_name` inherits, in Ruby's
|
|
17
|
+
# ancestor order: included / prepended modules before the superclass (Ruby places mixins nearer),
|
|
18
|
+
# transitively, breadth-first. `class_name` itself is excluded — step 1 already covered it.
|
|
19
|
+
#
|
|
20
|
+
# Only PROJECT ancestors appear. `Scope#superclass_of` / `#includes_of` carry as-written names
|
|
21
|
+
# from the discovery pre-pass, and an as-written name that resolves to no discovered class or
|
|
22
|
+
# module is dropped — so a `class Foo < ActiveRecord::Base` contributes nothing and a constant
|
|
23
|
+
# owned by an RBS-known ancestor still resolves only if the bare name reaches it at step 3. That
|
|
24
|
+
# gap is deliberate for this slice: widening to the RBS ancestor graph is a separate question
|
|
25
|
+
# with its own FP surface.
|
|
26
|
+
#
|
|
27
|
+
# Memoised per run because step 2 runs on every constant reference whose lexical candidates all
|
|
28
|
+
# miss — which is the common case for a core-class reference (`String` inside `class Foo`). The
|
|
29
|
+
# bucket keys on the identity of the runner-seeded run-generation token (ADR-84 WD2), falling
|
|
30
|
+
# back to the per-file discovery table for runner-less scopes, so a re-run in one process (LSP,
|
|
31
|
+
# ADR-62 warm loop) cannot hit stale entries.
|
|
32
|
+
def ancestor_constant_scopes(class_name, scope)
|
|
33
|
+
# ADR-46: `superclass_of` / `includes_of` record a cross-file class dependency per consumer
|
|
34
|
+
# file, and the memo is run-scoped rather than file-scoped — a hit would skip the recording and
|
|
35
|
+
# under-record the edge for every later file. Recording runs are rare (incremental only), so
|
|
36
|
+
# they simply bypass the memo rather than complicate its key.
|
|
37
|
+
return compute_ancestor_constant_scopes(class_name, scope) if Analysis::DependencyRecorder.active?
|
|
38
|
+
|
|
39
|
+
generation = scope.run_generation || scope.discovered_superclasses
|
|
40
|
+
slot = Thread.current[ANCESTOR_SCOPES_KEY]
|
|
41
|
+
unless slot && slot[0].equal?(generation)
|
|
42
|
+
slot = [generation, {}]
|
|
43
|
+
Thread.current[ANCESTOR_SCOPES_KEY] = slot
|
|
44
|
+
end
|
|
45
|
+
bucket = slot[1]
|
|
46
|
+
bucket.fetch(class_name) { bucket[class_name] = compute_ancestor_constant_scopes(class_name, scope) }
|
|
47
|
+
end
|
|
48
|
+
private_class_method :ancestor_constant_scopes
|
|
49
|
+
|
|
50
|
+
def compute_ancestor_constant_scopes(class_name, scope)
|
|
51
|
+
queue = [class_name]
|
|
52
|
+
seen = { class_name => true }
|
|
53
|
+
out = []
|
|
54
|
+
until queue.empty?
|
|
55
|
+
current = queue.shift
|
|
56
|
+
# Mixins first, then the superclass — Ruby's ancestor order.
|
|
57
|
+
scope.includes_of(current).each do |raw|
|
|
58
|
+
resolved = resolve_ancestor_name(current, raw, scope)
|
|
59
|
+
next if resolved.nil? || seen[resolved]
|
|
60
|
+
|
|
61
|
+
seen[resolved] = true
|
|
62
|
+
out << resolved
|
|
63
|
+
queue << resolved
|
|
64
|
+
end
|
|
65
|
+
raw_super = scope.superclass_of(current)
|
|
66
|
+
next if raw_super.nil?
|
|
67
|
+
|
|
68
|
+
resolved_super = resolve_ancestor_name(current, raw_super, scope)
|
|
69
|
+
next if resolved_super.nil? || seen[resolved_super]
|
|
70
|
+
|
|
71
|
+
seen[resolved_super] = true
|
|
72
|
+
out << resolved_super
|
|
73
|
+
queue << resolved_super
|
|
74
|
+
end
|
|
75
|
+
out.freeze
|
|
76
|
+
end
|
|
77
|
+
private_class_method :compute_ancestor_constant_scopes
|
|
78
|
+
|
|
79
|
+
# Resolves an ancestor name AS WRITTEN (`"Base"`, or a qualified `"A::B"`) against the nesting in
|
|
80
|
+
# force where the subclass's header is written — `Scope#ancestor_name_candidates`, the single
|
|
81
|
+
# owner of that order, which `Scope#enqueue_ancestors` reads for method lookup and the
|
|
82
|
+
# override-visibility rule reads for its own walk. Returns nil when no candidate names a
|
|
83
|
+
# discovered project class or module.
|
|
84
|
+
def resolve_ancestor_name(subclass_qualified, raw, scope)
|
|
85
|
+
scope.ancestor_name_candidates(subclass_qualified, raw)
|
|
86
|
+
.find { |candidate| known_project_namespace?(candidate, scope) }
|
|
87
|
+
end
|
|
88
|
+
private_class_method :resolve_ancestor_name
|
|
89
|
+
|
|
90
|
+
def known_project_namespace?(name, scope)
|
|
91
|
+
scope.discovered_superclasses.key?(name) ||
|
|
92
|
+
scope.discovered_includes.key?(name) ||
|
|
93
|
+
scope.discovered_classes.key?(name)
|
|
94
|
+
end
|
|
95
|
+
private_class_method :known_project_namespace?
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
# {Reflection}'s second constant-resolution phase, split out for the reader rather than for the
|
|
5
|
+
# loader: `reflection.rb` asks what a whole spelling names under a series of prefixes, and this file
|
|
6
|
+
# asks what a PATH names segment by segment. Reopening the module rather than nesting under it keeps
|
|
7
|
+
# the walk inside the facade its callers already read, and lets it use the same private candidate
|
|
8
|
+
# lookups (`constant_type_at`, `enclosing_class_path`, `ancestor_constant_scopes`) the ladder uses.
|
|
9
|
+
module Reflection
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# Issue #656 — Ruby's lookup for an as-written, unrooted constant PATH (`A::B`, `A::B::C`), which is
|
|
13
|
+
# a different question from "what does this whole string name under some prefix". Ruby resolves the
|
|
14
|
+
# FIRST segment through the ladder a bare name gets — `Module.nesting`, then the enclosing class's
|
|
15
|
+
# ancestors, then the top level — and then resolves each LATER segment inside the constant the
|
|
16
|
+
# previous segment produced, searching THAT constant's own ancestors in turn. So `A::B` written in
|
|
17
|
+
# `P::Guard` with `P::A < P::Base` names `P::Base::B`, while every whole-path candidate
|
|
18
|
+
# (`P::Guard::A::B`, `P::A::B`, `A::B`) either misses or names a real but different class.
|
|
19
|
+
#
|
|
20
|
+
# `known` decides the FINAL segment only, so the constant typer (any constant, values included) and
|
|
21
|
+
# `Inference::Narrowing`'s class-guard resolver (classes only) share one walk without sharing an
|
|
22
|
+
# acceptance test — the two cannot answer different names for the same spelling. Every earlier
|
|
23
|
+
# segment must name a namespace, because only a namespace can own the next one.
|
|
24
|
+
#
|
|
25
|
+
# Returns nil for a single-segment name — the callers' own ladders already own that case — and the
|
|
26
|
+
# moment any segment declines. Declining hands the caller back its unchanged fallback instead of a
|
|
27
|
+
# guess: a walk that finds the WRONG constant is worse than the wrong constant answered today
|
|
28
|
+
# (AGENTS.md § "Implementation Guidelines").
|
|
29
|
+
#
|
|
30
|
+
# Checked against MRI 4.0.5 rather than recollection: a later segment does NOT reach the top level
|
|
31
|
+
# for either a Class or a Module owner (`P::Mod::B` raises `NameError` where a top-level `B`
|
|
32
|
+
# exists), which is why {.constant_in_namespace} consults the owner's ancestors and stops. Rigor
|
|
33
|
+
# still lets its callers fall through to their own top-level rung there — that read raises at
|
|
34
|
+
# runtime and Rigor reports nothing about it either way, so retracting the resolution would trade a
|
|
35
|
+
# silent wrong answer for a silent absent one at no gain (the same reasoning as
|
|
36
|
+
# {.toplevel_first_constant_type}'s caller-derived rungs).
|
|
37
|
+
def resolve_constant_path_name(name, scope, &known)
|
|
38
|
+
walk_constant_path(name, scope, known, caller_derived: true)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# {.resolve_constant_path_name}'s walk. `caller_derived: false` is {.resolve_constant_type}'s flag: the
|
|
42
|
+
# head skips the enclosing class's ancestors — the one step a recorded top-level body takes from its
|
|
43
|
+
# caller — while every later segment still walks its owner's ancestors, as Ruby does.
|
|
44
|
+
def walk_constant_path(name, scope, known, caller_derived:)
|
|
45
|
+
segments = name.to_s.split("::")
|
|
46
|
+
return nil unless segments.size > 1
|
|
47
|
+
|
|
48
|
+
owner = path_head_owner(segments.first, scope, caller_derived)
|
|
49
|
+
last = segments.size - 1
|
|
50
|
+
segments.each_with_index do |segment, index|
|
|
51
|
+
next if index.zero?
|
|
52
|
+
return nil if owner.nil?
|
|
53
|
+
|
|
54
|
+
owner = constant_in_namespace(owner, segment, scope) do |candidate|
|
|
55
|
+
index == last ? known.call(candidate) : namespace_known?(candidate, scope)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
owner
|
|
59
|
+
end
|
|
60
|
+
private_class_method :walk_constant_path
|
|
61
|
+
|
|
62
|
+
# Step 2.5's rung as a type: the segment-wise name, then that name looked up like any other
|
|
63
|
+
# candidate so the answer comes from the same source-precedence order as every other rung.
|
|
64
|
+
#
|
|
65
|
+
# Issue #1290 — the final segment's candidates are looked up with the reference's `shadows` names
|
|
66
|
+
# ({.constant_type_at}), so an owner's own `B` another file writes stops the walk before the owner's
|
|
67
|
+
# superclass answers with its published `B`.
|
|
68
|
+
def constant_path_type(name, scope, shadows:, caller_derived: true)
|
|
69
|
+
known = ->(candidate) { constant_type_at(candidate, scope, shadows) }
|
|
70
|
+
qualified = walk_constant_path(name, scope, known, caller_derived: caller_derived)
|
|
71
|
+
qualified && constant_type_at(qualified, scope, shadows)
|
|
72
|
+
end
|
|
73
|
+
private_class_method :constant_path_type
|
|
74
|
+
|
|
75
|
+
# The namespace a path's FIRST segment names — the bare-name ladder, restricted to answers that can
|
|
76
|
+
# OWN the segments that follow. A value constant is not one of them, so it declines here rather
|
|
77
|
+
# than producing a namespace prefix no source knows.
|
|
78
|
+
def path_head_owner(head, scope, caller_derived)
|
|
79
|
+
hit = first_namespace_hit(lexical_nesting_chain(scope), head, scope)
|
|
80
|
+
return hit if hit
|
|
81
|
+
|
|
82
|
+
prefix = caller_derived ? enclosing_class_path(scope) : nil
|
|
83
|
+
unless prefix.nil? || prefix.empty?
|
|
84
|
+
hit = first_namespace_hit(bounded_ancestor_scopes(prefix, scope), head, scope)
|
|
85
|
+
return hit if hit
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
head if namespace_known?(head, scope)
|
|
89
|
+
end
|
|
90
|
+
private_class_method :path_head_owner
|
|
91
|
+
|
|
92
|
+
# {.first_constant_hit}'s namespace twin: the first `<entry>::<name>` that can own further segments.
|
|
93
|
+
def first_namespace_hit(entries, name, scope)
|
|
94
|
+
entries.each do |entry|
|
|
95
|
+
candidate = "#{entry}::#{name}"
|
|
96
|
+
return candidate if namespace_known?(candidate, scope)
|
|
97
|
+
end
|
|
98
|
+
nil
|
|
99
|
+
end
|
|
100
|
+
private_class_method :first_namespace_hit
|
|
101
|
+
|
|
102
|
+
# `segment` looked up inside `owner` and then through `owner`'s own ancestors — Ruby's lookup for
|
|
103
|
+
# every segment after the first. `Object` is deliberately absent: MRI raises rather than reaching a
|
|
104
|
+
# top-level constant through an explicit `::` receiver.
|
|
105
|
+
def constant_in_namespace(owner, segment, scope)
|
|
106
|
+
candidate = "#{owner}::#{segment}"
|
|
107
|
+
return candidate if yield(candidate)
|
|
108
|
+
|
|
109
|
+
bounded_ancestor_scopes(owner, scope).each do |ancestor|
|
|
110
|
+
inherited = "#{ancestor}::#{segment}"
|
|
111
|
+
return inherited if yield(inherited)
|
|
112
|
+
end
|
|
113
|
+
nil
|
|
114
|
+
end
|
|
115
|
+
private_class_method :constant_in_namespace
|
|
116
|
+
|
|
117
|
+
# How many of {.ancestor_constant_scopes}' entries one segment may consult, under
|
|
118
|
+
# `Scope::ANCESTOR_WALK_LIMIT` — the budget `Scope`'s method lookup already spends on this same
|
|
119
|
+
# graph, reused rather than re-chosen so one pathological ancestry costs one bound. The list
|
|
120
|
+
# itself is the memoised one step 2 builds, so this bounds the per-segment consultation the walk
|
|
121
|
+
# adds and not the graph. Reported through the shared counter, so a truncated walk is visible in a
|
|
122
|
+
# budget trace instead of looking like a plain miss.
|
|
123
|
+
def bounded_ancestor_scopes(class_name, scope)
|
|
124
|
+
scopes = ancestor_constant_scopes(class_name, scope)
|
|
125
|
+
return scopes if scopes.size <= Scope::ANCESTOR_WALK_LIMIT
|
|
126
|
+
|
|
127
|
+
Inference::BudgetTrace.hit(Inference::BudgetTrace::ANCESTOR_WALK_LIMIT)
|
|
128
|
+
scopes.first(Scope::ANCESTOR_WALK_LIMIT)
|
|
129
|
+
end
|
|
130
|
+
private_class_method :bounded_ancestor_scopes
|
|
131
|
+
|
|
132
|
+
# Whether `name` can OWN a constant. `class_known?` covers the RBS and registry classes and modules;
|
|
133
|
+
# the project tables cover a namespace the project declares with no RBS for it.
|
|
134
|
+
def namespace_known?(name, scope)
|
|
135
|
+
scope.environment.class_known?(name) || known_project_namespace?(name, scope)
|
|
136
|
+
end
|
|
137
|
+
private_class_method :namespace_known?
|
|
138
|
+
end
|
|
139
|
+
end
|