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/reflection.rb
CHANGED
|
@@ -45,15 +45,13 @@ module Rigor
|
|
|
45
45
|
# out of scope for the v0.0.7 first pass; v0.1.0's plugin API added it as a separate
|
|
46
46
|
# concern.
|
|
47
47
|
module Reflection
|
|
48
|
-
# #
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
# Issue #1290 — what {.constant_type_at} answers for a candidate the project writes but no source types, on
|
|
49
|
+
# a ladder that checks the census. Never a type: {.resolve_constant_type} replaces it before it returns.
|
|
50
|
+
WRITTEN_CANDIDATE = Object.new.freeze
|
|
51
|
+
private_constant :WRITTEN_CANDIDATE
|
|
51
52
|
|
|
52
53
|
module_function
|
|
53
54
|
|
|
54
|
-
# @param class_name [String, Symbol]
|
|
55
|
-
# @param scope [Rigor::Scope]
|
|
56
|
-
# @return [Boolean]
|
|
57
55
|
def class_known?(class_name, scope: Scope.empty)
|
|
58
56
|
return true if scope.discovered_classes.key?(class_name.to_s)
|
|
59
57
|
|
|
@@ -92,7 +90,7 @@ module Rigor
|
|
|
92
90
|
loader.project_declared_class?(class_name)
|
|
93
91
|
end
|
|
94
92
|
|
|
95
|
-
# @return
|
|
93
|
+
# @return one of `:equal`, `:subclass`, `:superclass`,
|
|
96
94
|
# `:disjoint`, `:unknown`.
|
|
97
95
|
def class_ordering(lhs, rhs, scope: Scope.empty)
|
|
98
96
|
scope.environment.class_ordering(lhs, rhs)
|
|
@@ -143,10 +141,16 @@ module Rigor
|
|
|
143
141
|
# answer to `::Foo`, and falling back to it was the bug (`::Rails` inside `module MyApp` typed
|
|
144
142
|
# as `MyApp::Rails`).
|
|
145
143
|
#
|
|
144
|
+
# `caller_derived: false` drops what {.toplevel_first_constant_type} takes from the caller — its
|
|
145
|
+
# namespaces and ancestors, for a bare name and for a path's head — for a reader whose miss is a
|
|
146
|
+
# meaningful answer rather than a read Ruby raises on. A constant compound write is one: an unset
|
|
147
|
+
# top-level `REGISTRY ||= {}` is the memoization idiom, and the caller's `Plugin::REGISTRY` is a binding
|
|
148
|
+
# Ruby never consults there. A path's later segments still walk their owner's ancestors.
|
|
149
|
+
#
|
|
146
150
|
# This is the shared owner of the lexical-constant resolution: `Inference::ExpressionTyper`
|
|
147
151
|
# reads it to type a constant read, and `Inference::Narrowing` reads it to recognise a
|
|
148
152
|
# value-pinned `Constant[Regexp]` match-predicate operand.
|
|
149
|
-
def resolve_constant_type(name, scope: Scope.empty, rooted: false)
|
|
153
|
+
def resolve_constant_type(name, scope: Scope.empty, rooted: false, caller_derived: true)
|
|
150
154
|
# Issue #644 — the ADR-46 name edge, recorded ONCE PER REFERENCE and BEFORE the ladder, so it does not
|
|
151
155
|
# depend on which resolver answers. A reference that resolves through RBS (`Math::PI`) or through the
|
|
152
156
|
# class registry is exactly as dependent on the project's constant write set as one that resolves
|
|
@@ -156,10 +160,25 @@ module Rigor
|
|
|
156
160
|
# go stale. Over-recording is ADR-46's safe direction.
|
|
157
161
|
record_constant_reference(name) if Analysis::DependencyRecorder.active?
|
|
158
162
|
return constant_type_at(name, scope) if rooted
|
|
163
|
+
|
|
164
|
+
# Issue #1290 — a candidate the project writes but no source types is where Ruby's lookup stops, so it
|
|
165
|
+
# REPLACES what a lower rung answers, and nothing else. The first pass hands the census's shadowing
|
|
166
|
+
# names to the rungs ({.constant_type_at}); a stop is `Dynamic[top]` only when the plain ladder, run
|
|
167
|
+
# again, answers below it. When nothing below answers, the reference stays unresolved exactly as before,
|
|
168
|
+
# so the nil its caller turns into the fallback, the missing-constant edge and the gem-origin label stay.
|
|
169
|
+
hit = lexical_constant_type(name, scope, caller_derived, scope.shadowing_constant_names(name.to_s))
|
|
170
|
+
return hit unless hit.equal?(WRITTEN_CANDIDATE)
|
|
171
|
+
|
|
172
|
+
Type::Combinator.untyped if lexical_constant_type(name, scope, caller_derived, nil)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# {.resolve_constant_type}'s unrooted ladder. `shadows` is the census's shadowing names for the
|
|
176
|
+
# reference, which the rungs above the last check their candidates against, or nil for the plain ladder.
|
|
177
|
+
def lexical_constant_type(name, scope, caller_derived, shadows)
|
|
159
178
|
# Issue #716 — a body whose `Module.nesting` was RECORDED EMPTY is definitively top level, and Ruby
|
|
160
179
|
# resolves its constants there no matter which namespace calls it. Steps 1 and 2 both derive from the
|
|
161
180
|
# caller and are both wrong for it, so it takes its own ladder.
|
|
162
|
-
return toplevel_first_constant_type(name, scope) if recorded_toplevel_nesting?(scope)
|
|
181
|
+
return toplevel_first_constant_type(name, scope, caller_derived, shadows) if recorded_toplevel_nesting?(scope)
|
|
163
182
|
|
|
164
183
|
# Step 1 — `Module.nesting`, innermost first. Each entry contributes only its OWN constants.
|
|
165
184
|
#
|
|
@@ -171,18 +190,26 @@ module Rigor
|
|
|
171
190
|
# § "Implementation Guidelines"). Only project ancestors are walked; an RBS-known superclass
|
|
172
191
|
# contributes no name here (see {.ancestor_constant_scopes}).
|
|
173
192
|
#
|
|
174
|
-
# Step
|
|
175
|
-
|
|
176
|
-
|
|
193
|
+
# Step 2.5 (#656) — the path read SEGMENT BY SEGMENT, which is the only rung that can answer a
|
|
194
|
+
# path whose head and tail have different owners. See {.resolve_constant_path_name}. It sits
|
|
195
|
+
# BELOW the whole-path rungs so no read that resolves today moves, and ABOVE step 3 because
|
|
196
|
+
# beating the top-level whole-string answer is the point: `A::B` inside `P::Guard` with
|
|
197
|
+
# `P::A < P::Base` is `P::Base::B`, and step 3's `A::B` is a real but different class.
|
|
198
|
+
#
|
|
199
|
+
# Step 3 — the bare name (top level). It takes no `shadows`: nothing sits below it for a stop to replace.
|
|
200
|
+
first_constant_hit(lexical_nesting_chain(scope), name, scope, shadows) ||
|
|
201
|
+
ancestor_constant_type(name, scope, enclosing_class_path(scope), shadows) ||
|
|
202
|
+
constant_path_type(name, scope, shadows: shadows) ||
|
|
177
203
|
constant_type_at(name, scope)
|
|
178
204
|
end
|
|
205
|
+
private_class_method :lexical_constant_type
|
|
179
206
|
|
|
180
207
|
# The first candidate `<entry>::<name>` any source knows, walking `entries` in order, or nil. The one
|
|
181
208
|
# place a qualifying prefix is joined to a name, so every rung of the ladder consults its candidates
|
|
182
209
|
# identically.
|
|
183
|
-
def first_constant_hit(entries, name, scope)
|
|
210
|
+
def first_constant_hit(entries, name, scope, shadows)
|
|
184
211
|
entries.each do |entry|
|
|
185
|
-
hit = constant_type_at("#{entry}::#{name}", scope)
|
|
212
|
+
hit = constant_type_at("#{entry}::#{name}", scope, shadows)
|
|
186
213
|
return hit if hit
|
|
187
214
|
end
|
|
188
215
|
nil
|
|
@@ -190,10 +217,10 @@ module Rigor
|
|
|
190
217
|
private_class_method :first_constant_hit
|
|
191
218
|
|
|
192
219
|
# Step 2's rung on its own: nil when there is no enclosing class path to take ancestors of.
|
|
193
|
-
def ancestor_constant_type(name, scope, prefix)
|
|
220
|
+
def ancestor_constant_type(name, scope, prefix, shadows)
|
|
194
221
|
return nil if prefix.nil? || prefix.empty?
|
|
195
222
|
|
|
196
|
-
first_constant_hit(ancestor_constant_scopes(prefix, scope), name, scope)
|
|
223
|
+
first_constant_hit(ancestor_constant_scopes(prefix, scope), name, scope, shadows)
|
|
197
224
|
end
|
|
198
225
|
private_class_method :ancestor_constant_type
|
|
199
226
|
|
|
@@ -215,20 +242,30 @@ module Rigor
|
|
|
215
242
|
# dependabot-core — `docs/notes/20260905-toplevel-def-cref-movable-sites.md`). Rigor reports nothing
|
|
216
243
|
# about them either way, so retracting them would trade a silent wrong answer for a silent absent one at
|
|
217
244
|
# no gain. Making them FIRE is a separate question with its own false-positive budget.
|
|
218
|
-
|
|
219
|
-
|
|
245
|
+
#
|
|
246
|
+
# Issue #656's rung goes LAST here rather than second: for a top-level body Ruby's own first answer
|
|
247
|
+
# for `A::B` is the top level, and a whole-string hit there already means "`A` owns `B`". The
|
|
248
|
+
# segment-wise walk only has something to add once that misses. Its head consults the caller's
|
|
249
|
+
# ancestors, so under `caller_derived: false` it resolves the head at the top level alone.
|
|
250
|
+
#
|
|
251
|
+
# Issue #1290 — the top level is this ladder's FIRST rung, so a top-level name the project writes stops it
|
|
252
|
+
# ({.constant_type_at}) before a caller's `Plug::TOP` can answer a read Ruby gives to the top-level `TOP`.
|
|
253
|
+
def toplevel_first_constant_type(name, scope, caller_derived, shadows)
|
|
254
|
+
constant_type_at(name, scope, shadows) ||
|
|
255
|
+
(caller_derived && caller_derived_constant_type(name, scope, shadows)) ||
|
|
256
|
+
constant_path_type(name, scope, caller_derived: caller_derived, shadows: shadows)
|
|
220
257
|
end
|
|
221
258
|
private_class_method :toplevel_first_constant_type
|
|
222
259
|
|
|
223
260
|
# The peel and its ancestors — {.resolve_constant_type}'s steps 1 and 2 as they answer for a scope with
|
|
224
261
|
# no recorded chain, factored out so the top-level ladder above can consult them BELOW the top level
|
|
225
262
|
# instead of above it.
|
|
226
|
-
def caller_derived_constant_type(name, scope)
|
|
263
|
+
def caller_derived_constant_type(name, scope, shadows)
|
|
227
264
|
prefix = enclosing_class_path(scope)
|
|
228
265
|
return nil if prefix.nil? || prefix.empty?
|
|
229
266
|
|
|
230
|
-
first_constant_hit(peeled_nesting(prefix), name, scope) ||
|
|
231
|
-
ancestor_constant_type(name, scope, prefix)
|
|
267
|
+
first_constant_hit(peeled_nesting(prefix), name, scope, shadows) ||
|
|
268
|
+
ancestor_constant_type(name, scope, prefix, shadows)
|
|
232
269
|
end
|
|
233
270
|
private_class_method :caller_derived_constant_type
|
|
234
271
|
|
|
@@ -236,22 +273,45 @@ module Rigor
|
|
|
236
273
|
# `Singleton[C]`), source-discovered classes, in-source value constants, then RBS-side
|
|
237
274
|
# constants. In-source values win over RBS constant decls because the user's source is
|
|
238
275
|
# authoritative for its own constants. Returns nil when no source knows `candidate`.
|
|
239
|
-
|
|
276
|
+
#
|
|
277
|
+
# Issue #1290 — `shadows`, passed on every rung that has a rung below it, is the last source: a candidate
|
|
278
|
+
# no other source types answers {WRITTEN_CANDIDATE} when `shadows` holds it, and {.resolve_constant_type}
|
|
279
|
+
# settles that stop. `shadows` is `Scope#shadowing_constant_names` for the reference, whose last segment
|
|
280
|
+
# every candidate shares. Ruby's lookup stops at a constant that exists, whatever its value, and the
|
|
281
|
+
# cross-file table publishes only a frozen scalar one file writes: another file's `App::LIMIT = { n: 1 }`
|
|
282
|
+
# was missed by every source, and the ladder moved on to a published top-level `LIMIT = 5`, typing `LIMIT`
|
|
283
|
+
# inside `module App` as `5` and reporting `call.undefined-method` on correct code. The value is one the
|
|
284
|
+
# analyzer does not carry, so the stop is gradual.
|
|
285
|
+
#
|
|
286
|
+
# Only an EXACT census name stops a candidate. The census keeps a path write as written
|
|
287
|
+
# ([#690](https://github.com/rigortype/rigor/issues/690)), so a suffix match would reach the as-written
|
|
288
|
+
# `Foo::BAR` from `M::Foo::BAR`, but would also stop `Admin::UsersController::X` on a top-level
|
|
289
|
+
# `UsersController::X`, losing the answer an ordinary Rails layout gets from the namespaced controller's
|
|
290
|
+
# superclass. A name written only through `||=` does not shadow, however many files memoize it: `X ||= v`
|
|
291
|
+
# resolves `X` through this same lookup, so wherever a lower rung answers, the memo finds that constant and
|
|
292
|
+
# never creates the name. The answer moves with the project's write set for the last segment, which the
|
|
293
|
+
# `constant:` edge {.resolve_constant_type} records once per reference already covers.
|
|
294
|
+
def constant_type_at(candidate, scope, shadows = nil)
|
|
240
295
|
env = scope.environment
|
|
241
296
|
|
|
242
297
|
singleton = env.singleton_for_name(candidate)
|
|
243
298
|
return singleton if singleton
|
|
244
299
|
|
|
300
|
+
# Issue #639 — the class-EXISTENCE edge. Without it a reference-only consumer (`Foo` with no call on
|
|
301
|
+
# it) recorded nothing, so deleting the declaring file left the warm `--incremental` run serving
|
|
302
|
+
# `singleton(Foo)` where `--no-cache` answers the honest unresolved type. Recorded ahead of the lookup
|
|
303
|
+
# rather than on the hit: every rung of the ladder spells the same last segment, which is the whole of
|
|
304
|
+
# the key, so one call covers the candidates instead of a branch around each.
|
|
305
|
+
scope.record_class_existence(candidate) if Analysis::DependencyRecorder.active?
|
|
245
306
|
in_source_class = scope.discovered_classes[candidate]
|
|
246
307
|
return in_source_class if in_source_class
|
|
247
308
|
|
|
248
|
-
in_source_value = scope.in_source_constants[candidate]
|
|
249
|
-
if in_source_value
|
|
309
|
+
if (in_source_value = scope.in_source_constants[candidate])
|
|
250
310
|
scope.record_constant_dependency(candidate) if Analysis::DependencyRecorder.active?
|
|
251
311
|
return in_source_value
|
|
252
312
|
end
|
|
253
313
|
|
|
254
|
-
env.constant_for_name(candidate)
|
|
314
|
+
env.constant_for_name(candidate) || (WRITTEN_CANDIDATE if shadows&.include?(candidate))
|
|
255
315
|
end
|
|
256
316
|
private_class_method :constant_type_at
|
|
257
317
|
|
|
@@ -267,87 +327,6 @@ module Rigor
|
|
|
267
327
|
end
|
|
268
328
|
private_class_method :record_constant_reference
|
|
269
329
|
|
|
270
|
-
# #354 — the project classes and modules whose own constants `class_name` inherits, in Ruby's
|
|
271
|
-
# ancestor order: included / prepended modules before the superclass (Ruby places mixins nearer),
|
|
272
|
-
# transitively, breadth-first. `class_name` itself is excluded — step 1 already covered it.
|
|
273
|
-
#
|
|
274
|
-
# Only PROJECT ancestors appear. `Scope#superclass_of` / `#includes_of` carry as-written names
|
|
275
|
-
# from the discovery pre-pass, and an as-written name that resolves to no discovered class or
|
|
276
|
-
# module is dropped — so a `class Foo < ActiveRecord::Base` contributes nothing and a constant
|
|
277
|
-
# owned by an RBS-known ancestor still resolves only if the bare name reaches it at step 3. That
|
|
278
|
-
# gap is deliberate for this slice: widening to the RBS ancestor graph is a separate question
|
|
279
|
-
# with its own FP surface.
|
|
280
|
-
#
|
|
281
|
-
# Memoised per run because step 2 runs on every constant reference whose lexical candidates all
|
|
282
|
-
# miss — which is the common case for a core-class reference (`String` inside `class Foo`). The
|
|
283
|
-
# bucket keys on the identity of the runner-seeded run-generation token (ADR-84 WD2), falling
|
|
284
|
-
# back to the per-file discovery table for runner-less scopes, so a re-run in one process (LSP,
|
|
285
|
-
# ADR-62 warm loop) cannot hit stale entries.
|
|
286
|
-
def ancestor_constant_scopes(class_name, scope)
|
|
287
|
-
# ADR-46: `superclass_of` / `includes_of` record a cross-file class dependency per consumer
|
|
288
|
-
# file, and the memo is run-scoped rather than file-scoped — a hit would skip the recording and
|
|
289
|
-
# under-record the edge for every later file. Recording runs are rare (incremental only), so
|
|
290
|
-
# they simply bypass the memo rather than complicate its key.
|
|
291
|
-
return compute_ancestor_constant_scopes(class_name, scope) if Analysis::DependencyRecorder.active?
|
|
292
|
-
|
|
293
|
-
generation = scope.run_generation || scope.discovered_superclasses
|
|
294
|
-
slot = Thread.current[ANCESTOR_SCOPES_KEY]
|
|
295
|
-
unless slot && slot[0].equal?(generation)
|
|
296
|
-
slot = [generation, {}]
|
|
297
|
-
Thread.current[ANCESTOR_SCOPES_KEY] = slot
|
|
298
|
-
end
|
|
299
|
-
bucket = slot[1]
|
|
300
|
-
bucket.fetch(class_name) { bucket[class_name] = compute_ancestor_constant_scopes(class_name, scope) }
|
|
301
|
-
end
|
|
302
|
-
private_class_method :ancestor_constant_scopes
|
|
303
|
-
|
|
304
|
-
def compute_ancestor_constant_scopes(class_name, scope)
|
|
305
|
-
queue = [class_name]
|
|
306
|
-
seen = { class_name => true }
|
|
307
|
-
out = []
|
|
308
|
-
until queue.empty?
|
|
309
|
-
current = queue.shift
|
|
310
|
-
# Mixins first, then the superclass — Ruby's ancestor order.
|
|
311
|
-
scope.includes_of(current).each do |raw|
|
|
312
|
-
resolved = resolve_ancestor_name(current, raw, scope)
|
|
313
|
-
next if resolved.nil? || seen[resolved]
|
|
314
|
-
|
|
315
|
-
seen[resolved] = true
|
|
316
|
-
out << resolved
|
|
317
|
-
queue << resolved
|
|
318
|
-
end
|
|
319
|
-
raw_super = scope.superclass_of(current)
|
|
320
|
-
next if raw_super.nil?
|
|
321
|
-
|
|
322
|
-
resolved_super = resolve_ancestor_name(current, raw_super, scope)
|
|
323
|
-
next if resolved_super.nil? || seen[resolved_super]
|
|
324
|
-
|
|
325
|
-
seen[resolved_super] = true
|
|
326
|
-
out << resolved_super
|
|
327
|
-
queue << resolved_super
|
|
328
|
-
end
|
|
329
|
-
out.freeze
|
|
330
|
-
end
|
|
331
|
-
private_class_method :compute_ancestor_constant_scopes
|
|
332
|
-
|
|
333
|
-
# Resolves an ancestor name AS WRITTEN (`"Base"`, or a qualified `"A::B"`) against the nesting in
|
|
334
|
-
# force where the subclass's header is written — `Scope#ancestor_name_candidates`, the single
|
|
335
|
-
# owner of that order, which `Scope#enqueue_ancestors` reads for method lookup and the
|
|
336
|
-
# override-visibility rule reads for its own walk. Returns nil when no candidate names a
|
|
337
|
-
# discovered project class or module.
|
|
338
|
-
def resolve_ancestor_name(subclass_qualified, raw, scope)
|
|
339
|
-
scope.ancestor_name_candidates(subclass_qualified, raw)
|
|
340
|
-
.find { |candidate| known_project_namespace?(candidate, scope) }
|
|
341
|
-
end
|
|
342
|
-
private_class_method :resolve_ancestor_name
|
|
343
|
-
|
|
344
|
-
def known_project_namespace?(name, scope)
|
|
345
|
-
scope.discovered_superclasses.key?(name) ||
|
|
346
|
-
scope.discovered_includes.key?(name) ||
|
|
347
|
-
scope.discovered_classes.key?(name)
|
|
348
|
-
end
|
|
349
|
-
private_class_method :known_project_namespace?
|
|
350
|
-
|
|
351
330
|
# Pulls the enclosing qualified class name out of `scope.self_type` when one is set.
|
|
352
331
|
# `Nominal[T]` and `Singleton[T]` both expose `class_name`. Returns nil at the top level.
|
|
353
332
|
def enclosing_class_path(scope)
|
|
@@ -434,7 +413,7 @@ module Rigor
|
|
|
434
413
|
nil
|
|
435
414
|
end
|
|
436
415
|
|
|
437
|
-
#
|
|
416
|
+
# The singleton-side twin of {#instance_definition}, nil under the same conditions.
|
|
438
417
|
def singleton_definition(class_name, scope: nil, environment: nil)
|
|
439
418
|
loader = rbs_loader_for(scope, environment)
|
|
440
419
|
return nil if loader.nil?
|
|
@@ -465,15 +444,14 @@ module Rigor
|
|
|
465
444
|
end
|
|
466
445
|
private_class_method :rbs_loader_for
|
|
467
446
|
|
|
468
|
-
# @return
|
|
447
|
+
# @return true when the analyzed source contains a class / module declaration
|
|
469
448
|
# for the given name. Does NOT consult the RBS loader (use {.class_known?} for the
|
|
470
449
|
# union).
|
|
471
450
|
def discovered_class?(class_name, scope: Scope.empty)
|
|
472
451
|
scope.discovered_classes.key?(class_name.to_s)
|
|
473
452
|
end
|
|
474
453
|
|
|
475
|
-
# @
|
|
476
|
-
# @return [Boolean] true when the ScopeIndexer recorded a `def` for the given method on
|
|
454
|
+
# @return true when the ScopeIndexer recorded a `def` for the given method on
|
|
477
455
|
# the given class with the matching kind.
|
|
478
456
|
#
|
|
479
457
|
# ADR-46 — a MISS records a negative cross-file dependency, so a consumer whose analysis
|
|
@@ -497,3 +475,8 @@ module Rigor
|
|
|
497
475
|
end
|
|
498
476
|
end
|
|
499
477
|
end
|
|
478
|
+
|
|
479
|
+
# Loaded last: the ancestor walk and the segment-wise path walk reopen the module above and read its
|
|
480
|
+
# private candidate lookups, so the facade has to exist first.
|
|
481
|
+
require_relative "reflection/constant_ancestors"
|
|
482
|
+
require_relative "reflection/constant_path"
|
data/lib/rigor/runtime/jit.rb
CHANGED
|
@@ -70,7 +70,7 @@ module Rigor
|
|
|
70
70
|
# call is what enabled YJIT (so the `?`-suffix predicate convention does
|
|
71
71
|
# not apply; hence the Naming/PredicateMethod exemption).
|
|
72
72
|
#
|
|
73
|
-
# @return
|
|
73
|
+
# @return true if this call enabled YJIT; false if it was a
|
|
74
74
|
# no-op (unavailable / opted out / already enabled).
|
|
75
75
|
def enable_now # rubocop:disable Naming/PredicateMethod
|
|
76
76
|
return false unless available?
|
|
@@ -90,8 +90,8 @@ module Rigor
|
|
|
90
90
|
# up front (unavailable / opted out / already enabled), so callers never
|
|
91
91
|
# pay for a thread that could only no-op.
|
|
92
92
|
#
|
|
93
|
-
# @param seconds
|
|
94
|
-
# @return
|
|
93
|
+
# @param seconds — the amortization deadline.
|
|
94
|
+
# @return the deadline thread, or nil when no-op up front.
|
|
95
95
|
def enable_after(seconds)
|
|
96
96
|
return nil unless available?
|
|
97
97
|
return nil if disabled?
|
|
@@ -143,7 +143,7 @@ module Rigor
|
|
|
143
143
|
# Re-arming goes through {enable_after}, so the child records the same
|
|
144
144
|
# absolute deadline it inherited and a grandchild fork carries it too.
|
|
145
145
|
#
|
|
146
|
-
# @return
|
|
146
|
+
# @return the child's deadline thread; nil when YJIT was
|
|
147
147
|
# enabled immediately, and nil when the call is a no-op up front
|
|
148
148
|
# (unavailable / opted out / already enabled — a child forked after the
|
|
149
149
|
# parent enabled inherits the enabled state and has nothing to do).
|
|
@@ -166,8 +166,6 @@ module Rigor
|
|
|
166
166
|
|
|
167
167
|
# The resolved {enable_after} deadline: {DEADLINE_ENV} when it parses to a
|
|
168
168
|
# non-negative float, else {DEFAULT_DEADLINE_SECONDS}.
|
|
169
|
-
#
|
|
170
|
-
# @return [Numeric]
|
|
171
169
|
def deadline_seconds
|
|
172
170
|
raw = ENV.fetch(DEADLINE_ENV, nil)
|
|
173
171
|
return DEFAULT_DEADLINE_SECONDS if raw.nil? || raw.empty?
|
|
@@ -176,12 +174,12 @@ module Rigor
|
|
|
176
174
|
value && value >= 0 ? value : DEFAULT_DEADLINE_SECONDS
|
|
177
175
|
end
|
|
178
176
|
|
|
179
|
-
# @return
|
|
177
|
+
# @return whether this Ruby exposes `RubyVM::YJIT.enable`.
|
|
180
178
|
def available?
|
|
181
179
|
defined?(RubyVM::YJIT.enable) ? true : false
|
|
182
180
|
end
|
|
183
181
|
|
|
184
|
-
# @return
|
|
182
|
+
# @return whether the opt-out env switch is set.
|
|
185
183
|
def disabled?
|
|
186
184
|
ENV[DISABLE_ENV] == "1"
|
|
187
185
|
end
|
|
@@ -15,6 +15,7 @@ module Rigor
|
|
|
15
15
|
:class_ivars,
|
|
16
16
|
:class_cvars,
|
|
17
17
|
:program_globals,
|
|
18
|
+
:program_global_seeds,
|
|
18
19
|
:discovered_classes,
|
|
19
20
|
:in_source_constants,
|
|
20
21
|
:discovered_methods,
|
|
@@ -24,17 +25,31 @@ module Rigor
|
|
|
24
25
|
:discovered_def_sources,
|
|
25
26
|
:discovered_singleton_def_sources,
|
|
26
27
|
:discovered_method_visibilities,
|
|
28
|
+
:discovered_parameter_envelopes,
|
|
27
29
|
:discovered_superclasses,
|
|
30
|
+
:discovered_deferred_ranges,
|
|
31
|
+
:discovered_refinements,
|
|
32
|
+
:discovered_global_write_census,
|
|
28
33
|
:discovered_header_nestings,
|
|
29
34
|
:discovered_includes,
|
|
35
|
+
:discovered_prepends,
|
|
36
|
+
:discovered_extends,
|
|
30
37
|
:discovered_class_sources,
|
|
31
38
|
:constant_sources,
|
|
39
|
+
:constant_writers,
|
|
40
|
+
:constant_shadowers,
|
|
32
41
|
:published_constant_names,
|
|
33
42
|
:local_constant_names,
|
|
43
|
+
:published_constant_alias_names,
|
|
44
|
+
:published_constant_ivars,
|
|
34
45
|
:data_member_layouts,
|
|
35
46
|
:struct_member_layouts,
|
|
36
47
|
:param_inferred_types,
|
|
37
|
-
:run_generation
|
|
48
|
+
:run_generation,
|
|
49
|
+
:patched_line_readers,
|
|
50
|
+
:clears_last_status,
|
|
51
|
+
:defines_case_equality,
|
|
52
|
+
:implicit_self_evidence
|
|
38
53
|
)
|
|
39
54
|
|
|
40
55
|
class DiscoveryIndex
|
|
@@ -52,6 +67,57 @@ module Rigor
|
|
|
52
67
|
# either kind.
|
|
53
68
|
METHOD_KIND_BOTH = :both
|
|
54
69
|
|
|
70
|
+
# Issue #728 — the key a `discovered_header_nestings` bucket stores its class-wide chain under, beside
|
|
71
|
+
# the per-ancestor-name entries. `nil` is used because every other key in a bucket is an ancestor name
|
|
72
|
+
# as written, and no ancestor name can be nil.
|
|
73
|
+
UNKEYED_HEADER_NESTING = nil
|
|
74
|
+
|
|
75
|
+
# Issue #986 — a bucket entry is normally ONE chain (`["Wrap"]`, innermost first). When the
|
|
76
|
+
# compact-header rename pass lands two declarations of one class on a single key and both wrote the
|
|
77
|
+
# same raw ancestor name in DIFFERENT crefs, the entry is instead the LIST of those chains —
|
|
78
|
+
# `[["Wrap"], []]` — because no union of them is Ruby's answer for either site. `Scope` resolves each
|
|
79
|
+
# alternative and declines outright when they name two different project classes: which one wins
|
|
80
|
+
# depends on the runtime load order of the two `include`s, which static analysis cannot know, so
|
|
81
|
+
# picking either is unsound. A chain's entries are Strings and an alternatives list's are Arrays, so
|
|
82
|
+
# the two shapes cannot be confused.
|
|
83
|
+
def self.ambiguous_header_nesting?(entries)
|
|
84
|
+
entries.first.is_a?(Array)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Issue #992 — the two class-wide keys a `discovered_parameter_envelopes` bucket can carry beside its
|
|
88
|
+
# `[kind, method_name]` entries. Their PRESENCE is the fact; the value is always
|
|
89
|
+
# `Source::ParameterEnvelope::OPAQUE`, so a bucket folds under the one join every other entry does.
|
|
90
|
+
# Symbols, because every per-method key is an Array and neither can collide with the other.
|
|
91
|
+
#
|
|
92
|
+
# - {ENVELOPE_MODULE_MARK}: the name is declared with `module` (or `Const = Module.new do … end`) somewhere
|
|
93
|
+
# in the project. An instance of it is an instance of an unknown includer.
|
|
94
|
+
# - {ENVELOPE_DYNAMIC_MARK}: the class body rewrites its method table in a way no literal argument names
|
|
95
|
+
# (`class_eval`, a computed `define_method`, `send`, a non-constant mixin), or a constant-receiver form
|
|
96
|
+
# of those names it from outside.
|
|
97
|
+
# - {ENVELOPE_OBJECT_EXTENDED_MARK}: some method body passes the module to `extend`, so an object of any
|
|
98
|
+
# class may carry its instance methods ahead of that class's own.
|
|
99
|
+
# - {ENVELOPE_REFINED_MARK}: a `refine` block refines the class, which redefines its methods wherever a `using`
|
|
100
|
+
# is in effect. Issue #1367 splits it from {ENVELOPE_DYNAMIC_MARK}, which it used to share: an implicit
|
|
101
|
+
# conversion (`to_str`, `to_int`) ignores a refinement, so the `global.*` rules must tell the two apart.
|
|
102
|
+
# Every reader that asks whether a surface is rewritten reads both ({.rewritten_surface?}).
|
|
103
|
+
ENVELOPE_MODULE_MARK = :"<module>"
|
|
104
|
+
ENVELOPE_DYNAMIC_MARK = :"<dynamic>"
|
|
105
|
+
ENVELOPE_OBJECT_EXTENDED_MARK = :"<object-extended>"
|
|
106
|
+
ENVELOPE_REFINED_MARK = :"<refined>"
|
|
107
|
+
|
|
108
|
+
# Whether an envelope bucket says the project rewrites the class's method table beyond its literal names: a
|
|
109
|
+
# dynamic rewrite, or a refinement.
|
|
110
|
+
def self.rewritten_surface?(bucket)
|
|
111
|
+
bucket.key?(ENVELOPE_DYNAMIC_MARK) || bucket.key?(ENVELOPE_REFINED_MARK)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Issue #992 — the class key a WHOLE-PROJECT discovery pass adds to `discovered_parameter_envelopes`
|
|
115
|
+
# (`ScopeIndexer#finalize_def_index`), with an empty bucket. A single file's walk alone — `run_source`,
|
|
116
|
+
# the LSP `prebuilt:` scope — sees one `def` and cannot see the reopening, subclass or `class_eval` in
|
|
117
|
+
# another file that would make it opaque, so `call.wrong-arity` reads an envelope only when this key is
|
|
118
|
+
# present. Not a constant character, so no class can be named it.
|
|
119
|
+
ENVELOPE_PROJECT_WIDE = "<project-wide>"
|
|
120
|
+
|
|
55
121
|
# The shared all-empty index `Scope.empty` (and every scope that never sees a seeding pass) points at — one
|
|
56
122
|
# allocation per process.
|
|
57
123
|
EMPTY = new(
|
|
@@ -59,6 +125,12 @@ module Rigor
|
|
|
59
125
|
class_ivars: EMPTY_TABLE,
|
|
60
126
|
class_cvars: EMPTY_TABLE,
|
|
61
127
|
program_globals: EMPTY_TABLE,
|
|
128
|
+
# Issue #1362 — for each global in `program_globals` that Ruby's own signatures declare (`$VERBOSE: bool?`,
|
|
129
|
+
# `$stdout: IO`), its declared type joined with its writes in the file: what every method body and the top
|
|
130
|
+
# level start from, under the ADR-58 `:global` mark. Any other global starts from its `program_globals` entry,
|
|
131
|
+
# which keeps the writes alone for the consumers that compare against them (the mark's gates, and `$;` for
|
|
132
|
+
# `split`). Filled by `Inference::ScopeIndexer.index` from the file's own tree only.
|
|
133
|
+
program_global_seeds: EMPTY_TABLE,
|
|
62
134
|
discovered_classes: EMPTY_TABLE,
|
|
63
135
|
in_source_constants: EMPTY_TABLE,
|
|
64
136
|
discovered_methods: EMPTY_TABLE,
|
|
@@ -79,21 +151,81 @@ module Rigor
|
|
|
79
151
|
discovered_def_sources: EMPTY_TABLE,
|
|
80
152
|
discovered_singleton_def_sources: EMPTY_TABLE,
|
|
81
153
|
discovered_method_visibilities: EMPTY_TABLE,
|
|
154
|
+
# Issue #992 — `{qualified class name => {[kind, method_name] => Source::ParameterEnvelope}}`, the
|
|
155
|
+
# parameter envelope of every method the declaration walk records, plus {ENVELOPE_MODULE_MARK} /
|
|
156
|
+
# {ENVELOPE_DYNAMIC_MARK}. Written beside `discovered_methods` by one recorder, so an `alias` / `attr_*`
|
|
157
|
+
# / `define_method` name is always present here as `OPAQUE`, and folded across files and reopenings
|
|
158
|
+
# with `Source::ParameterEnvelope.merge`: one value per name, a real envelope only while every
|
|
159
|
+
# contribution agrees. Read by `call.wrong-arity` for a method no signature declares.
|
|
160
|
+
discovered_parameter_envelopes: EMPTY_TABLE,
|
|
82
161
|
discovered_superclasses: EMPTY_TABLE,
|
|
162
|
+
# Issue #1097 — `{file path => [[start_offset, end_offset, name, kind, owner], ...]}`, every
|
|
163
|
+
# `def` / block / lambda body range in the file. `Scope#*_def_shadows_call?` reads it to tell
|
|
164
|
+
# an eager class-body call (orderable by offset against a same-name, same-owner def entry)
|
|
165
|
+
# from a deferred one (contained in any range — it runs at invocation time, when every
|
|
166
|
+
# class-body def exists). Def entries carry the method name, the `:instance` / `:singleton` /
|
|
167
|
+
# `:both` (module_function) kind, and the qualified owner; block / lambda rows and defs nested
|
|
168
|
+
# inside another deferred range carry nils and answer only the containment half. Plain data,
|
|
169
|
+
# so the ADR-85 seed bundle round-trips it unchanged.
|
|
170
|
+
discovered_deferred_ranges: EMPTY_TABLE,
|
|
171
|
+
# Issue #1120 — `{refined class name => {method name => [refining module names]}}`, the instance
|
|
172
|
+
# methods a `refine X do … end` block defines. They are not X's methods everywhere: Ruby activates them
|
|
173
|
+
# only lexically after a `using` of the refining module, so `call.undefined-method` reads this table
|
|
174
|
+
# together with the call site's file ({Analysis::CheckRules::LexicalMethodSites}) and never through
|
|
175
|
+
# `discovered_methods`. A refinement a `Module.new { … }` block defines has no nameable module; it is
|
|
176
|
+
# keyed by the name the walk gives the block's owner. Plain data, so the ADR-85 seed bundle
|
|
177
|
+
# round-trips it unchanged.
|
|
178
|
+
discovered_refinements: EMPTY_TABLE,
|
|
179
|
+
# Issue #1367 — the project's `Inference::GlobalWriteCensus`: the globals any `alias` names, the
|
|
180
|
+
# `write` / `to_str` / `to_int` / hatch names any file defines (inside a refinement or not), and the
|
|
181
|
+
# modules a top-level mixin names, over every file and inside method bodies too. The `global.*` write rules
|
|
182
|
+
# read it. The project pre-pass seeds the whole project's census and `Inference::ScopeIndexer.index` adds the
|
|
183
|
+
# analysed file's own. Plain data, so the ADR-85 seed bundle round-trips it unchanged.
|
|
184
|
+
discovered_global_write_census: EMPTY_NAME_SET,
|
|
83
185
|
# Issue #682 — `{qualified class name => Module.nesting where its declaration HEADER is written}`,
|
|
84
186
|
# innermost first and EXCLUDING the declaration's own entry. Read by `Scope#ancestor_name_candidates`,
|
|
85
187
|
# which resolves a superclass / include name in that cref instead of peeling the subclass's qualified
|
|
86
188
|
# name — the peel is the nested spelling's answer, and it searched an `Admin::Base` that a compact
|
|
87
189
|
# `class Admin::Widget < Base` written at the top level never reaches. An absent entry means "not
|
|
88
190
|
# recorded" and keeps the peel, so a scope that never saw a declaration walk is unchanged.
|
|
191
|
+
#
|
|
192
|
+
# Issue #728 — the value is keyed by the ancestor NAME the site wrote, because a class's declaration
|
|
193
|
+
# sites need not share a cref: `class Foo < Base` at the top level and `class ::Foo; include Helper`
|
|
194
|
+
# inside `module Outer` resolve `Base` and `Helper` in different ones, and a single chain per class
|
|
195
|
+
# gave `Outer` to both. {UNKEYED_HEADER_NESTING} holds the union over every ancestor-naming site, for
|
|
196
|
+
# a name no site recorded under its own key.
|
|
89
197
|
discovered_header_nestings: EMPTY_TABLE,
|
|
90
198
|
discovered_includes: EMPTY_TABLE,
|
|
199
|
+
# Issue #1123 — `{qualified class or module name => [module names it `prepend`s, as written]}`,
|
|
200
|
+
# stored in instance-ancestor SEARCH order (nearest prepend first), the `discovered_extends`
|
|
201
|
+
# convention. The instance-side twin `discovered_includes` holds the same names — prepends
|
|
202
|
+
# included — in that order too since #1173: prepends ahead of includes, each nearest-first. The
|
|
203
|
+
# kind still cannot be told apart there, so `Scope#user_def_through_ancestors` reads the wedge
|
|
204
|
+
# from here. An absent entry means "prepends nothing", which is the un-preprended behaviour
|
|
205
|
+
# every scope had before it existed.
|
|
206
|
+
discovered_prepends: EMPTY_TABLE,
|
|
207
|
+
# Issue #898 — the singleton-side twin of `discovered_includes`: `{qualified class or module name =>
|
|
208
|
+
# [module names it `extend`s, as written]}`, built by the same `ScopeIndexer` walk that #526 already
|
|
209
|
+
# ran to fold an extended module's instance defs onto the extending class's singleton. #526 consumed
|
|
210
|
+
# the table inside the indexer and threw it away; `Narrowing` needs it to survive onto the scope,
|
|
211
|
+
# because `Singleton[C]`'s ancestry is exactly what `extend` writes and nothing else records it.
|
|
212
|
+
discovered_extends: EMPTY_TABLE,
|
|
91
213
|
discovered_class_sources: EMPTY_TABLE,
|
|
92
214
|
# Issue #644 — `{qualified constant name => Set[declaring file]}`, the write attribution behind the
|
|
93
215
|
# cross-file value-constant table. Read only by `Scope#record_constant_dependency` during ADR-46
|
|
94
216
|
# dependency recording, so the runner seeds it only on a recording run; every other run leaves it
|
|
95
217
|
# empty and the edge costs one nil check.
|
|
96
218
|
constant_sources: EMPTY_TABLE,
|
|
219
|
+
# Issue #617 — the censused names that bind (any write other than a memo `||=`, or memos of the
|
|
220
|
+
# segment in two files), grouped by LAST SEGMENT, wildcard keys (`*::LIMIT`) under their segment.
|
|
221
|
+
# `Scope#bound_constant_names` reads it for a constant compound write whose plain read resolves to
|
|
222
|
+
# nothing: such a name is bound, just not to a value the analyzer carries. Seeded on every run, because
|
|
223
|
+
# the question is a typing one rather than a recording one.
|
|
224
|
+
constant_writers: EMPTY_TABLE,
|
|
225
|
+
# Issue #1290 — the censused names some write other than a memo `||=` assigns, grouped by LAST SEGMENT.
|
|
226
|
+
# `Scope#shadowing_constant_names` reads it for the lexical ladder: a candidate no source types but this
|
|
227
|
+
# table holds is where Ruby's lookup stops. Seeded on every run beside `constant_writers`.
|
|
228
|
+
constant_shadowers: EMPTY_TABLE,
|
|
97
229
|
# Issue #644 — the two halves of `Scope#published_constant?`, the question
|
|
98
230
|
# {Analysis::CheckRules::PublishedConstantGuard} asks. `published_constant_names` is the LAST
|
|
99
231
|
# SEGMENTS of the project-wide published table (run-wide, seeded by the runner);
|
|
@@ -102,6 +234,16 @@ module Rigor
|
|
|
102
234
|
# author cannot see. Both empty outside a runner-seeded scope, which makes the guard a no-op there.
|
|
103
235
|
published_constant_names: EMPTY_NAME_SET,
|
|
104
236
|
local_constant_names: EMPTY_NAME_SET,
|
|
237
|
+
# Issue #667 — the two per-file tables that carry a published constant's provenance across a COPY,
|
|
238
|
+
# which the name sets above cannot: they answer about a reference's spelling, and a copy has none.
|
|
239
|
+
# `published_constant_alias_names` is the last segments of the constants THIS FILE assigns straight
|
|
240
|
+
# from a foreign published one (`MODE2 = AppConfig::MODE`), which the local-declaration exemption
|
|
241
|
+
# would otherwise release. `published_constant_ivars` is `{class name => Set[ivar name]}` for an ivar
|
|
242
|
+
# whose class-ivar seed is such a copy (`@mode = AppConfig::MODE` in `initialize`), stamped onto the
|
|
243
|
+
# flow carrier at method entry. Both are seeded by `ScopeIndexer.index` and only when the project
|
|
244
|
+
# published something, so a project with no cross-file value constants pays no walk.
|
|
245
|
+
published_constant_alias_names: EMPTY_NAME_SET,
|
|
246
|
+
published_constant_ivars: EMPTY_TABLE,
|
|
105
247
|
data_member_layouts: EMPTY_TABLE,
|
|
106
248
|
struct_member_layouts: EMPTY_TABLE,
|
|
107
249
|
# ADR-67 WD3 — the call-site parameter-inference table, keyed by `[class_name, method_name, kind]` (the
|
|
@@ -117,7 +259,28 @@ module Rigor
|
|
|
117
259
|
# cross a run boundary (LSP / ADR-62 warm-loop re-runs land in a fresh bucket). Nil on scopes that
|
|
118
260
|
# never see the runner seed (single-file probes, `run_source` before the seed applies): the memo
|
|
119
261
|
# falls back to today's per-file `discovered_def_nodes` identity for those.
|
|
120
|
-
run_generation: nil
|
|
262
|
+
run_generation: nil,
|
|
263
|
+
# Issue #1359 — the `gets` / `readline` names this file patches in through the `define_method` family
|
|
264
|
+
# (`$stdin.define_singleton_method(:gets) { … }`, `IO.define_method(:gets)`, `alias_method :gets, :x`, or a
|
|
265
|
+
# computed name, which may be either), which `Inference::LastLine.reads_line?` declines on, as it does on a
|
|
266
|
+
# name `BlockCallTiming.project_defines_anywhere?` finds. Filled by `Inference::ScopeIndexer.index` from the
|
|
267
|
+
# file's own tree only.
|
|
268
|
+
patched_line_readers: EMPTY_NAME_SET,
|
|
269
|
+
# Issue #1360 — true when this file holds a call that may set `$?` to nil (`Inference::LastStatus.clears?`: a
|
|
270
|
+
# `wait`-family call with a flags argument, or `waitall`), which may run between any subprocess and a read of
|
|
271
|
+
# `$?`, so `Inference::LastStatus.after` binds it nowhere in the file. Filled by `Inference::ScopeIndexer.index`
|
|
272
|
+
# from the file's own tree only.
|
|
273
|
+
clears_last_status: false,
|
|
274
|
+
# Issue #1360 — true when this file holds a `define_method` or `define_singleton_method` call whose literal
|
|
275
|
+
# name is `===` (`Inference::ErrorInfo.defines_case_equality?`), which may give a class the singleton `===`
|
|
276
|
+
# `rescue` matches with; the class it lands on is not recorded, so no rescued class binds `$!` in the file.
|
|
277
|
+
# Filled by `Inference::ScopeIndexer.index` from the file's own tree only.
|
|
278
|
+
defines_case_equality: false,
|
|
279
|
+
# Issue #1415 — the file's evidence about the `self` its implicit-self `gets` / `readline` readers run with
|
|
280
|
+
# (`Inference::LastLine::SelfEvidence`, read on the first ask), which `Inference::LastLine.reads_line?` reads
|
|
281
|
+
# them by. Filled by `Inference::ScopeIndexer.index` from the file's own tree only; nil, where no file was
|
|
282
|
+
# indexed, declines every such reader.
|
|
283
|
+
implicit_self_evidence: nil
|
|
121
284
|
)
|
|
122
285
|
end
|
|
123
286
|
end
|