rigortype 0.4.5 → 0.4.7
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/gem_overlay/activesupport/core_ext.rbs +16 -13
- data/data/vendored_gem_sigs/bundler/bundler.rbs +1 -1
- data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +4 -3
- data/docs/handbook/01-getting-started.md +5 -2
- data/docs/handbook/11-sig-gen.md +61 -5
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/manual/02-cli-reference.md +192 -27
- data/docs/manual/03-configuration.md +38 -4
- data/docs/manual/04-diagnostics.md +1 -1
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/09-editor-integration.md +13 -2
- data/docs/manual/10-mcp-server.md +47 -3
- data/docs/manual/12-caching.md +9 -1
- data/docs/manual/plugins/rigor-actionmailer.md +30 -0
- data/docs/manual/plugins/rigor-actionpack.md +49 -11
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +20 -1
- data/docs/manual/plugins/rigor-devise.md +15 -0
- data/docs/manual/plugins/rigor-rspec.md +2 -1
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/buffer_binding.rb +14 -0
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +4 -4
- data/lib/rigor/analysis/check_rules/duplicate_hash_key_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +105 -12
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +143 -15
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +4 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +1 -1
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +66 -3
- data/lib/rigor/analysis/check_rules/rebinding_block_callees/dispatch.rb +112 -0
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +394 -0
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/ruby_deprecations.rb +7 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +9 -7
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +3 -4
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +3 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +53 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules.rb +217 -52
- data/lib/rigor/analysis/crash_signature.rb +2 -2
- data/lib/rigor/analysis/dependency_recorder.rb +15 -4
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +14 -3
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/index.rb +6 -8
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/edit_replay.rb +154 -0
- data/lib/rigor/analysis/fact_store.rb +3 -3
- data/lib/rigor/analysis/incremental.rb +37 -0
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +2 -2
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +202 -43
- data/lib/rigor/analysis/path_expansion.rb +41 -0
- data/lib/rigor/analysis/require_relative_closure.rb +100 -0
- data/lib/rigor/analysis/rule_catalog.rb +7 -3
- data/lib/rigor/analysis/run_disclosure_credit.rb +80 -0
- data/lib/rigor/analysis/run_disclosure_ledger.rb +155 -0
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +8 -4
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -1
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +204 -96
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +1 -1
- data/lib/rigor/analysis/runner/pool_coordinator.rb +157 -320
- data/lib/rigor/analysis/runner/project_pre_passes.rb +48 -6
- data/lib/rigor/analysis/runner/run_level_facts.rb +304 -0
- data/lib/rigor/analysis/runner/run_snapshots.rb +44 -54
- data/lib/rigor/analysis/runner/scan_environment.rb +51 -0
- data/lib/rigor/analysis/runner/worker_payload.rb +36 -0
- data/lib/rigor/analysis/runner.rb +233 -120
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +1 -1
- data/lib/rigor/analysis/template_unit_positions.rb +2 -3
- data/lib/rigor/analysis/template_units.rb +9 -1
- data/lib/rigor/analysis/worker_session.rb +38 -33
- data/lib/rigor/bleeding_edge.rb +3 -6
- data/lib/rigor/builtins/imported_refinements.rb +6 -8
- data/lib/rigor/builtins/predefined_constant_refinements.rb +1 -1
- data/lib/rigor/builtins/regex_refinement.rb +4 -6
- data/lib/rigor/cache/descriptor.rb +6 -5
- data/lib/rigor/cache/incremental_snapshot.rb +60 -18
- data/lib/rigor/cache/rbs_cache_producer.rb +2 -2
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +1 -1
- data/lib/rigor/cache/rbs_class_type_param_names.rb +2 -2
- data/lib/rigor/cache/rbs_constant_table.rb +1 -1
- data/lib/rigor/cache/rbs_descriptor.rb +54 -3
- data/lib/rigor/cache/rbs_environment.rb +4 -1
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +2 -2
- data/lib/rigor/cache/rbs_known_class_names.rb +1 -1
- data/lib/rigor/cache/store.rb +11 -10
- data/lib/rigor/ci_detector.rb +1 -1
- data/lib/rigor/cli/annotate_command.rb +24 -19
- data/lib/rigor/cli/baseline_command.rb +145 -55
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +188 -93
- data/lib/rigor/cli/check_runner_factory.rb +2 -2
- data/lib/rigor/cli/command.rb +15 -1
- data/lib/rigor/cli/coverage_command.rb +21 -8
- data/lib/rigor/cli/coverage_mutation.rb +5 -7
- data/lib/rigor/cli/coverage_renderer.rb +2 -1
- data/lib/rigor/cli/coverage_scan.rb +3 -5
- data/lib/rigor/cli/diff_command.rb +27 -21
- data/lib/rigor/cli/docs_command.rb +1 -2
- data/lib/rigor/cli/doctor_command.rb +12 -12
- data/lib/rigor/cli/effects_command.rb +50 -40
- data/lib/rigor/cli/effects_diff_renderer.rb +18 -17
- data/lib/rigor/cli/effects_explain_renderer.rb +13 -12
- data/lib/rigor/cli/effects_renderer.rb +2 -1
- data/lib/rigor/cli/effects_snapshot_command.rb +18 -17
- data/lib/rigor/cli/explain_command.rb +18 -8
- data/lib/rigor/cli/fused_protection_renderer.rb +2 -1
- data/lib/rigor/cli/json_document.rb +41 -0
- data/lib/rigor/cli/lens_command.rb +17 -13
- data/lib/rigor/cli/lsp_command.rb +250 -23
- data/lib/rigor/cli/mcp_command.rb +14 -8
- data/lib/rigor/cli/mutation_fork_scan.rb +1 -1
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -2
- data/lib/rigor/cli/options.rb +60 -4
- data/lib/rigor/cli/plugin_command.rb +93 -46
- data/lib/rigor/cli/plugins_command.rb +22 -18
- data/lib/rigor/cli/plugins_renderer.rb +34 -8
- data/lib/rigor/cli/protection_fork_scan.rb +2 -2
- data/lib/rigor/cli/protection_renderer.rb +2 -1
- data/lib/rigor/cli/show_bleedingedge_command.rb +23 -16
- data/lib/rigor/cli/sig_gen_command.rb +130 -34
- data/lib/rigor/cli/skill_command.rb +32 -3
- data/lib/rigor/cli/skill_deep_probe.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +1 -1
- data/lib/rigor/cli/trace_command.rb +14 -9
- data/lib/rigor/cli/triage_command.rb +10 -11
- data/lib/rigor/cli/triage_renderer.rb +2 -1
- data/lib/rigor/cli/type_of_command.rb +18 -12
- data/lib/rigor/cli/type_of_project_scope.rb +24 -0
- data/lib/rigor/cli/type_of_renderer.rb +4 -1
- data/lib/rigor/cli/type_scan_command.rb +14 -9
- data/lib/rigor/cli/type_scan_renderer.rb +2 -1
- data/lib/rigor/cli/unused_command.rb +27 -17
- data/lib/rigor/cli/upgrade_command.rb +5 -0
- data/lib/rigor/cli.rb +209 -54
- data/lib/rigor/config_audit.rb +17 -6
- data/lib/rigor/configuration/severity_profile.rb +5 -5
- data/lib/rigor/configuration.rb +86 -34
- data/lib/rigor/effects/definition_context.rb +0 -2
- data/lib/rigor/effects/envelope.rb +1 -1
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/mutation_classifier.rb +4 -7
- data/lib/rigor/effects/propagator.rb +1 -1
- data/lib/rigor/effects/registry.rb +2 -2
- data/lib/rigor/effects/snapshot.rb +1 -1
- data/lib/rigor/effects/taint_cause.rb +0 -2
- data/lib/rigor/effects/unit_scan.rb +9 -13
- data/lib/rigor/environment/bundle_sig_discovery.rb +5 -9
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +1 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +283 -0
- data/lib/rigor/environment/gated_signature_guard.rb +1 -1
- data/lib/rigor/environment/gated_signature_plan.rb +5 -2
- data/lib/rigor/environment/lockfile_resolver.rb +28 -12
- data/lib/rigor/environment/member_consistency/comparator.rb +18 -1
- data/lib/rigor/environment/member_consistency.rb +56 -7
- data/lib/rigor/environment/missing_gem_constant_index.rb +3 -2
- data/lib/rigor/environment/project_path_gems.rb +124 -0
- data/lib/rigor/environment/rbs_hierarchy.rb +6 -15
- data/lib/rigor/environment/rbs_loader.rb +592 -70
- data/lib/rigor/environment/reflection.rb +7 -7
- data/lib/rigor/environment/required_features.rb +136 -32
- data/lib/rigor/environment/ruby_library_roots.rb +122 -0
- data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
- data/lib/rigor/environment.rb +44 -11
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +93 -32
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +178 -0
- data/lib/rigor/inference/budget_trace.rb +8 -2
- data/lib/rigor/inference/builtins/exception_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/numeric_catalog.rb +2 -5
- data/lib/rigor/inference/builtins/random_catalog.rb +2 -2
- data/lib/rigor/inference/callee_mutation_chain.rb +126 -0
- data/lib/rigor/inference/callee_write_census.rb +815 -0
- data/lib/rigor/inference/construction_escape.rb +217 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- data/lib/rigor/inference/deep_erasure.rb +170 -0
- data/lib/rigor/inference/def_handle.rb +1 -1
- data/lib/rigor/inference/def_node_resolver.rb +1 -1
- data/lib/rigor/inference/def_return_typer.rb +204 -12
- data/lib/rigor/inference/definer_resolution.rb +21 -5
- data/lib/rigor/inference/definers_index.rb +106 -0
- data/lib/rigor/inference/direct_ivar_writes.rb +300 -0
- data/lib/rigor/inference/element_read_widening.rb +49 -3
- data/lib/rigor/inference/error_info.rb +17 -3
- data/lib/rigor/inference/expression_typer.rb +173 -57
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/global_write_census.rb +110 -1
- data/lib/rigor/inference/global_writer_reach.rb +260 -0
- data/lib/rigor/inference/hkt_body.rb +1 -2
- data/lib/rigor/inference/hkt_body_parser.rb +3 -5
- data/lib/rigor/inference/hkt_reducer.rb +2 -2
- data/lib/rigor/inference/hkt_registry.rb +3 -5
- data/lib/rigor/inference/indexed_narrowing.rb +4 -7
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +246 -0
- data/lib/rigor/inference/key_presence_guard.rb +2 -1
- data/lib/rigor/inference/loop_value_record.rb +57 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +65 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +45 -0
- data/lib/rigor/inference/match_rebinding.rb +11 -1
- data/lib/rigor/inference/memo_audit.rb +55 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/argument_distribution.rb +40 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +113 -12
- data/lib/rigor/inference/method_dispatcher/contested_overloads.rb +89 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -3
- data/lib/rigor/inference/method_dispatcher/no_match_fallback.rb +54 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +39 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +203 -17
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +59 -24
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +83 -20
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +0 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +50 -17
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +4 -6
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +109 -29
- data/lib/rigor/inference/module_function_state/spellings.rb +64 -0
- data/lib/rigor/inference/module_function_state.rb +23 -1
- data/lib/rigor/inference/multi_target_binder.rb +1 -1
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +162 -29
- data/lib/rigor/inference/narrowing.rb +113 -38
- data/lib/rigor/inference/object_mixins.rb +13 -1
- data/lib/rigor/inference/optimistic_origin.rb +1 -1
- data/lib/rigor/inference/out_buffer_mutation.rb +72 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +6 -3
- data/lib/rigor/inference/project_seed_tables.rb +2 -1
- data/lib/rigor/inference/project_yielder.rb +122 -0
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +3 -1
- data/lib/rigor/inference/refined_dispatch/own_method.rb +2 -1
- data/lib/rigor/inference/remover_holder_scan.rb +233 -0
- data/lib/rigor/inference/remover_narrowing.rb +224 -0
- data/lib/rigor/inference/rewrite_mutation.rb +53 -2
- data/lib/rigor/inference/scope_indexer/certainty.rb +9 -1
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_ivar_types.rb +64 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +205 -0
- data/lib/rigor/inference/scope_indexer/derived_param_value.rb +112 -0
- data/lib/rigor/inference/scope_indexer/empty_seed.rb +99 -0
- data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +135 -0
- data/lib/rigor/inference/scope_indexer/unseen_ivar_writers.rb +133 -0
- data/lib/rigor/inference/scope_indexer.rb +614 -146
- data/lib/rigor/inference/self_call_ivar_writes.rb +101 -17
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +1 -2
- data/lib/rigor/inference/statement_evaluator.rb +3036 -278
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_index.rb +23 -0
- data/lib/rigor/inference/synthetic_method_scanner/project_members.rb +130 -0
- data/lib/rigor/inference/synthetic_method_scanner.rb +73 -14
- data/lib/rigor/inference/toplevel_def_census.rb +59 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -1
- data/lib/rigor/language_server/buffer_table.rb +9 -3
- data/lib/rigor/language_server/completion_provider.rb +26 -20
- data/lib/rigor/language_server/config_warning_announcer.rb +28 -0
- data/lib/rigor/language_server/diagnostic_publisher.rb +28 -9
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -2
- data/lib/rigor/language_server/hover_provider.rb +1 -7
- data/lib/rigor/language_server/hover_renderer.rb +6 -8
- data/lib/rigor/language_server/project_context.rb +98 -4
- data/lib/rigor/language_server/publish_batcher.rb +3 -4
- data/lib/rigor/language_server/selection_range_provider.rb +2 -4
- data/lib/rigor/language_server/server.rb +12 -6
- data/lib/rigor/language_server/signature_help_provider.rb +4 -4
- data/lib/rigor/lens/plugins.rb +1 -1
- data/lib/rigor/mcp/server.rb +82 -3
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/base.rb +26 -11
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +1 -1
- data/lib/rigor/plugin/loader.rb +25 -8
- data/lib/rigor/plugin/macro/heredoc_template.rb +7 -8
- data/lib/rigor/plugin/macro/trait_registry.rb +6 -9
- data/lib/rigor/plugin/manifest.rb +38 -16
- data/lib/rigor/plugin/registry.rb +41 -3
- data/lib/rigor/plugin/services.rb +2 -3
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -2
- data/lib/rigor/plugin/type_node_resolver.rb +2 -4
- data/lib/rigor/plugin.rb +6 -8
- data/lib/rigor/plugin_gap_advisory.rb +5 -1
- data/lib/rigor/project_environment.rb +16 -2
- data/lib/rigor/protection/analysis_guard.rb +1 -1
- data/lib/rigor/protection/discovery_seed.rb +96 -2
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/hkt_directives.rb +6 -10
- data/lib/rigor/rbs_extended/reporter.rb +27 -3
- data/lib/rigor/rbs_extended.rb +2 -3
- data/lib/rigor/reflection/constant_ancestors.rb +5 -3
- data/lib/rigor/rooted_glob.rb +25 -2
- data/lib/rigor/run_scoped_slots.rb +38 -0
- data/lib/rigor/runtime/jit.rb +1 -1
- data/lib/rigor/scope/discovery_index.rb +19 -6
- data/lib/rigor/scope/resolution_chain.rb +3 -1
- data/lib/rigor/scope.rb +379 -36
- data/lib/rigor/sig_gen/classification.rb +4 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +668 -84
- data/lib/rigor/sig_gen/generic_header_scan.rb +189 -0
- data/lib/rigor/sig_gen/inline_declarations.rb +2 -2
- data/lib/rigor/sig_gen/layout_index.rb +3 -3
- data/lib/rigor/sig_gen/method_candidate.rb +23 -4
- data/lib/rigor/sig_gen/observation_collector.rb +7 -6
- data/lib/rigor/sig_gen/observed_call.rb +1 -1
- data/lib/rigor/sig_gen/path_mapper.rb +6 -0
- data/lib/rigor/sig_gen/rbs_validity.rb +1 -1
- data/lib/rigor/sig_gen/renderer.rb +21 -12
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +15 -2
- data/lib/rigor/sig_gen/type_elaborator.rb +21 -5
- data/lib/rigor/sig_gen/type_name_qualification.rb +69 -0
- data/lib/rigor/sig_gen/write_reporter.rb +63 -14
- data/lib/rigor/sig_gen/write_result.rb +23 -12
- data/lib/rigor/sig_gen/writer.rb +217 -37
- data/lib/rigor/type/acceptance_router.rb +2 -2
- data/lib/rigor/type/accepts_result.rb +1 -1
- data/lib/rigor/type/app.rb +4 -6
- data/lib/rigor/type/combinator.rb +13 -16
- data/lib/rigor/type/constant.rb +48 -7
- data/lib/rigor/type/hash_shape.rb +26 -40
- data/lib/rigor/type/struct_instance.rb +3 -2
- data/lib/rigor/type/union.rb +1 -1
- data/lib/rigor/type_node/identifier.rb +1 -2
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node/string_literal.rb +1 -2
- data/lib/rigor/type_node/symbol_literal.rb +1 -2
- data/lib/rigor/type_node/union.rb +3 -6
- data/lib/rigor/value_semantics.rb +1 -10
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +2 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +2 -3
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +89 -70
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +25 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -5
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +2 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +79 -19
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +6 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +3 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +2 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +21 -31
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +10 -16
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +2 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +0 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +5 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +3 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +7 -12
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/symbolize_keys.rb +102 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +19 -6
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +26 -13
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +3 -3
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +5 -3
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +1 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +6 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +5 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +7 -6
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/params_shape.rb +2 -3
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -8
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +10 -18
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +0 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +0 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +4 -5
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +0 -2
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +6 -7
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +2 -4
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +2 -5
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -2
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +6 -6
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +2 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +3 -8
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +2 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -8
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +4 -11
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +102 -11
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +2 -2
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +3 -4
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +6 -8
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +5 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +6 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +1 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +17 -21
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +3 -2
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +4 -4
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer.rb +1 -1
- data/sig/rigor/analysis/baseline.rbs +0 -2
- data/sig/rigor/analysis/fact_store.rbs +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- data/sig/rigor/cli/diff_command.rbs +1 -1
- data/sig/rigor/cli/explain_command.rbs +1 -1
- data/sig/rigor/effects/file_collection.rbs +5 -6
- data/sig/rigor/effects/registry.rbs +8 -6
- data/sig/rigor/effects/summary.rbs +6 -5
- data/sig/rigor/environment.rbs +5 -3
- data/sig/rigor/inference/optimistic_origin.rbs +11 -0
- data/sig/rigor/inference.rbs +10 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +1 -0
- data/sig/rigor/plugin/effect_ancestry.rbs +6 -4
- data/sig/rigor/plugin/effect_attribution.rbs +25 -10
- data/sig/rigor/plugin/effect_edge.rbs +12 -5
- data/sig/rigor/plugin/effect_entry_points.rbs +8 -3
- data/sig/rigor/plugin/io_boundary.rbs +6 -5
- data/sig/rigor/plugin/manifest.rbs +16 -18
- data/sig/rigor/plugin/protocol_contract.rbs +6 -9
- data/sig/rigor/plugin/registry.rbs +1 -1
- data/sig/rigor/scope.rbs +51 -50
- data/sig/rigor/type.rbs +0 -6
- data/skills/rigor-plugin-author/SKILL.md +4 -4
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +5 -5
- data/skills/rigor-plugin-review/SKILL.md +3 -3
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +12 -1
- metadata +55 -3
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../type"
|
|
4
|
+
require_relative "../rbs_type_translator"
|
|
5
|
+
|
|
6
|
+
module Rigor
|
|
7
|
+
module Inference
|
|
8
|
+
module MethodDispatcher
|
|
9
|
+
module OverloadSelector
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# Issue #2379 — every overload a supertype argument may select, when a nominal argument is wider than the
|
|
13
|
+
# parameter of the overload the call selected, `chosen`: `Integer#-` with a `Numeric` argument matched no
|
|
14
|
+
# overload and took the first, `(Integer) -> Integer`, although the runtime takes `(Float)`, `(Rational)` or
|
|
15
|
+
# `(Complex)` for those subclasses. Answers, in affinity order, every strictly typed overload whose every
|
|
16
|
+
# parameter takes its argument or is taken by a nominal one; nil when no argument is wider than `chosen`'s
|
|
17
|
+
# parameter or `chosen` is the only such overload.
|
|
18
|
+
# rubocop:disable-next Metrics/ParameterLists -- the selection inputs.
|
|
19
|
+
def contested_matches(method_definition, chosen, arg_types:, self_type:, instance_type:, type_vars:,
|
|
20
|
+
block_required:, environment:)
|
|
21
|
+
return nil unless arg_types.any?(Type::Nominal)
|
|
22
|
+
|
|
23
|
+
shared = { arg_types: arg_types, self_type: self_type, instance_type: instance_type,
|
|
24
|
+
type_vars: type_vars, block_required: block_required,
|
|
25
|
+
param_overrides: RbsExtended.param_type_override_map(method_definition, environment: environment),
|
|
26
|
+
environment: environment, keywords_last: false }
|
|
27
|
+
return nil unless wider_argument?(chosen, shared)
|
|
28
|
+
|
|
29
|
+
overloads = ReceiverAffinity.reorder(method_definition.method_types, self_type: self_type,
|
|
30
|
+
environment: environment)
|
|
31
|
+
matches = overloads.select do |method_type|
|
|
32
|
+
engages_block_shape?(method_type, block_required) &&
|
|
33
|
+
strictly_typed_params?(method_type, shared) && overlaps?(method_type, shared)
|
|
34
|
+
end
|
|
35
|
+
matches.empty? || (matches.size == 1 && matches.first.equal?(chosen)) ? nil : matches
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class << self
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
# Whether a nominal argument is strictly wider than the parameter `method_type` binds it to: the parameter
|
|
42
|
+
# does not take the whole argument, and the argument takes the parameter (`Numeric` against `(Integer)`).
|
|
43
|
+
def wider_argument?(method_type, shared)
|
|
44
|
+
fun = method_type.type
|
|
45
|
+
arg_types = shared[:arg_types]
|
|
46
|
+
return false unless fun.respond_to?(:required_positionals) && arity_compatible?(fun, arg_types.size)
|
|
47
|
+
|
|
48
|
+
params = positional_params_for(fun, arg_types.size)
|
|
49
|
+
index = -1
|
|
50
|
+
params.any? do |param|
|
|
51
|
+
arg = arg_types[index += 1]
|
|
52
|
+
next false unless arg.is_a?(Type::Nominal)
|
|
53
|
+
|
|
54
|
+
param_type = translate_param(param, shared)
|
|
55
|
+
!param_type.accepts(arg, mode: :gradual).yes? && arg.accepts(param_type, mode: :gradual).yes?
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# The strict pass's test with a nominal argument also counting where it takes the parameter: some value of
|
|
60
|
+
# a `Numeric` reaches `(Float)`.
|
|
61
|
+
def overlaps?(method_type, shared)
|
|
62
|
+
fun = method_type.type
|
|
63
|
+
ok = KeywordArguments.accepted_by?(fun, shared, true) { |*kv| accepts_param?(*kv, shared, true, true) }
|
|
64
|
+
return false unless ok
|
|
65
|
+
|
|
66
|
+
arg_types = shared[:arg_types]
|
|
67
|
+
return false unless arity_compatible?(fun, arg_types.size)
|
|
68
|
+
|
|
69
|
+
each_param_accepts?(positional_params_for(fun, arg_types.size), arg_types) do |param, arg|
|
|
70
|
+
accepts_param?(param, arg, shared, true) ||
|
|
71
|
+
(arg.is_a?(Type::Nominal) && arg.accepts(translate_param(param, shared), mode: :gradual).yes?)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# A parameter's type as the selector reads it: the `rigor:v1:param:` override, else the translated RBS type.
|
|
76
|
+
def translate_param(param, shared)
|
|
77
|
+
shared[:param_overrides][param.name] || RbsTypeTranslator.translate(
|
|
78
|
+
param.type,
|
|
79
|
+
self_type: shared[:self_type],
|
|
80
|
+
instance_type: shared[:instance_type],
|
|
81
|
+
type_vars: shared[:type_vars],
|
|
82
|
+
alias_expander: shared[:environment]&.rbs_loader
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -105,7 +105,7 @@ module Rigor
|
|
|
105
105
|
# throws)
|
|
106
106
|
# - `Hash[K, V]` / `HashShape{...}` → Tuple[K, V]
|
|
107
107
|
# (Ruby yields `[key, value]` pairs as the element)
|
|
108
|
-
# - `Constant<Array>` / `Constant<Range>`
|
|
108
|
+
# - `Constant<Array>` / `Constant<Range>`
|
|
109
109
|
# → corresponding Constant element
|
|
110
110
|
#
|
|
111
111
|
# Receivers we cannot project (Top, Dynamic, unknown nominals, IO, …) decline so the RBS tier still
|
|
@@ -11,7 +11,7 @@ module Rigor
|
|
|
11
11
|
# Kernel intrinsic shape-folding — precision tier for the `Kernel` module-functions whose return type
|
|
12
12
|
# is a function of the argument's *shape*, not just its class.
|
|
13
13
|
#
|
|
14
|
-
#
|
|
14
|
+
# `Kernel#Array` is the shape-sensitive fold. Its default RBS sig is
|
|
15
15
|
# `Array(untyped) -> Array[untyped]`, which collapses to `Array[Dynamic[top]]` for every caller. This
|
|
16
16
|
# tier short-circuits with a precise answer when the argument's type lattice tells us what the result
|
|
17
17
|
# element type MUST be:
|
|
@@ -191,12 +191,16 @@ module Rigor
|
|
|
191
191
|
# Runs the real `Kernel#format` when everything is value-pinned. A malformed directive or an
|
|
192
192
|
# argument-count mismatch raises at fold time; the handler declines so the literal-string
|
|
193
193
|
# lift (or the RBS `String` envelope) answers instead. Results larger than the shared
|
|
194
|
-
# `ConstantFolding::STRING_FOLD_BYTE_LIMIT` decline too, keeping the carrier-size convention
|
|
194
|
+
# `ConstantFolding::STRING_FOLD_BYTE_LIMIT` decline too, keeping the carrier-size convention,
|
|
195
|
+
# and a field width or precision past it declines before the string is built (#2125).
|
|
195
196
|
def fold_format_constant(args)
|
|
196
197
|
return nil unless args.all?(Type::Constant)
|
|
197
198
|
return nil unless args.first.value.is_a?(String)
|
|
198
199
|
|
|
199
|
-
|
|
200
|
+
values = args.drop(1).map(&:value)
|
|
201
|
+
return nil if ConstantFolding.format_blow_up?(args.first.value, values)
|
|
202
|
+
|
|
203
|
+
result = format(args.first.value, *values)
|
|
200
204
|
return nil if result.bytesize > ConstantFolding::STRING_FOLD_BYTE_LIMIT
|
|
201
205
|
|
|
202
206
|
Type::Combinator.constant_of(result)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Inference
|
|
5
|
+
module MethodDispatcher
|
|
6
|
+
module OverloadSelector
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
# The overload a call answers when no selection pass matched it. A call with a block, on a method that
|
|
10
|
+
# declares a block overload, reads the block overloads (`block_call_fallback`, #2429) unless `block_fallback`
|
|
11
|
+
# is false. Otherwise prefer an overload that does not REQUIRE a block over `overloads.first`: methods like
|
|
12
|
+
# `Array#filter` / `Enumerable#map` declare the block-bearing overload first (`() { ... } -> Array[Elem]`)
|
|
13
|
+
# and the bare-call overload second (`() -> Enumerator[...]`), and a no-block `[1, 2].filter` yields an
|
|
14
|
+
# `Enumerator`.
|
|
15
|
+
def no_match_fallback(overloads, shared, block_fallback)
|
|
16
|
+
if block_fallback && shared[:block_required] && overloads.any? { |mt| overload_has_block?(mt) }
|
|
17
|
+
return block_call_fallback(overloads, shared)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
[overloads.find { |mt| !overload_requires_block?(mt) } || overloads.first]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
# Issue #2429 — the block-less arm's return is what the method answers without a block, so
|
|
27
|
+
# `URI.open(url, read_timeout: 3) { |io| }` read `StringIO | Tempfile` instead of the block's value. The
|
|
28
|
+
# answer is the block overload whose positional arity admits the call when only one does, or the one every
|
|
29
|
+
# such overload agrees on; otherwise none (`[]`, which the return path reads as `Dynamic[top]`).
|
|
30
|
+
# `[3, 1, 2].max_by(2.0) { }` takes `(Integer n) { } -> Array[Elem]`, not `() { } -> Elem?`, and overloads of
|
|
31
|
+
# differing returns that all admit the call are not decided by position.
|
|
32
|
+
def block_call_fallback(overloads, shared)
|
|
33
|
+
admitted = overloads.select { |mt| overload_has_block?(mt) && arity_admits?(mt, shared) }
|
|
34
|
+
return [] if admitted.empty?
|
|
35
|
+
|
|
36
|
+
admitted.map { |mt| mt.type.return_type }.uniq.size == 1 ? [admitted.first] : []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# The call's positional count (less a keyword hash the overload takes as keywords) fits `method_type`'s
|
|
40
|
+
# arity; a splat fits when some count of its elements does (#1801).
|
|
41
|
+
def arity_admits?(method_type, shared)
|
|
42
|
+
fun = method_type.type
|
|
43
|
+
arg_types = KeywordArguments.selection_positional(method_type, shared)
|
|
44
|
+
splats = shared[:splats]
|
|
45
|
+
return arity_compatible?(fun, arg_types.size) unless splats
|
|
46
|
+
|
|
47
|
+
lists = SplatArity.expansions(fun, arg_types, splats)
|
|
48
|
+
lists.nil? || lists.any? { |list| arity_compatible?(fun, list.size) }
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -4,9 +4,11 @@ require_relative "../../type"
|
|
|
4
4
|
require_relative "../acceptance"
|
|
5
5
|
require_relative "../rbs_type_translator"
|
|
6
6
|
require_relative "alias_strict_nominals"
|
|
7
|
+
require_relative "contested_overloads"
|
|
7
8
|
require_relative "facet_distribution"
|
|
8
9
|
require_relative "imprecise_argument"
|
|
9
10
|
require_relative "keyword_arguments"
|
|
11
|
+
require_relative "no_match_fallback"
|
|
10
12
|
require_relative "proven_overload"
|
|
11
13
|
require_relative "receiver_affinity"
|
|
12
14
|
require_relative "splat_arity"
|
|
@@ -43,8 +45,10 @@ module Rigor
|
|
|
43
45
|
# otherwise win purely by list position and inject false constants into the flow; they remain
|
|
44
46
|
# selectable when the argument PROVES the value (strict pass) or when no other overload matches
|
|
45
47
|
# (step 4's fallback picks the first overload regardless).
|
|
46
|
-
# 4. If no overload matches at all, fall back to
|
|
47
|
-
# their phase 1 / 2b behavior. This preserves the
|
|
48
|
+
# 4. If no overload matches at all, fall back to the first overload that does not require a block (else
|
|
49
|
+
# `method_types.first`), so existing call sites keep their phase 1 / 2b behavior. This preserves the
|
|
50
|
+
# fail-soft invariant of the dispatcher. A call with a block reads the block overloads by arity instead
|
|
51
|
+
# (`no_match_fallback`, #2429).
|
|
48
52
|
#
|
|
49
53
|
# The selector is intentionally agnostic about the dispatch kind (instance vs singleton). Both kinds
|
|
50
54
|
# share the same arity and acceptance shape; the difference is only in which `Definition` the caller
|
|
@@ -64,10 +68,10 @@ module Rigor
|
|
|
64
68
|
# like `::Array[Elem]` substitute Elem before the accepts check, instead of degrading the param
|
|
65
69
|
# to `Array[Dynamic[Top]]`.
|
|
66
70
|
# @param block_required — when `true`, only overloads that declare a block clause are
|
|
67
|
-
# considered (Slice 6 phase C sub-phase 1)
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
+
# considered first (Slice 6 phase C sub-phase 1), and a call none of them matches is retried with
|
|
72
|
+
# the block ignored. Where nothing matches, a block call answers by arity among the block overloads
|
|
73
|
+
# (`block_call_fallback`, #2429), and otherwise the fallback prefers an overload that does not require a
|
|
74
|
+
# block over `method_types.first`.
|
|
71
75
|
# @return the chosen overload, or nil when the definition has no method
|
|
72
76
|
# types at all.
|
|
73
77
|
def select(method_definition, **) = select_candidates(method_definition, member_wise: false, **).first
|
|
@@ -88,12 +92,14 @@ module Rigor
|
|
|
88
92
|
# rubocop:disable-next Metrics/ParameterLists -- the selection keywords plus the member-wise switch.
|
|
89
93
|
# @param keywords_last — the call's last argument is a keyword hash (`f(a, k: 1)`, not `f(a, { k: 1 })`).
|
|
90
94
|
# @param splats — the indices of `arg_types` that are splat arguments (`f(*xs)`), or nil (#1801).
|
|
95
|
+
# @param block_fallback — false keeps a block call nothing matches on the block-less fallback (#2429): the
|
|
96
|
+
# block-parameter probe binds no parameters from an overload the call does not match.
|
|
91
97
|
def select_candidates(definition, arg_types:, self_type:, instance_type:, type_vars: {},
|
|
92
98
|
block_required: false, environment: nil, member_wise: true, keywords_last: false,
|
|
93
|
-
splats: nil)
|
|
99
|
+
splats: nil, block_fallback: true)
|
|
94
100
|
unless FacetDistribution.faceted?(arg_types)
|
|
95
101
|
return select_declared(definition, arg_types, self_type, instance_type, type_vars, block_required,
|
|
96
|
-
environment, false, keywords_last, splats)
|
|
102
|
+
environment, false, keywords_last, splats, block_fallback)
|
|
97
103
|
end
|
|
98
104
|
|
|
99
105
|
FacetDistribution.select(arg_types, definition, member_wise:, environment:) do |args, member|
|
|
@@ -101,7 +107,7 @@ module Rigor
|
|
|
101
107
|
# gradually matches every arm and the strict pass's pick is the first by position, so the member-wise answer
|
|
102
108
|
# is every gradual match (`:joined`), as the block probe reads it (#1750); the caller joins their returns.
|
|
103
109
|
select_declared(definition, args, self_type, instance_type, type_vars, block_required, environment,
|
|
104
|
-
member || (member_wise && :joined), keywords_last, splats)
|
|
110
|
+
member || (member_wise && :joined), keywords_last, splats, block_fallback)
|
|
105
111
|
end
|
|
106
112
|
end
|
|
107
113
|
|
|
@@ -114,7 +120,7 @@ module Rigor
|
|
|
114
120
|
# first-overload fallback, as the return path's reading of the arguments as given always has (#1782).
|
|
115
121
|
# rubocop:disable-next Metrics/ParameterLists -- the selection inputs plus the member-wise flag.
|
|
116
122
|
def select_declared(method_definition, arg_types, self_type, instance_type, type_vars, block_required,
|
|
117
|
-
environment, member, keywords_last, splats
|
|
123
|
+
environment, member, keywords_last, splats, block_fallback)
|
|
118
124
|
declared = method_definition.method_types
|
|
119
125
|
return [] if declared.empty?
|
|
120
126
|
|
|
@@ -159,12 +165,7 @@ module Rigor
|
|
|
159
165
|
end
|
|
160
166
|
return [] if member && member != :joined
|
|
161
167
|
|
|
162
|
-
|
|
163
|
-
# `overloads.first`. Methods like `Array#filter` / `Enumerable#map` declare the block-bearing
|
|
164
|
-
# overload first (`() { ... } -> Array[Elem]`) and the bare-call overload second
|
|
165
|
-
# (`() -> Enumerator[...]`). Without this, a no-block `[1, 2].filter` would adopt the block
|
|
166
|
-
# overload's `Array[Elem]` return when the call actually yields an `Enumerator`.
|
|
167
|
-
[overloads.find { |mt| !overload_requires_block?(mt) } || overloads.first]
|
|
168
|
+
no_match_fallback(overloads, shared, block_fallback)
|
|
168
169
|
end
|
|
169
170
|
|
|
170
171
|
def overload_has_block?(method_type)
|
|
@@ -230,13 +231,25 @@ module Rigor
|
|
|
230
231
|
# and the dispatch layer unions their returns (#521).
|
|
231
232
|
matches = find_matching_overload(overloads, shared, strict: false)
|
|
232
233
|
every_match = gradual || ImpreciseArgument.any_in?(shared[:arg_types], shared[:keywords_last])
|
|
233
|
-
return matches.
|
|
234
|
+
return [first_read_match(matches, shared)].compact unless every_match
|
|
234
235
|
|
|
235
236
|
# Issue #1675 — and every overload the arguments' untyped parts reach on their own, after the
|
|
236
237
|
# whole-argument matches so the singular `select` keeps its answer.
|
|
237
238
|
ImpreciseArgument.with_stand_ins(matches, shared) { find_matching_overload(overloads, it, strict: false) }
|
|
238
239
|
end
|
|
239
240
|
|
|
241
|
+
# Issue #2428 — the single winner of pass 2 is the first match that does not rest on a tuple's `maybe` for
|
|
242
|
+
# an `Array` of unknown arity, when there is one. Pass 1 declines a strict overload against a competitor
|
|
243
|
+
# whose parameter is an alias, an interface or `untyped`, and taking the tuple overload by list position
|
|
244
|
+
# then typed redis's `hmget(key, Array[String])` as `[String?]`, where its `(arg, Array[arg])` overload
|
|
245
|
+
# says `Array[String?]`. Only the tuple's `maybe` is re-asked; a record's `maybe` for an unread hash keeps
|
|
246
|
+
# its documented gradual-pass answer.
|
|
247
|
+
def first_read_match(matches, shared)
|
|
248
|
+
return matches.first if matches.size < 2 || !Acceptance.unread_array_in?(shared[:arg_types])
|
|
249
|
+
|
|
250
|
+
matches.find { |mt| Acceptance.refusing_unread_arrays { matches?(mt, shared) } } || matches.first
|
|
251
|
+
end
|
|
252
|
+
|
|
240
253
|
# Pass 0. With every argument a plain value (a `Constant`, or a `Nominal` with no type arguments), the
|
|
241
254
|
# first overload in declared order that the arguments do not rule out is the one RBS would take, and
|
|
242
255
|
# the pass takes it only when that is certain: every parameter is a lone class naming its argument's
|
|
@@ -307,7 +320,10 @@ module Rigor
|
|
|
307
320
|
next false unless engages_block_shape?(method_type, shared[:block_required])
|
|
308
321
|
|
|
309
322
|
fun = method_type.type
|
|
310
|
-
|
|
323
|
+
# Issue #2428 — a tuple keyword's `maybe` for an unread Array is no evidence here; pass 2 decides.
|
|
324
|
+
ok = Acceptance.refusing_unread_arrays do
|
|
325
|
+
KeywordArguments.accepted_by?(fun, shared, false) { |*kv| accepts_param?(*kv, shared, false, true) }
|
|
326
|
+
end
|
|
311
327
|
next false unless ok
|
|
312
328
|
|
|
313
329
|
arg_types = KeywordArguments.selection_positional(method_type, shared)
|
|
@@ -445,13 +461,7 @@ module Rigor
|
|
|
445
461
|
|
|
446
462
|
# `shared` is the keyword bundle `select_candidates` assembled (see `find_matching_overload`).
|
|
447
463
|
def accepts_param?(param, arg, shared, strict, keyword = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
448
|
-
param_type =
|
|
449
|
-
param.type,
|
|
450
|
-
self_type: shared[:self_type],
|
|
451
|
-
instance_type: shared[:instance_type],
|
|
452
|
-
type_vars: shared[:type_vars],
|
|
453
|
-
alias_expander: shared[:environment]&.rbs_loader
|
|
454
|
-
)
|
|
464
|
+
param_type = translate_param(param, shared)
|
|
455
465
|
# An `untyped` arg gradually accepts against every param, so a value-pinning param would be
|
|
456
466
|
# "matched" with zero evidence and its value-precise return (`(nil) -> []`) would beat broader
|
|
457
467
|
# overloads purely by list position. Decline the pair; only the strict pass (where the arg
|
|
@@ -467,8 +477,10 @@ module Rigor
|
|
|
467
477
|
# A record's `maybe` for a `Hash` with a gradual arm or an open shape is no evidence for the overload:
|
|
468
478
|
# with `({ a: Integer }) -> Integer | (Hash[Symbol, untyped]) -> String`, `{ **o, b: 2 }` has a key the
|
|
469
479
|
# closed record forbids, yet the first overload won by list position. The gradual pass still takes it.
|
|
470
|
-
# A `maybe`
|
|
471
|
-
|
|
480
|
+
# A tuple's `maybe` for an `Array` of unknown arity is the same: `([Integer, Integer]) -> Symbol |
|
|
481
|
+
# (Array[Integer]) -> String` answers `String` for an `Array[Integer]`. A `maybe` that survives with
|
|
482
|
+
# those shapes answering `no` has another source, and still counts.
|
|
483
|
+
return false if strict && result.maybe? && Acceptance.maybe_rests_on_unread_shape?(param_type, arg)
|
|
472
484
|
|
|
473
485
|
result.yes? || result.maybe?
|
|
474
486
|
end
|
|
@@ -20,7 +20,7 @@ module Rigor
|
|
|
20
20
|
# (`Errno::EDOM`) and a non-literal argument decline to the RBS envelope. The other argument
|
|
21
21
|
# shapes (`rand`, `rand(n)`, `rand(1.5)`) are deliberately NOT folded: the corpus uses them as its
|
|
22
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
|
|
23
|
+
# oracle first. The `Kernel` spelling is folded by {KernelDispatch.try_dispatch} behind ADR-91's
|
|
24
24
|
# ownership gate; this module owns `Singleton[Random]` and the shared interval reading.
|
|
25
25
|
module RandomFolding
|
|
26
26
|
module_function
|