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
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
require_relative "../../type"
|
|
4
4
|
require_relative "../acceptance"
|
|
5
5
|
require_relative "../rbs_type_translator"
|
|
6
|
+
require_relative "alias_strict_nominals"
|
|
7
|
+
require_relative "facet_distribution"
|
|
8
|
+
require_relative "proven_overload"
|
|
6
9
|
require_relative "receiver_affinity"
|
|
7
10
|
|
|
8
11
|
module Rigor
|
|
@@ -14,6 +17,9 @@ module Rigor
|
|
|
14
17
|
# 1. Filter overloads by positional arity (required, optional and rest_positionals are honored;
|
|
15
18
|
# required_keywords disqualify the overload because we do not yet thread keyword args through
|
|
16
19
|
# `call_arg_types`).
|
|
20
|
+
# 1a. **Pass 0 — proven, in declared order (#1344).** With only plain-value arguments, the first
|
|
21
|
+
# overload they do not rule out wins outright when each of its params names its argument's own
|
|
22
|
+
# class and accepts it with a `yes`; every later pass reads the receiver-affinity order instead.
|
|
17
23
|
# 2. **Pass 1 — strict matches first.** Among the arity-matching overloads, prefer the first one
|
|
18
24
|
# whose every (param, arg) pair returns a `yes` or `maybe` answer AND whose param types do NOT
|
|
19
25
|
# translate through `RBS::Types::Alias` / `Interface` / `Intersection`. The translator demotes
|
|
@@ -38,64 +44,57 @@ module Rigor
|
|
|
38
44
|
module OverloadSelector
|
|
39
45
|
module_function
|
|
40
46
|
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
#
|
|
44
|
-
# The translator collapses both aliases to `Dynamic[Top]` (interfaces are not structurally matched
|
|
45
|
-
# yet), so a dedicated pass 1.5 between strict and gradual consults this map to pick the alias
|
|
46
|
-
# whose strict arm matches.
|
|
47
|
-
#
|
|
48
|
-
# Symbol keys are the alias names as they appear under `RBS::Types::Alias#name.to_s` (the `name` is
|
|
49
|
-
# a `TypeName` whose `to_s` includes the `::` prefix). Values are an Array of class names whose
|
|
50
|
-
# Nominal[..] form is the alias's strict-arm matcher.
|
|
51
|
-
ALIAS_STRICT_NOMINALS = {
|
|
52
|
-
"::int" => ["Integer"],
|
|
53
|
-
"::string" => ["String"],
|
|
54
|
-
"::interned" => %w[Symbol String],
|
|
55
|
-
"::io" => ["IO"],
|
|
56
|
-
"::encoding" => %w[Encoding String],
|
|
57
|
-
"::path" => ["String"],
|
|
58
|
-
"::boolean" => %w[TrueClass FalseClass],
|
|
59
|
-
# `range[T] = Range[T] | _Range[T]`. Generic, unlike the others, but the strict arm is still a
|
|
60
|
-
# single nominal and the args are irrelevant to this pass. rbs 4.1 rewrote `Array#[]`'s slicing
|
|
61
|
-
# overload from `(::Range[::Integer?])` to `(range[int])`; without the entry both it and the
|
|
62
|
-
# `(int) -> E` overload look alias-typed, so `a[1..2]` resolved to the element type.
|
|
63
|
-
"::range" => ["Range"]
|
|
64
|
-
}.freeze
|
|
65
|
-
private_constant :ALIAS_STRICT_NOMINALS
|
|
66
|
-
|
|
67
|
-
# @param method_definition [RBS::Definition::Method]
|
|
68
|
-
# @param arg_types [Array<Rigor::Type>] caller-provided types in positional order. Empty when
|
|
47
|
+
# `ALIAS_STRICT_NOMINALS`, the alias-strict pass's table, lives in `alias_strict_nominals.rb`.
|
|
48
|
+
|
|
49
|
+
# @param arg_types — caller-provided types in positional order. Empty when
|
|
69
50
|
# there are no arguments.
|
|
70
|
-
# @param self_type
|
|
71
|
-
# @param instance_type
|
|
72
|
-
# @param type_vars
|
|
51
|
+
# @param self_type — substitute for `Bases::Self`.
|
|
52
|
+
# @param instance_type — substitute for `Bases::Instance`.
|
|
53
|
+
# @param type_vars — substitution map for class-level type variables
|
|
73
54
|
# (Slice 4 phase 2d). The selector threads it through to {RbsTypeTranslator} so parameter types
|
|
74
55
|
# like `::Array[Elem]` substitute Elem before the accepts check, instead of degrading the param
|
|
75
56
|
# to `Array[Dynamic[Top]]`.
|
|
76
|
-
# @param block_required
|
|
57
|
+
# @param block_required — when `true`, only overloads that declare a block clause are
|
|
77
58
|
# considered (Slice 6 phase C sub-phase 1). The fallback also prefers a block-bearing overload
|
|
78
59
|
# over `method_types.first`. When `false` (the Slice 4 phase 2c default) the selector behaves
|
|
79
60
|
# exactly as before: `find` over arity-compatible overloads, falling back to the first
|
|
80
61
|
# declaration.
|
|
81
|
-
# @return
|
|
62
|
+
# @return the chosen overload, or nil when the definition has no method
|
|
82
63
|
# types at all.
|
|
83
|
-
def select(method_definition, **) = select_candidates(method_definition, **).first
|
|
64
|
+
def select(method_definition, **) = select_candidates(method_definition, member_wise: false, **).first
|
|
84
65
|
|
|
85
|
-
# Issue #521 — like {.select}, but when
|
|
86
|
-
#
|
|
87
|
-
#
|
|
66
|
+
# Issue #521 — like {.select}, but when an imprecise argument (`Dynamic[Top]`, or since #1021 a
|
|
67
|
+
# union with a `Dynamic[Top]` member) reaches the gradual pass it returns EVERY gradually-matching
|
|
68
|
+
# overload instead of pinning the first. An untyped argument accepts every param
|
|
69
|
+
# indiscriminately, so "first gradual match" is decided by overload-list
|
|
88
70
|
# position, not by types — `[true] * n` with an untyped `n` pinned `Array#*(string) -> String`
|
|
89
71
|
# and answered a wrong precise type the runtime can contradict. The caller unions the candidates'
|
|
90
|
-
# returns, which contains the truth whichever overload the runtime takes.
|
|
91
|
-
#
|
|
92
|
-
#
|
|
72
|
+
# returns, which contains the truth whichever overload the runtime takes. The member-wise reading of a
|
|
73
|
+
# two-member `Dynamic` facet (#1350, `FacetDistribution`) returns one candidate per member the same way.
|
|
74
|
+
# Every other path (strict, alias-resolved, typed-gradual, arity fallback) yields exactly one candidate,
|
|
75
|
+
# and `select` (`member_wise: false`) keeps its historical single answer.
|
|
93
76
|
#
|
|
94
|
-
# @return
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
77
|
+
# @return matching overloads; empty when the definition declares none.
|
|
78
|
+
# rubocop:disable-next Metrics/ParameterLists -- the selection keywords plus the member-wise switch.
|
|
79
|
+
def select_candidates(definition, arg_types:, self_type:, instance_type:, type_vars: {},
|
|
80
|
+
block_required: false, environment: nil, member_wise: true)
|
|
81
|
+
unless FacetDistribution.faceted?(arg_types)
|
|
82
|
+
return select_declared(definition, arg_types, self_type, instance_type, type_vars, block_required,
|
|
83
|
+
environment, false)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
FacetDistribution.select(arg_types, definition, member_wise:, environment:) do |args, member|
|
|
87
|
+
select_declared(definition, args, self_type, instance_type, type_vars, block_required, environment, member)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# The selection proper, positional so the hot path forwards no keyword hash. A member-wise call (`member`, see
|
|
92
|
+
# `FacetDistribution.select`) answers only a genuine match, never the first-overload fallback.
|
|
93
|
+
# rubocop:disable-next Metrics/ParameterLists -- the selection inputs plus the member-wise flag.
|
|
94
|
+
def select_declared(method_definition, arg_types, self_type, instance_type, type_vars, block_required,
|
|
95
|
+
environment, member)
|
|
96
|
+
declared = method_definition.method_types
|
|
97
|
+
return [] if declared.empty?
|
|
99
98
|
|
|
100
99
|
# `rigor:v1:param: <name> <refinement>` annotations on this method override the RBS-declared
|
|
101
100
|
# parameter type at the matching name. The map is consumed inside `accepts_param?` so overload
|
|
@@ -105,20 +104,18 @@ module Rigor
|
|
|
105
104
|
# Pre-sort: demote overloads whose param class is a disjoint sibling of the receiver class (e.g.
|
|
106
105
|
# `Integer#+(BigDecimal) -> BigDecimal` from the `bigdecimal` RBS reopen). Honors the coerce
|
|
107
106
|
# convention so `5 + ?` for unknown `?` resolves to the receiver-class-preserving arm rather than
|
|
108
|
-
# an arbitrary sibling-class arm that only wins by overload-list position.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
matches = passes.call(block_required)
|
|
107
|
+
# an arbitrary sibling-class arm that only wins by overload-list position. The proven pass keeps
|
|
108
|
+
# the declared order (see `run_selection_passes`).
|
|
109
|
+
overloads = ReceiverAffinity.reorder(declared, self_type: self_type, environment: environment)
|
|
110
|
+
|
|
111
|
+
# One keyword bundle for the pass pipeline (see `run_selection_passes`); a block retry rebuilds it
|
|
112
|
+
# with the block flag cleared. Built once and passed positionally -- the previous lambda plus a
|
|
113
|
+
# `**shared` splat per pass allocated three objects per selection (#775).
|
|
114
|
+
shared = { arg_types: arg_types, self_type: self_type, instance_type: instance_type,
|
|
115
|
+
type_vars: type_vars, block_required: block_required, param_overrides: param_overrides,
|
|
116
|
+
alias_expander: environment&.rbs_loader, environment: environment }
|
|
117
|
+
|
|
118
|
+
matches = run_selection_passes(declared, overloads, shared)
|
|
122
119
|
return matches unless matches.empty?
|
|
123
120
|
|
|
124
121
|
# A block at the call site that no block-declaring overload matched: Ruby ignores a block handed
|
|
@@ -127,9 +124,10 @@ module Rigor
|
|
|
127
124
|
# `define_command(:x) do … end` against `def define_command: (Symbol) -> Symbol`) degraded to
|
|
128
125
|
# `Dynamic[Top]` — and on a self-send suppressed the whole method's return type.
|
|
129
126
|
if block_required
|
|
130
|
-
matches =
|
|
127
|
+
matches = run_selection_passes(declared, overloads, shared.merge(block_required: false))
|
|
131
128
|
return matches unless matches.empty?
|
|
132
129
|
end
|
|
130
|
+
return [] if member
|
|
133
131
|
|
|
134
132
|
# No (usable) block at the call site: prefer an overload that does not REQUIRE a block over
|
|
135
133
|
# `overloads.first`. Methods like `Array#filter` / `Enumerable#map` declare the block-bearing
|
|
@@ -154,18 +152,30 @@ module Rigor
|
|
|
154
152
|
class << self
|
|
155
153
|
private
|
|
156
154
|
|
|
157
|
-
#
|
|
158
|
-
# - Pass 1 (strict): skipped when any arg is `
|
|
159
|
-
# an untyped arg accepts every param indiscriminately and would let pass 1
|
|
160
|
-
# strict overload (e.g. `Regexp#=~(nil) -> nil` over the
|
|
155
|
+
# Overload search after pass 0 (`find_proven_overload`):
|
|
156
|
+
# - Pass 1 (strict): skipped when any arg is imprecise (`imprecise_arg?`), because gradual
|
|
157
|
+
# acceptance against an untyped arg accepts every param indiscriminately and would let pass 1
|
|
158
|
+
# lock in an arbitrary strict overload (e.g. `Regexp#=~(nil) -> nil` over the
|
|
159
|
+
# `(::interned?) -> Integer?` overload).
|
|
161
160
|
# - Pass 1.5 (alias-resolved): consults each `RBS::Types::Alias`'s strict arm so e.g.
|
|
162
161
|
# `Array#*(int)` wins over the `Array#*(string) -> String` overload for Integer args.
|
|
163
162
|
# - Pass 2 (gradual): the original gradual matcher so overloads that legitimately rely on
|
|
164
163
|
# duck-typed params still resolve when nothing stricter applies.
|
|
165
164
|
# `shared` is the caller-assembled keyword bundle for `find_matching_overload` — hash-shaped
|
|
166
165
|
# because the pass pipeline forwards it twice and RuboCop's parameter-list budget is real.
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
#
|
|
167
|
+
# Pass 0 (#1344) comes first and reads the overloads in declared order; every later pass reads them
|
|
168
|
+
# in receiver-affinity order (`ReceiverAffinity`). RBS resolves two arms that both take an argument by
|
|
169
|
+
# declaration order: `Rational#+` declares `(Float) -> Float` before `(Numeric) -> Rational`, and the
|
|
170
|
+
# affinity order, which moves the `(Numeric)` arm first, typed `Rational(1, 2) + 0.5` as `Rational`
|
|
171
|
+
# where Ruby answers `1.0`. The affinity order stays for every call pass 0 declines: read in declared
|
|
172
|
+
# order, the strict pass let the `bigdecimal` reopen's `(BigDecimal) -> BigDecimal` arm, which it
|
|
173
|
+
# matches on a `maybe`, take `Integer#+` of a `bot`, a `Dynamic[Integer | Float | …]` or an
|
|
174
|
+
# unloadable class (612 call sites across the survey corpus).
|
|
175
|
+
def run_selection_passes(declared, overloads, shared)
|
|
176
|
+
# Unreordered, pass 0 can only pick what the strict pass picks, so it is skipped (#1344's allocations).
|
|
177
|
+
proven = find_proven_overload(declared, shared) unless overloads.equal?(declared)
|
|
178
|
+
strict = proven || find_matching_overload(overloads, shared, strict: true)
|
|
169
179
|
return strict unless strict.empty?
|
|
170
180
|
|
|
171
181
|
alias_hit = find_matching_overload_via_aliases(
|
|
@@ -174,36 +184,58 @@ module Rigor
|
|
|
174
184
|
return [alias_hit] if alias_hit
|
|
175
185
|
|
|
176
186
|
# Pass 2, array-valued. With every argument carrying real type information the first gradual
|
|
177
|
-
# match keeps its historical single-winner contract. With
|
|
187
|
+
# match keeps its historical single-winner contract. With an imprecise argument in play the
|
|
178
188
|
# matches are indistinguishable by types — position alone would pick — so ALL of them come back
|
|
179
189
|
# and the dispatch layer unions their returns (#521).
|
|
180
|
-
matches = find_matching_overload(overloads,
|
|
181
|
-
return matches.first(1) unless shared[:arg_types].any? { |t|
|
|
190
|
+
matches = find_matching_overload(overloads, shared, strict: false)
|
|
191
|
+
return matches.first(1) unless shared[:arg_types].any? { |t| imprecise_arg?(t) }
|
|
182
192
|
|
|
183
193
|
matches
|
|
184
194
|
end
|
|
185
195
|
|
|
186
|
-
#
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
196
|
+
# Pass 0. With every argument a plain value (a `Constant`, or a `Nominal` with no type arguments), the
|
|
197
|
+
# first overload in declared order that the arguments do not rule out is the one RBS would take, and
|
|
198
|
+
# the pass takes it only when that is certain: every parameter is a lone class naming its argument's
|
|
199
|
+
# own class, and accepts it with a `yes`. Any doubt declines to the affinity-ordered passes. A `maybe`
|
|
200
|
+
# is doubt — the analyzer process cannot load a project class, so a declared `(Base)` only maybe
|
|
201
|
+
# takes a `Sub`, and taking a later `(top)` arm instead typed the call wrong. So is a union or
|
|
202
|
+
# supertype parameter, which takes the argument through a declaration upstream RBS can get wrong:
|
|
203
|
+
# `Rational#divmod`'s `(Integer | Float | Rational) -> [Integer, Rational]` for a Float remainder.
|
|
204
|
+
def find_proven_overload(declared, shared)
|
|
205
|
+
args = shared[:arg_types]
|
|
206
|
+
return nil unless ProvenOverload.applies?(args)
|
|
207
|
+
|
|
208
|
+
index = declared.index { |mt| engages_block_shape?(mt, shared[:block_required]) && matches?(mt, shared) }
|
|
209
|
+
first = index && declared[index]
|
|
210
|
+
proven = first && strictly_typed_params?(first, args.size) && matches?(first, shared, strict: :proven)
|
|
211
|
+
[first] if proven && !ProvenOverload.contested?(declared, index, args, shared[:environment])
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# The shared "no overload matched" answer; every consumer only reads the list.
|
|
215
|
+
NO_MATCH = [].freeze
|
|
216
|
+
private_constant :NO_MATCH
|
|
190
217
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
type_vars: type_vars, param_overrides: param_overrides,
|
|
199
|
-
alias_expander: alias_expander
|
|
200
|
-
)
|
|
201
|
-
end
|
|
218
|
+
# `shared` is the keyword bundle `select_candidates` assembled (arg_types, self_type, instance_type,
|
|
219
|
+
# type_vars, block_required, param_overrides, alias_expander).
|
|
220
|
+
def find_matching_overload(overloads, shared, strict:)
|
|
221
|
+
arg_types = shared[:arg_types]
|
|
222
|
+
return NO_MATCH if strict && arg_types.any? { |t| imprecise_arg?(t) }
|
|
223
|
+
|
|
224
|
+
block_required = shared[:block_required]
|
|
202
225
|
# Strict keeps its historical first-match short-circuit (a dispatch hot path); the gradual
|
|
203
226
|
# pass needs the full candidate list for the #521 union.
|
|
204
|
-
|
|
227
|
+
if strict
|
|
228
|
+
found = overloads.find do |method_type|
|
|
229
|
+
engages_block_shape?(method_type, block_required) &&
|
|
230
|
+
strictly_typed_params?(method_type, arg_types.size) &&
|
|
231
|
+
matches?(method_type, shared, strict: true)
|
|
232
|
+
end
|
|
233
|
+
return found ? [found] : NO_MATCH
|
|
234
|
+
end
|
|
205
235
|
|
|
206
|
-
overloads.select
|
|
236
|
+
overloads.select do |method_type|
|
|
237
|
+
engages_block_shape?(method_type, block_required) && matches?(method_type, shared)
|
|
238
|
+
end
|
|
207
239
|
end
|
|
208
240
|
|
|
209
241
|
# Whether the overload's block clause is compatible with the call site's block shape: a
|
|
@@ -218,8 +250,17 @@ module Rigor
|
|
|
218
250
|
# Treats the literal `untyped` carrier (`Dynamic[Top]`) as too imprecise to drive a strict-pass
|
|
219
251
|
# match. Other `Dynamic`-wrapped types with a concrete static facet carry enough information to
|
|
220
252
|
# pick a sensible overload.
|
|
221
|
-
def untyped_arg?(type)
|
|
222
|
-
|
|
253
|
+
def untyped_arg?(type) = type.is_a?(Type::Dynamic) && type.static_facet.is_a?(Type::Top)
|
|
254
|
+
|
|
255
|
+
# Issue #1021 — the strict and alias passes must not discriminate on an argument whose type
|
|
256
|
+
# cannot rule an overload out: the bare untyped carrier, or a union with an untyped member. That
|
|
257
|
+
# member may reach any overload at runtime, so a strict match is decided by the union's other
|
|
258
|
+
# members alone — `Dynamic[top] | nil` pinned `Regexp#match?(nil) -> false` and typed a live
|
|
259
|
+
# predicate as the literal `false`. The gradual pass still accepts against the whole union, so
|
|
260
|
+
# `Dynamic[top] | nil` keeps both `match?` overloads and the #521 join answers `Dynamic[bool]`.
|
|
261
|
+
# A `Dynamic` with a concrete static facet stays out: its facet discriminates.
|
|
262
|
+
def imprecise_arg?(type)
|
|
263
|
+
untyped_arg?(type) || (type.is_a?(Type::Union) && type.members.any? { |member| untyped_arg?(member) })
|
|
223
264
|
end
|
|
224
265
|
|
|
225
266
|
# Pass 1.5: for arity-compatible overloads whose every positional param is either a strict
|
|
@@ -232,7 +273,7 @@ module Rigor
|
|
|
232
273
|
# Issue #521 — an untyped argument "maybe"-accepts EVERY alias's strict arm, so it cannot
|
|
233
274
|
# discriminate between overloads here any more than in the strict pass; without this guard a
|
|
234
275
|
# Dynamic arg pinned `Array#*(string) -> String` purely by declaration order.
|
|
235
|
-
return nil if arg_types.any? { |t|
|
|
276
|
+
return nil if arg_types.any? { |t| imprecise_arg?(t) }
|
|
236
277
|
|
|
237
278
|
overloads.find do |method_type|
|
|
238
279
|
next false unless engages_block_shape?(method_type, block_required)
|
|
@@ -243,10 +284,19 @@ module Rigor
|
|
|
243
284
|
params = positional_params_for(fun, arg_types.size)
|
|
244
285
|
next false unless params.size == arg_types.size
|
|
245
286
|
|
|
246
|
-
params
|
|
287
|
+
each_param_accepts?(params, arg_types) { |param, arg| alias_param_accepts?(param.type, arg) }
|
|
247
288
|
end
|
|
248
289
|
end
|
|
249
290
|
|
|
291
|
+
# `params.zip(arg_types).all? { |param, arg| ... }` without the pair arrays: a formal beyond the
|
|
292
|
+
# actuals meets `nil`, exactly as `zip` pads. Selection zips once per overload per pass, so the
|
|
293
|
+
# pairs were a top allocation site of dispatch (#775). The counter is a captured local, so the
|
|
294
|
+
# walk allocates nothing (a Range or an Enumerator would be one object per overload per pass).
|
|
295
|
+
def each_param_accepts?(params, arg_types)
|
|
296
|
+
index = -1
|
|
297
|
+
params.all? { |param| yield(param, arg_types[index += 1]) }
|
|
298
|
+
end
|
|
299
|
+
|
|
250
300
|
# Checks the param's RBS type against an arg using alias-strict-arm matching. Optional / Union
|
|
251
301
|
# wrappers are flattened; alias resolution is one level deep (the canonical core aliases all have
|
|
252
302
|
# non-alias strict arms).
|
|
@@ -317,25 +367,17 @@ module Rigor
|
|
|
317
367
|
end
|
|
318
368
|
end
|
|
319
369
|
|
|
320
|
-
|
|
321
|
-
|
|
370
|
+
# `shared` is the keyword bundle `select_candidates` assembled (see `find_matching_overload`).
|
|
371
|
+
# `strict:` is `false` (gradual), `true` (strict pass) or `:proven` (pass 0; see `find_proven_overload`).
|
|
372
|
+
def matches?(method_type, shared, strict: false)
|
|
322
373
|
return false if method_type.respond_to?(:type_params) && rejects_keyword_required?(method_type)
|
|
323
374
|
|
|
375
|
+
arg_types = shared[:arg_types]
|
|
324
376
|
fun = method_type.type
|
|
325
377
|
return false unless arity_compatible?(fun, arg_types.size)
|
|
326
378
|
|
|
327
379
|
params = positional_params_for(fun, arg_types.size)
|
|
328
|
-
params
|
|
329
|
-
accepts_param?(
|
|
330
|
-
param,
|
|
331
|
-
arg,
|
|
332
|
-
self_type: self_type,
|
|
333
|
-
instance_type: instance_type,
|
|
334
|
-
type_vars: type_vars,
|
|
335
|
-
param_overrides: param_overrides,
|
|
336
|
-
alias_expander: alias_expander
|
|
337
|
-
)
|
|
338
|
-
end
|
|
380
|
+
each_param_accepts?(params, arg_types) { |param, arg| accepts_param?(param, arg, shared, strict) }
|
|
339
381
|
end
|
|
340
382
|
|
|
341
383
|
# Slice 4 phase 2c does not pass keyword arguments through the call site (caller passes only
|
|
@@ -376,8 +418,12 @@ module Rigor
|
|
|
376
418
|
rest = fun.rest_positionals
|
|
377
419
|
trailing = fun.trailing_positionals
|
|
378
420
|
|
|
421
|
+
optional_needed = [actual_count - required.size - trailing.size, 0].max
|
|
422
|
+
# Nothing to append: the declaration's own list is the answer, read-only (the common
|
|
423
|
+
# required-positionals-only overload -- no copy, #775).
|
|
424
|
+
return required if optional_needed.zero? && trailing.empty? && (rest.nil? || actual_count <= required.size)
|
|
425
|
+
|
|
379
426
|
head = required.dup
|
|
380
|
-
optional_needed = [actual_count - head.size - trailing.size, 0].max
|
|
381
427
|
head.concat(optional.first(optional_needed))
|
|
382
428
|
|
|
383
429
|
absorbed_by_rest = actual_count - head.size - trailing.size
|
|
@@ -387,14 +433,14 @@ module Rigor
|
|
|
387
433
|
head
|
|
388
434
|
end
|
|
389
435
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
param_type = param_overrides[param.name] || RbsTypeTranslator.translate(
|
|
436
|
+
# `shared` is the keyword bundle `select_candidates` assembled (see `find_matching_overload`).
|
|
437
|
+
def accepts_param?(param, arg, shared, strict)
|
|
438
|
+
param_type = shared[:param_overrides][param.name] || RbsTypeTranslator.translate(
|
|
393
439
|
param.type,
|
|
394
|
-
self_type: self_type,
|
|
395
|
-
instance_type: instance_type,
|
|
396
|
-
type_vars: type_vars,
|
|
397
|
-
alias_expander: alias_expander
|
|
440
|
+
self_type: shared[:self_type],
|
|
441
|
+
instance_type: shared[:instance_type],
|
|
442
|
+
type_vars: shared[:type_vars],
|
|
443
|
+
alias_expander: shared[:alias_expander]
|
|
398
444
|
)
|
|
399
445
|
# An `untyped` arg gradually accepts against every param, so a value-pinning param would be
|
|
400
446
|
# "matched" with zero evidence and its value-precise return (`(nil) -> []`) would beat broader
|
|
@@ -404,6 +450,14 @@ module Rigor
|
|
|
404
450
|
return false if untyped_arg?(arg) && value_pinning?(param_type)
|
|
405
451
|
|
|
406
452
|
result = param_type.accepts(arg, mode: :gradual)
|
|
453
|
+
return result.yes? && ProvenOverload.names_arg_class?(param_type, arg) if strict == :proven
|
|
454
|
+
|
|
455
|
+
# A record's `maybe` for a `Hash` with a gradual arm or an open shape is no evidence for the overload:
|
|
456
|
+
# with `({ a: Integer }) -> Integer | (Hash[Symbol, untyped]) -> String`, `{ **o, b: 2 }` has a key the
|
|
457
|
+
# closed record forbids, yet the first overload won by list position. The gradual pass still takes it.
|
|
458
|
+
# A `maybe` that survives with those records answering `no` has another source, and still counts.
|
|
459
|
+
return false if strict && result.maybe? && Acceptance.maybe_rests_on_unread_hash?(param_type, arg)
|
|
460
|
+
|
|
407
461
|
result.yes? || result.maybe?
|
|
408
462
|
end
|
|
409
463
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../type"
|
|
4
|
+
require_relative "singleton_folding"
|
|
5
|
+
|
|
6
|
+
module Rigor
|
|
7
|
+
module Inference
|
|
8
|
+
module MethodDispatcher
|
|
9
|
+
# `Process` class-method calls that read flow state.
|
|
10
|
+
#
|
|
11
|
+
# `Process.last_status` answers the thread's last child status, the slot `$?` reads (both are
|
|
12
|
+
# `rb_last_status_get` in CRuby's `process.c`). `data/core_overlay/process.rbs` declares it
|
|
13
|
+
# `() -> Process::Status?`, which is right where nothing is known. But past a statement that certainly
|
|
14
|
+
# ran a subprocess the flow engine has already bound `$?` to a non-nil `Process::Status`
|
|
15
|
+
# ({Inference::LastStatus}); answering the declared return there would put back the possible nil
|
|
16
|
+
# receiver the binding exists to remove as soon as the code reaches the status through the method
|
|
17
|
+
# rather than the global (`system("make"); Process.last_status.success?`). The same reasoning, for
|
|
18
|
+
# `Regexp.last_match` and `$~`, is {RegexpFolding.fold_last_match}.
|
|
19
|
+
#
|
|
20
|
+
# A bound `$?` is answered as it stands, so the method reads what the global reads in every body the
|
|
21
|
+
# binding rules reach, `Dynamic[top]` in a `define_method` body included. The consult never invents a
|
|
22
|
+
# binding: where `$?` is unbound (rescue clauses, closures, thread roots, joins with a path that ran no
|
|
23
|
+
# subprocess) it declines to the declaration. It also declines an argument-bearing call, whose arity
|
|
24
|
+
# the RBS tier reports.
|
|
25
|
+
#
|
|
26
|
+
# A project that defines `Process.last_status` itself answers `Dynamic[top]`: its method may return
|
|
27
|
+
# anything, and declining would hand the call to the overlay's declaration, which outranks a
|
|
28
|
+
# discovered method. A definition the discovery pass does not record — `def Process.last_status` outside
|
|
29
|
+
# `module Process`, `define_singleton_method`, `alias_method`, a prepended module — keeps the binding's answer.
|
|
30
|
+
module ProcessFolding
|
|
31
|
+
module_function
|
|
32
|
+
|
|
33
|
+
# @return the answer, or nil to defer.
|
|
34
|
+
def try_dispatch(context)
|
|
35
|
+
return nil unless SingletonFolding.receiver?(context.receiver, "Process")
|
|
36
|
+
return nil unless context.method_name == :last_status && context.args.empty?
|
|
37
|
+
|
|
38
|
+
scope = context.scope
|
|
39
|
+
return nil if scope.nil?
|
|
40
|
+
return Type::Combinator.untyped if project_defines_last_status?(scope)
|
|
41
|
+
|
|
42
|
+
scope.global(:$?)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def project_defines_last_status?(scope)
|
|
46
|
+
return true if scope.discovered_method?("Process", :last_status, :singleton)
|
|
47
|
+
return true if scope.discovered_singleton_def_nodes["Process"]&.key?(:last_status)
|
|
48
|
+
|
|
49
|
+
patched = scope.environment&.project_patched_methods
|
|
50
|
+
!patched.nil? && !patched.lookup(class_name: "Process", method_name: :last_status, kind: :singleton).nil?
|
|
51
|
+
end
|
|
52
|
+
private_class_method :project_defines_last_status?
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../type"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Inference
|
|
7
|
+
module MethodDispatcher
|
|
8
|
+
# The value tests of `OverloadSelector`'s pass 0 (#1344), which reads the overloads in declared order and
|
|
9
|
+
# takes the first one plain-value arguments do not rule out, when that one names each argument's own class.
|
|
10
|
+
#
|
|
11
|
+
# Acceptance reads class relations from the analyzer's own process, which cannot load a project class or
|
|
12
|
+
# module, so it can rule an arm out wrongly: `(Printable)` against `1`, where project RBS includes
|
|
13
|
+
# `Printable` into `Integer`, answers `no`, and taking the `(Integer)` arm declared after it typed the call
|
|
14
|
+
# as that arm's return and fired `call.undefined-method` on correct code. {.contested?} therefore trusts
|
|
15
|
+
# an earlier arm to be out only when it can prove it: every positional parameter, rest included, is a plain
|
|
16
|
+
# class (through `?` and `|`), and both orderings — `Environment#class_ordering`, which asks the host class
|
|
17
|
+
# registry first, and the RBS loader's own — call it disjoint from every argument's class. A type alias,
|
|
18
|
+
# interface or variable proves nothing, and the host registry alone calls `Integer` and `Enumerable`
|
|
19
|
+
# disjoint where project RBS includes one into the other. Nor does a module, or a name Rigor stubbed because
|
|
20
|
+
# no RBS declares it: the source can include a module into the argument's class where no RBS says so, and
|
|
21
|
+
# neither ordering sees a source-only `include` (#1351). A class cannot be included, so a declared class
|
|
22
|
+
# stays provable.
|
|
23
|
+
module ProvenOverload
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
# Every argument is a plain value: a `Constant`, or a `Nominal` with no type arguments.
|
|
27
|
+
def applies?(arg_types)
|
|
28
|
+
!arg_types.empty? && arg_types.all? do |arg|
|
|
29
|
+
arg.is_a?(Type::Constant) || (arg.is_a?(Type::Nominal) && arg.type_args.empty?)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def names_arg_class?(param, arg) = param.is_a?(Type::Nominal) && param.class_name == class_name_of(arg)
|
|
34
|
+
|
|
35
|
+
def class_name_of(arg) = arg.is_a?(Type::Constant) ? arg.value.class.name : arg.class_name
|
|
36
|
+
|
|
37
|
+
# Whether an overload declared before `declared[index]` may take the arguments after all.
|
|
38
|
+
def contested?(declared, index, arg_types, environment)
|
|
39
|
+
loader = environment&.rbs_loader
|
|
40
|
+
return true if loader.nil?
|
|
41
|
+
|
|
42
|
+
arg_names = arg_types.map { |arg| class_name_of(arg) }
|
|
43
|
+
(0...index).any? { |position| !proven_out?(declared[position], arg_names, environment, loader) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def proven_out?(method_type, arg_names, environment, loader)
|
|
47
|
+
fun = method_type.type
|
|
48
|
+
return false unless fun.respond_to?(:required_positionals)
|
|
49
|
+
|
|
50
|
+
params = fun.required_positionals + fun.optional_positionals + fun.trailing_positionals
|
|
51
|
+
params += [fun.rest_positionals] if fun.rest_positionals
|
|
52
|
+
params.all? { |param| disjoint_param?(param.type, arg_names, environment, loader) }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def disjoint_param?(rbs_type, arg_names, environment, loader)
|
|
56
|
+
case rbs_type
|
|
57
|
+
when RBS::Types::ClassInstance
|
|
58
|
+
name = rbs_type.name.to_s.delete_prefix("::")
|
|
59
|
+
return false if loader.rbs_module?(name) || loader.synthesized_type_names.include?(name)
|
|
60
|
+
|
|
61
|
+
arg_names.all? do |arg|
|
|
62
|
+
environment.class_ordering(arg, name) == :disjoint && loader.class_ordering(arg, name) == :disjoint
|
|
63
|
+
end
|
|
64
|
+
when RBS::Types::Optional then disjoint_param?(rbs_type.type, arg_names, environment, loader)
|
|
65
|
+
when RBS::Types::Union then rbs_type.types.all? { |member| disjoint_param?(member, arg_names, environment, loader) }
|
|
66
|
+
else false
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../type"
|
|
4
|
+
require_relative "singleton_folding"
|
|
5
|
+
|
|
6
|
+
module Rigor
|
|
7
|
+
module Inference
|
|
8
|
+
module MethodDispatcher
|
|
9
|
+
# ADR-109 — the interval a random draw over a literal range lands in. `Random.rand` and
|
|
10
|
+
# `Kernel#rand` advance a generator, so no call folds to a constant ({Builtins::RANDOM_CATALOG}
|
|
11
|
+
# says why); but a draw over `a..b` returns a value the range covers, and that is a bounded
|
|
12
|
+
# carrier of the range's own class, keeping its written end:
|
|
13
|
+
#
|
|
14
|
+
# rand(1..6) -> Integer[1..6]
|
|
15
|
+
# rand(1...6) -> Integer[1..5]
|
|
16
|
+
# rand(0.0...1.0) -> Float[0.0...1.0]
|
|
17
|
+
# Random.rand(1.0..2.0) -> Float[1.0..2.0]
|
|
18
|
+
#
|
|
19
|
+
# An empty range (`rand(5..1)` returns nil, `Random.rand(5..1)` raises), an unbounded one
|
|
20
|
+
# (`Errno::EDOM`) and a non-literal argument decline to the RBS envelope. The other argument
|
|
21
|
+
# shapes (`rand`, `rand(n)`, `rand(1.5)`) are deliberately NOT folded: the corpus uses them as its
|
|
22
|
+
# "unknown Integer / Float" oracle, and their intervals belong to a change that replaces that
|
|
23
|
+
# oracle first. The `Kernel` spelling is folded by {KernelDispatch#try_rand} behind ADR-91's
|
|
24
|
+
# ownership gate; this module owns `Singleton[Random]` and the shared interval reading.
|
|
25
|
+
module RandomFolding
|
|
26
|
+
module_function
|
|
27
|
+
|
|
28
|
+
def try_dispatch(context)
|
|
29
|
+
return nil unless SingletonFolding.receiver?(context.receiver, "Random")
|
|
30
|
+
return nil unless context.method_name == :rand
|
|
31
|
+
|
|
32
|
+
interval_for_args(context.args)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# The bounded carrier a one-argument draw over a literal range lands in, or `nil` for any other
|
|
36
|
+
# argument shape.
|
|
37
|
+
def interval_for_args(args)
|
|
38
|
+
return nil unless args.size == 1
|
|
39
|
+
|
|
40
|
+
arg = args.first
|
|
41
|
+
return nil unless arg.is_a?(Type::Constant) && arg.value.is_a?(Range)
|
|
42
|
+
|
|
43
|
+
range_interval(arg.value)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def range_interval(range)
|
|
47
|
+
lower = range.begin
|
|
48
|
+
upper = range.end
|
|
49
|
+
return nil unless real_endpoint?(lower) && real_endpoint?(upper)
|
|
50
|
+
|
|
51
|
+
if lower.is_a?(Integer) && upper.is_a?(Integer)
|
|
52
|
+
integer_range_interval(lower, upper, range.exclude_end?)
|
|
53
|
+
else
|
|
54
|
+
float_range_interval(lower.to_f, upper.to_f, range.exclude_end?)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# A finite Integer or Float; a missing end is `Errno::EDOM` at run time.
|
|
59
|
+
def real_endpoint?(value)
|
|
60
|
+
case value
|
|
61
|
+
when Integer then true
|
|
62
|
+
when Float then value.finite?
|
|
63
|
+
else false
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def integer_range_interval(lower, upper, exclusive)
|
|
68
|
+
upper -= 1 if exclusive
|
|
69
|
+
return nil if lower > upper
|
|
70
|
+
|
|
71
|
+
Type::Combinator.integer_range(lower, upper)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def float_range_interval(lower, upper, exclusive)
|
|
75
|
+
return nil if lower > (exclusive ? upper.prev_float : upper)
|
|
76
|
+
|
|
77
|
+
Type::Combinator.float_range(lower, upper, exclude_end: exclusive)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|