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
|
@@ -21,10 +21,13 @@ module Rigor
|
|
|
21
21
|
module_function
|
|
22
22
|
|
|
23
23
|
def reorder(overloads, self_type:, environment:)
|
|
24
|
-
return overloads if environment.nil?
|
|
24
|
+
return overloads if environment.nil? || overloads.size <= 1
|
|
25
25
|
|
|
26
26
|
self_class_name = self_type_class_name(self_type)
|
|
27
27
|
return overloads if self_class_name.nil?
|
|
28
|
+
# A list with no affinity arm behind a non-affinity arm is already in order -- the common case,
|
|
29
|
+
# answered without the partition's three arrays (#775).
|
|
30
|
+
return overloads unless out_of_order?(overloads, self_class_name, environment)
|
|
28
31
|
|
|
29
32
|
affinity, other = overloads.partition do |mt|
|
|
30
33
|
overload_param_classes_in_ancestry?(mt, self_class_name, environment)
|
|
@@ -41,6 +44,19 @@ module Rigor
|
|
|
41
44
|
end
|
|
42
45
|
end
|
|
43
46
|
|
|
47
|
+
# True when some affinity arm follows a non-affinity arm, i.e. the stable partition would move it.
|
|
48
|
+
def out_of_order?(overloads, self_class_name, environment)
|
|
49
|
+
other_seen = false
|
|
50
|
+
overloads.each do |mt|
|
|
51
|
+
if overload_param_classes_in_ancestry?(mt, self_class_name, environment)
|
|
52
|
+
return true if other_seen
|
|
53
|
+
else
|
|
54
|
+
other_seen = true
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
false
|
|
58
|
+
end
|
|
59
|
+
|
|
44
60
|
# `RBS::Types::UntypedFunction` (a `(?)` method type, e.g. core's `Proc#call`) declares no
|
|
45
61
|
# parameters and exposes none of the per-arity accessors. It has no param classes to compare
|
|
46
62
|
# against the receiver, so it carries no affinity either way.
|
|
@@ -48,10 +64,15 @@ module Rigor
|
|
|
48
64
|
fun = method_type.type
|
|
49
65
|
return false unless fun.respond_to?(:required_positionals)
|
|
50
66
|
|
|
51
|
-
|
|
52
|
-
|
|
67
|
+
required = fun.required_positionals
|
|
68
|
+
optional = fun.optional_positionals
|
|
69
|
+
trailing = fun.trailing_positionals
|
|
70
|
+
return false if required.empty? && optional.empty? && trailing.empty?
|
|
53
71
|
|
|
54
|
-
|
|
72
|
+
# The three lists are checked in place rather than concatenated (#775).
|
|
73
|
+
required.all? { |param| param_class_in_ancestry?(param.type, self_class_name, environment) } &&
|
|
74
|
+
optional.all? { |param| param_class_in_ancestry?(param.type, self_class_name, environment) } &&
|
|
75
|
+
trailing.all? { |param| param_class_in_ancestry?(param.type, self_class_name, environment) }
|
|
55
76
|
end
|
|
56
77
|
|
|
57
78
|
# Walks Optional and Union one level so `(Numeric?)` and `(Integer | Float)` still classify when
|
|
@@ -58,7 +58,6 @@ module Rigor
|
|
|
58
58
|
CONSTANT_FOLD_BIT_CAP = 256
|
|
59
59
|
private_constant :CONSTANT_FOLD_ELEMENT_CAP, :CONSTANT_FOLD_BIT_CAP
|
|
60
60
|
|
|
61
|
-
# @return [Rigor::Type, nil]
|
|
62
61
|
def try_dispatch(context)
|
|
63
62
|
return nil unless REDUCE_METHODS.include?(context.method_name)
|
|
64
63
|
return nil if context.block_type
|
|
@@ -84,9 +83,8 @@ module Rigor
|
|
|
84
83
|
# Executes the reduction on real constant values, or returns nil to decline. The caller falls
|
|
85
84
|
# through to the nominal fold on a nil return, so every guard here is precision-additive only.
|
|
86
85
|
#
|
|
87
|
-
# @param seed
|
|
86
|
+
# @param seed — the optional seed type; only a foldable `Constant` seed is
|
|
88
87
|
# honoured, any other seed declines.
|
|
89
|
-
# @return [Rigor::Type::Constant, nil]
|
|
90
88
|
def try_constant_reduce(receiver, operator, seed)
|
|
91
89
|
return nil unless CONSTANT_FOLD_OPERATORS.include?(operator)
|
|
92
90
|
|
|
@@ -102,8 +100,6 @@ module Rigor
|
|
|
102
100
|
# Extracts the receiver's elements as a Ruby Array of foldable constant values, or nil to decline.
|
|
103
101
|
# Checks the size cap BEFORE enumerating so an unbounded / huge `Constant[Range]` (e.g.
|
|
104
102
|
# `(1..1_000_000)`) never calls `to_a`.
|
|
105
|
-
#
|
|
106
|
-
# @return [Array, nil]
|
|
107
103
|
def constant_members(receiver)
|
|
108
104
|
case receiver
|
|
109
105
|
when Type::Constant
|
|
@@ -140,7 +136,7 @@ module Rigor
|
|
|
140
136
|
elements.map(&:value)
|
|
141
137
|
end
|
|
142
138
|
|
|
143
|
-
# @return
|
|
139
|
+
# @return `[seed_value, present?]`. A nil seed type yields `[nil, false]`
|
|
144
140
|
# (no-seed form). A foldable `Constant` seed yields `[value, true]`. Any other seed yields
|
|
145
141
|
# `[nil, false]` so the caller can decline.
|
|
146
142
|
def constant_seed(seed)
|
|
@@ -153,8 +149,6 @@ module Rigor
|
|
|
153
149
|
# Runs the actual reduction, guarded by the rescue harness and the magnitude cap. Empty-collection
|
|
154
150
|
# semantics match Ruby: `[].reduce(s, :op) == s` (seed form) and `[].reduce(:op) == nil` (no-seed
|
|
155
151
|
# form → declines so the nominal fold's no-nil contract stands; see `fold_result`).
|
|
156
|
-
#
|
|
157
|
-
# @return [Rigor::Type::Constant, nil]
|
|
158
152
|
def execute_constant_reduce(members, operator, seed_value, seed_present)
|
|
159
153
|
result =
|
|
160
154
|
if seed_present
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../type"
|
|
4
|
+
require_relative "../mutation_widening"
|
|
5
|
+
|
|
6
|
+
module Rigor
|
|
7
|
+
module Inference
|
|
8
|
+
module MethodDispatcher
|
|
9
|
+
# Issue #1092 — the substitute {RbsDispatch} hands the translator for `Bases::Self` on an instance
|
|
10
|
+
# receiver whose projection carries type arguments, so `Array[Integer]#tap {}` answers
|
|
11
|
+
# `Array[Integer]` rather than the raw `Array` the class name alone builds. `nil` keeps that raw
|
|
12
|
+
# nominal.
|
|
13
|
+
#
|
|
14
|
+
# The substitute is always a nominal built from the receiver's projected arguments, never the
|
|
15
|
+
# receiver's shape: the pure self-returners keep the shape through ShapeDispatch (ADR-76 WD3), and a
|
|
16
|
+
# block can mutate the receiver through its yielded alias, which MutationWidening does not follow.
|
|
17
|
+
# For the same reason every argument is widened DEEPLY — a literal to its class, a nested
|
|
18
|
+
# `Tuple` / `HashShape` to its projected nominal — so `[[1, 2]].tap { |a| a[0] << 3 }` cannot fold
|
|
19
|
+
# `.first.size == 3`.
|
|
20
|
+
#
|
|
21
|
+
# A `-> self` method that can change the element types keeps the arguments only when the call
|
|
22
|
+
# provably adds nothing outside them; otherwise the call value would claim `ints.map!(&:to_s)` is
|
|
23
|
+
# still an `Array[Integer]`.
|
|
24
|
+
module SelfSubstitute
|
|
25
|
+
# In-place methods that cannot change the receiver's element, key, or value types.
|
|
26
|
+
TYPE_PRESERVING = %i[
|
|
27
|
+
sort! sort_by! reverse! uniq! compact! shuffle! rotate!
|
|
28
|
+
select! filter! reject! keep_if delete_if delete subtract
|
|
29
|
+
clear compare_by_identity rehash reset
|
|
30
|
+
].to_set.freeze
|
|
31
|
+
|
|
32
|
+
# Adders whose positional arguments are each a new element (`Array` / `Set`).
|
|
33
|
+
ELEMENT_ADDERS = %i[<< push append unshift prepend add add?].to_set.freeze
|
|
34
|
+
|
|
35
|
+
# Adders whose positional arguments are each a collection of the receiver's own class.
|
|
36
|
+
COLLECTION_ADDERS = %i[concat merge merge! update].to_set.freeze
|
|
37
|
+
|
|
38
|
+
# Every other name MutationWidening knows as a receiver mutator (`map!`, `replace`, `fill`,
|
|
39
|
+
# `flatten!`, `transform_values!`, ...) rewrites or may rewrite the element types.
|
|
40
|
+
KNOWN_MUTATORS = (MutationWidening::ARRAY_MUTATORS | MutationWidening::HASH_MUTATORS).freeze
|
|
41
|
+
|
|
42
|
+
module_function
|
|
43
|
+
|
|
44
|
+
# @param args — the call's positional argument types.
|
|
45
|
+
# @param block_type — the call's block return type, nil without a block.
|
|
46
|
+
def for(receiver, receiver_args, method_name, args, block_type)
|
|
47
|
+
return nil if receiver_args.empty?
|
|
48
|
+
|
|
49
|
+
case receiver
|
|
50
|
+
when Type::Nominal
|
|
51
|
+
nominal_self(receiver.class_name, receiver_args, method_name, args, block_type)
|
|
52
|
+
when Type::Tuple
|
|
53
|
+
projected_self("Array", receiver_args) unless MutationWidening::ARRAY_MUTATORS.include?(method_name)
|
|
54
|
+
when Type::HashShape
|
|
55
|
+
projected_self("Hash", receiver_args) unless MutationWidening::HASH_MUTATORS.include?(method_name)
|
|
56
|
+
when Type::Refined, Type::Difference
|
|
57
|
+
self.for(receiver.base, receiver_args, method_name, args, block_type)
|
|
58
|
+
when Type::Dynamic
|
|
59
|
+
inner = self.for(receiver.static_facet, receiver_args, method_name, args, block_type)
|
|
60
|
+
inner && Type::Combinator.dynamic(inner)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def nominal_self(class_name, receiver_args, method_name, args, block_type)
|
|
65
|
+
return nil unless preserves_type_args?(class_name, receiver_args, method_name, args, block_type)
|
|
66
|
+
|
|
67
|
+
projected_self(class_name, receiver_args)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Nil when every argument widens to the bare `Dynamic[top]`: `Hash[untyped, untyped]` says nothing
|
|
71
|
+
# the raw `Hash` does not.
|
|
72
|
+
def projected_self(class_name, receiver_args)
|
|
73
|
+
type_args = receiver_args.map { |arg| deep_widen(arg) }
|
|
74
|
+
return nil if type_args.all? { |arg| untyped?(arg) }
|
|
75
|
+
|
|
76
|
+
Type::Combinator.nominal_of(class_name, type_args: type_args)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def preserves_type_args?(class_name, receiver_args, method_name, args, block_type)
|
|
80
|
+
return true if TYPE_PRESERVING.include?(method_name)
|
|
81
|
+
|
|
82
|
+
if ELEMENT_ADDERS.include?(method_name)
|
|
83
|
+
receiver_args.size == 1 && all_provably_within?(receiver_args.first, args)
|
|
84
|
+
elsif method_name == :insert
|
|
85
|
+
receiver_args.size == 1 && all_provably_within?(receiver_args.first, args.drop(1))
|
|
86
|
+
elsif COLLECTION_ADDERS.include?(method_name)
|
|
87
|
+
block_type.nil? &&
|
|
88
|
+
all_provably_within?(Type::Combinator.nominal_of(class_name, type_args: receiver_args), args)
|
|
89
|
+
else
|
|
90
|
+
!KNOWN_MUTATORS.include?(method_name) && !method_name.end_with?("!")
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def all_provably_within?(bound, args)
|
|
95
|
+
args.all? { |arg| !imprecise?(arg) && bound.accepts(arg, mode: :gradual).yes? }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def imprecise?(type)
|
|
99
|
+
case type
|
|
100
|
+
when Type::Dynamic then true
|
|
101
|
+
when Type::Union then type.members.any? { |member| imprecise?(member) }
|
|
102
|
+
else false
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def untyped?(type)
|
|
107
|
+
type.is_a?(Type::Dynamic) && type.static_facet.is_a?(Type::Top)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# `widen_value_pinned`, extended through nested shape carriers and applied type arguments.
|
|
111
|
+
def deep_widen(type)
|
|
112
|
+
case type
|
|
113
|
+
when Type::Tuple
|
|
114
|
+
return Type::Combinator.nominal_of("Array") if type.elements.empty?
|
|
115
|
+
|
|
116
|
+
Type::Combinator.nominal_of("Array", type_args: [deep_widen(Type::Combinator.union(*type.elements))])
|
|
117
|
+
when Type::HashShape
|
|
118
|
+
deep_widen_hash_shape(type)
|
|
119
|
+
when Type::Nominal
|
|
120
|
+
return type if type.type_args.empty?
|
|
121
|
+
|
|
122
|
+
Type::Combinator.nominal_of(type.class_name, type_args: type.type_args.map { |arg| deep_widen(arg) })
|
|
123
|
+
when Type::Union
|
|
124
|
+
Type::Combinator.union(*type.members.map { |member| deep_widen(member) })
|
|
125
|
+
when Type::Dynamic
|
|
126
|
+
untyped?(type) ? type : Type::Combinator.dynamic(deep_widen(type.static_facet))
|
|
127
|
+
else
|
|
128
|
+
Type::Combinator.widen_value_pinned(type)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def deep_widen_hash_shape(shape)
|
|
133
|
+
return Type::Combinator.nominal_of("Hash") if shape.pairs.empty?
|
|
134
|
+
|
|
135
|
+
keys = Type::Combinator.union(*shape.pairs.keys.map { |key| Type::Combinator.constant_of(key) })
|
|
136
|
+
values = Type::Combinator.union(*shape.pairs.values)
|
|
137
|
+
Type::Combinator.nominal_of("Hash", type_args: [deep_widen(keys), deep_widen(values)])
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -27,7 +27,7 @@ module Rigor
|
|
|
27
27
|
module SetFolding
|
|
28
28
|
module_function
|
|
29
29
|
|
|
30
|
-
# @return
|
|
30
|
+
# @return folded result, or nil to defer.
|
|
31
31
|
def try_dispatch(context)
|
|
32
32
|
receiver = context.receiver
|
|
33
33
|
method_name = context.method_name
|
|
@@ -186,7 +186,7 @@ module Rigor
|
|
|
186
186
|
itself: :shape_self
|
|
187
187
|
}.freeze
|
|
188
188
|
|
|
189
|
-
# @return
|
|
189
|
+
# @return the precise element/value type, or `nil` to defer to the next
|
|
190
190
|
# dispatcher tier.
|
|
191
191
|
# Per-carrier dispatch table. Adding a new carrier here is a one-row change; the helper methods
|
|
192
192
|
# stay private. Anonymous Type subclasses are not expected.
|
|
@@ -197,21 +197,11 @@ module Rigor
|
|
|
197
197
|
Type::Difference => :dispatch_difference,
|
|
198
198
|
Type::Refined => :dispatch_refined,
|
|
199
199
|
Type::Intersection => :dispatch_intersection,
|
|
200
|
-
Type::IntegerRange => :dispatch_integer_range
|
|
200
|
+
Type::IntegerRange => :dispatch_integer_range,
|
|
201
|
+
Type::FloatRange => :dispatch_float_range
|
|
201
202
|
}.freeze
|
|
202
203
|
private_constant :RECEIVER_HANDLERS
|
|
203
204
|
|
|
204
|
-
# v0.1.1 Track 1 slice 5b — `Integer#to_s(base)` on a non-negative `IntegerRange` receiver. The
|
|
205
|
-
# output of `n.to_s(b)` for `n >= 0` is digit-string-only (no leading sign), so when the base is in
|
|
206
|
-
# this table the result lifts to the matching imported refinement. Bases not listed (2, 36, ...)
|
|
207
|
-
# keep the v0.1.0 baseline since Rigor has no carrier for the resulting alphabet.
|
|
208
|
-
TO_S_BASE_REFINEMENTS = {
|
|
209
|
-
10 => :decimal_int_string,
|
|
210
|
-
8 => :octal_int_string,
|
|
211
|
-
16 => :hex_int_string
|
|
212
|
-
}.freeze
|
|
213
|
-
private_constant :TO_S_BASE_REFINEMENTS
|
|
214
|
-
|
|
215
205
|
def try_dispatch(context)
|
|
216
206
|
receiver = context.receiver
|
|
217
207
|
method_name = context.method_name
|
|
@@ -304,7 +294,9 @@ module Rigor
|
|
|
304
294
|
when "String"
|
|
305
295
|
dispatch_string_binary_from_arg(method_name, args.first) if args.size == 1
|
|
306
296
|
when "Integer"
|
|
307
|
-
|
|
297
|
+
integer_nominal_projection(method_name, args)
|
|
298
|
+
when "Float"
|
|
299
|
+
float_to_s_projection(method_name, args)
|
|
308
300
|
when "Array"
|
|
309
301
|
case method_name
|
|
310
302
|
when :flatten then array_nominal_flatten(nominal, args)
|
|
@@ -313,6 +305,65 @@ module Rigor
|
|
|
313
305
|
end
|
|
314
306
|
end
|
|
315
307
|
|
|
308
|
+
# `Integer#to_s` / `Integer#inspect` (#993) on a bare `Nominal[Integer]` receiver, ahead of the
|
|
309
|
+
# existing `:*` binary fold. `#inspect` takes no argument and matches `#to_s()` byte for byte, so
|
|
310
|
+
# it routes through the same no-arg branch.
|
|
311
|
+
def integer_nominal_projection(method_name, args)
|
|
312
|
+
case method_name
|
|
313
|
+
when :to_s then integer_to_s_projection(args)
|
|
314
|
+
when :inspect then args.empty? ? Type::Combinator.decimal_int_string : nil
|
|
315
|
+
else dispatch_integer_binary_from_arg(method_name, args.first) if args.size == 1
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# `decimal-int-string`'s predicate (`/\A-?\d+\z/`) admits the optional sign, so — unlike the
|
|
320
|
+
# `IntegerRange#to_s` tier above, which declines a signed range because it cannot yet prove the
|
|
321
|
+
# sign is absent — a bare `Integer` (sign completely unknown) still reaches it for the base-10
|
|
322
|
+
# case: base 10 is Ruby's default sign-and-digits grammar for every Integer. Any other base,
|
|
323
|
+
# known or not statically known, drops to `non-empty-string`: `to_s(base)` never returns `""`,
|
|
324
|
+
# but a non-decimal base's digits (`255.to_s(16)` is `"ff"`, not the `0xff` literal) match no
|
|
325
|
+
# registered refinement.
|
|
326
|
+
def integer_to_s_projection(args)
|
|
327
|
+
return Type::Combinator.decimal_int_string if args.empty?
|
|
328
|
+
return nil unless args.size == 1
|
|
329
|
+
|
|
330
|
+
decimal_base?(args.first) ? Type::Combinator.decimal_int_string : Type::Combinator.non_empty_string
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def decimal_base?(arg)
|
|
334
|
+
arg.is_a?(Type::Constant) && arg.value == 10
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# `Float#to_s` / `Float#inspect` (#993) on a bare `Nominal[Float]` receiver. No finiteness proof
|
|
338
|
+
# is available here — a bare `Float` admits `Infinity` / `-Infinity` / `NaN`, none of which are
|
|
339
|
+
# Ruby numeric literals — so the floor is `non-empty-string` (Ruby's conversion is total and
|
|
340
|
+
# never returns `""`). A `FloatRange` receiver with proven-finite bounds reaches `numeric-string`
|
|
341
|
+
# instead; see {#dispatch_float_range}.
|
|
342
|
+
def float_to_s_projection(method_name, args)
|
|
343
|
+
return nil unless %i[to_s inspect].include?(method_name)
|
|
344
|
+
return nil unless args.empty?
|
|
345
|
+
|
|
346
|
+
Type::Combinator.non_empty_string
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# `Float#to_s` / `Float#inspect` (#993) on a `FloatRange` receiver. `min` / `canonical_max` both
|
|
350
|
+
# finite (Ruby's own `Float#finite?`, the same check {MethodDispatcher::ConstantFolding}'s
|
|
351
|
+
# `float_range_finite` fold uses) is exactly a finiteness proof: no bounded range contains `NaN`,
|
|
352
|
+
# and finite bounds rule out both infinities too. `finite-float` satisfies it, as does any
|
|
353
|
+
# narrower bounded sub-range and the `f.finite?` truthy-edge narrowing (ADR-109 WD5) that
|
|
354
|
+
# produces `finite-float` — but `Float[0.0..]` does NOT, because its endless upper bound is
|
|
355
|
+
# `Float::INFINITY`.
|
|
356
|
+
def dispatch_float_range(range, method_name, args)
|
|
357
|
+
return nil unless args.empty?
|
|
358
|
+
return nil unless %i[to_s inspect].include?(method_name)
|
|
359
|
+
|
|
360
|
+
if range.min.finite? && range.canonical_max.finite?
|
|
361
|
+
Type::Combinator.numeric_string
|
|
362
|
+
else
|
|
363
|
+
Type::Combinator.non_empty_string
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
316
367
|
# `Array[T]#compact` — `compact` removes every `nil` element, so the result element type is `T`
|
|
317
368
|
# with its `nil` constituent stripped (`Array[Node?]#compact` → `Array[Node]`). Mirrors the
|
|
318
369
|
# `Tuple#compact` constant fold for the generic element case. Declines when the receiver carries
|
|
@@ -418,10 +469,18 @@ module Rigor
|
|
|
418
469
|
|
|
419
470
|
# `IntegerRange#to_s` precision (v0.1.1 Track 1 slice 5b). When the range's lower bound is
|
|
420
471
|
# `>= 0`, every member is a non-negative integer and `to_s(base)` returns a digit-string with no
|
|
421
|
-
# leading sign.
|
|
422
|
-
#
|
|
423
|
-
#
|
|
424
|
-
#
|
|
472
|
+
# leading sign. Base 10 is Ruby's decimal-literal grammar, so the result lifts to
|
|
473
|
+
# `decimal-int-string`. Signed ranges fall through entirely (the result could carry a `-` sign
|
|
474
|
+
# that `decimal-int-string` alone would need a sign proof for, matching the
|
|
475
|
+
# `Nominal[Integer]` tier's own signed-base-10 carve-out below).
|
|
476
|
+
#
|
|
477
|
+
# #1004 — every other base (a different literal, such as 8 or 16, or a value that is not
|
|
478
|
+
# statically known) does NOT lift to `octal-int-string` / `hex-int-string`: those refinements'
|
|
479
|
+
# predicates REQUIRE the `0o` / `0x` prefix Ruby's own `to_s(base)` never emits
|
|
480
|
+
# (`64.to_s(8)` is `"100"`, `255.to_s(16)` is `"ff"` — neither has a prefix), so a producer
|
|
481
|
+
# that claimed them was unsound. The floor is `non-empty-string`, same as the bare
|
|
482
|
+
# `Nominal[Integer]` path (#993 / #1001) reaches for the identical reason: `to_s(base)` is
|
|
483
|
+
# total and never returns `""`.
|
|
425
484
|
def dispatch_integer_range(range, method_name, args)
|
|
426
485
|
return nil unless method_name == :to_s
|
|
427
486
|
return nil unless range.lower >= 0
|
|
@@ -429,10 +488,7 @@ module Rigor
|
|
|
429
488
|
base = base_argument(args)
|
|
430
489
|
return nil if base.nil?
|
|
431
490
|
|
|
432
|
-
|
|
433
|
-
return nil if refinement.nil?
|
|
434
|
-
|
|
435
|
-
Type::Combinator.public_send(refinement)
|
|
491
|
+
base == 10 ? Type::Combinator.decimal_int_string : Type::Combinator.non_empty_string
|
|
436
492
|
end
|
|
437
493
|
|
|
438
494
|
# `to_s` with no argument defaults to base 10. With one argument, the value MUST be a
|
|
@@ -1556,14 +1612,18 @@ module Rigor
|
|
|
1556
1612
|
Type::Combinator.constant_of(found)
|
|
1557
1613
|
end
|
|
1558
1614
|
|
|
1559
|
-
# `shape.default` / `default_proc` — a literal `HashShape` carries no default value or proc,
|
|
1560
|
-
# both fold to `Constant[nil]`. `default` accepts an optional key argument (still returns the
|
|
1615
|
+
# `shape.default` / `default_proc` — a closed literal `HashShape` carries no default value or proc,
|
|
1616
|
+
# so both fold to `Constant[nil]`. `default` accepts an optional key argument (still returns the
|
|
1561
1617
|
# default), `default_proc` takes none — the `args.size <= 1` guard covers both.
|
|
1562
|
-
|
|
1618
|
+
#
|
|
1619
|
+
# An open shape's `default` is `untyped`. The default is what an unseen key reads, which the known
|
|
1620
|
+
# values do not bound — the RBS answer `V?` would bound it by them, so `h = { a: 1 }; h.default = 0`
|
|
1621
|
+
# (which opens the shape, see `HashLookupMutation`) read `h.default` as `1?`. `default_proc` defers.
|
|
1622
|
+
def hash_default(shape, method_name, args)
|
|
1563
1623
|
return nil unless args.size <= 1
|
|
1564
|
-
return nil
|
|
1624
|
+
return Type::Combinator.constant_of(nil) if shape.closed?
|
|
1565
1625
|
|
|
1566
|
-
Type::Combinator.
|
|
1626
|
+
Type::Combinator.untyped if method_name == :default
|
|
1567
1627
|
end
|
|
1568
1628
|
|
|
1569
1629
|
# `shape < other` / `<=` / `>` / `>=` — Hash containment comparison. Both sides must be closed
|
|
@@ -1772,17 +1832,23 @@ module Rigor
|
|
|
1772
1832
|
#
|
|
1773
1833
|
# On an `:open` shape neither applies — the key is unknown rather than missing, so both methods
|
|
1774
1834
|
# answer the `untyped` step from {#hash_dig_step}.
|
|
1835
|
+
#
|
|
1836
|
+
# `[]` takes whatever step {#hash_dig_step} gives a computed key. `fetch` answers only literal keys
|
|
1837
|
+
# none of which can miss — a required declared key, or an undeclared one on an open shape — and
|
|
1838
|
+
# defers otherwise: a miss raises instead of reading nil, so the projection's nil-free value union
|
|
1839
|
+
# is already the sound answer.
|
|
1775
1840
|
def hash_lookup(shape, method_name, args)
|
|
1776
1841
|
return nil unless args.size == 1
|
|
1777
1842
|
|
|
1778
1843
|
step = hash_dig_step(shape, args.first)
|
|
1779
1844
|
return nil if step.nil?
|
|
1780
|
-
return nil if method_name == :fetch && optional_key_step?(shape, args.first)
|
|
1781
|
-
return step unless missing_key_step?(shape, args.first)
|
|
1782
|
-
|
|
1783
1845
|
return step if method_name == :[]
|
|
1784
1846
|
|
|
1785
|
-
|
|
1847
|
+
keys = literal_keys(args.first)
|
|
1848
|
+
return nil if keys.nil?
|
|
1849
|
+
return nil if keys.any? { |key| shape.optional_key?(key) || (shape.closed? && !shape.pairs.key?(key)) }
|
|
1850
|
+
|
|
1851
|
+
step
|
|
1786
1852
|
end
|
|
1787
1853
|
|
|
1788
1854
|
# `shape.dig(:a, :b, ...)` with a chain of static keys. Same recursion semantics as Tuple#`dig`:
|
|
@@ -1799,20 +1865,45 @@ module Rigor
|
|
|
1799
1865
|
end
|
|
1800
1866
|
|
|
1801
1867
|
# Returns the per-step value type for a HashShape lookup (or `Constant[nil]` for a known-missing
|
|
1802
|
-
# key)
|
|
1803
|
-
# through to the projection answer.
|
|
1868
|
+
# key), or `nil` so the caller falls through to the projection answer.
|
|
1804
1869
|
#
|
|
1805
1870
|
# A key outside `pairs` only resolves to `Constant[nil]` on a CLOSED shape, where `pairs` is the
|
|
1806
1871
|
# whole key set and the runtime read provably returns nil. On an `:open` shape the key set is by
|
|
1807
1872
|
# definition not exhausted, so an undeclared key is *unknown*, not absent — it may hold a value
|
|
1808
1873
|
# of any type. Typing it `Constant[nil]` there would put `call.undefined-method` on the next line
|
|
1809
1874
|
# of correct code (`payload[:undeclared].upcase`), so the open case answers `untyped`.
|
|
1875
|
+
#
|
|
1876
|
+
# A union of value-pinned keys that the shape all declares answers the union of their steps, which
|
|
1877
|
+
# is exact. Any other key is computed — including a union with an undeclared member, whose per-member
|
|
1878
|
+
# answer on a stale shape is the same lone `Constant[nil]` the empty-shape rule below refuses. On a
|
|
1879
|
+
# closed shape a computed key may match any declared key or none, so the step is every value plus
|
|
1880
|
+
# `Constant[nil]`. Deferring it instead let the projection answer the value union alone — nil-free,
|
|
1881
|
+
# since `RbsDispatch` reads past `Hash#[]`'s `%a{implicitly-returns-nil}` — and
|
|
1882
|
+
# `o = { a: 1 }; o[name] == 1` folded always-truthy. An open shape still defers: its undeclared keys
|
|
1883
|
+
# may hold any value. So does the empty shape: a hash read by a computed key while it looks empty is
|
|
1884
|
+
# one filled where the analysis did not see — a loop body's earlier iteration
|
|
1885
|
+
# (`h = {}; xs.each { |x| h[x] = h[x] ? h[x] + 1 : 1 }`), a cache (`(@cache ||= {})[key]`), an
|
|
1886
|
+
# `instance_eval`ed file — and answering `Constant[nil]` there folds its own guard always-falsey.
|
|
1810
1887
|
def hash_dig_step(shape, arg)
|
|
1811
|
-
|
|
1888
|
+
keys = literal_keys(arg)
|
|
1889
|
+
if keys && (keys.size == 1 || keys.all? { |key| shape.pairs.key?(key) })
|
|
1890
|
+
return Type::Combinator.union(*keys.map { |key| static_key_step(shape, key) })
|
|
1891
|
+
end
|
|
1892
|
+
return nil if shape.open? || shape.pairs.empty?
|
|
1812
1893
|
|
|
1813
|
-
|
|
1814
|
-
|
|
1894
|
+
Type::Combinator.union(*shape.pairs.values, Type::Combinator.constant_of(nil))
|
|
1895
|
+
end
|
|
1896
|
+
|
|
1897
|
+
# The value-pinned keys `arg` can take — one for a scalar `Constant`, one per member for a union of
|
|
1898
|
+
# them — or `nil` when it can take any other value.
|
|
1899
|
+
def literal_keys(arg)
|
|
1900
|
+
members = arg.is_a?(Type::Union) ? arg.members : [arg]
|
|
1901
|
+
return nil unless members.all? { |member| member.is_a?(Type::Constant) && static_shape_key?(member.value) }
|
|
1815
1902
|
|
|
1903
|
+
members.map(&:value)
|
|
1904
|
+
end
|
|
1905
|
+
|
|
1906
|
+
def static_key_step(shape, key)
|
|
1816
1907
|
if shape.pairs.key?(key)
|
|
1817
1908
|
value = shape.pairs[key]
|
|
1818
1909
|
return value unless shape.optional_key?(key)
|
|
@@ -1825,26 +1916,10 @@ module Rigor
|
|
|
1825
1916
|
Type::Combinator.constant_of(nil)
|
|
1826
1917
|
end
|
|
1827
1918
|
|
|
1828
|
-
def optional_key_step?(shape, arg)
|
|
1829
|
-
return false unless arg.is_a?(Type::Constant)
|
|
1830
|
-
|
|
1831
|
-
shape.optional_key?(arg.value)
|
|
1832
|
-
end
|
|
1833
|
-
|
|
1834
|
-
# Whether the key is provably ABSENT — which only a closed shape can establish. An open shape
|
|
1835
|
-
# permits keys outside `pairs`, so a key it does not declare is unknown rather than missing, and
|
|
1836
|
-
# `fetch` must not be deferred on the theory that Ruby would raise `KeyError`: the key may well
|
|
1837
|
-
# be there. {#hash_dig_step} has already answered `untyped` for that case.
|
|
1838
|
-
def missing_key_step?(shape, arg)
|
|
1839
|
-
return false unless arg.is_a?(Type::Constant)
|
|
1840
|
-
return false if shape.open?
|
|
1841
|
-
|
|
1842
|
-
!shape.pairs.key?(arg.value)
|
|
1843
|
-
end
|
|
1844
|
-
|
|
1845
1919
|
# `shape.values_at(:a, :b, ...)` with a list of static keys. Returns a `Tuple` whose per-position
|
|
1846
1920
|
# values are the per-key value types (`Constant[nil]` for missing keys, mirroring Ruby's runtime
|
|
1847
|
-
# behaviour).
|
|
1921
|
+
# behaviour). A computed key takes the nil-bearing step {#hash_dig_step} gives it; the call falls
|
|
1922
|
+
# through when any step does (a computed key on an open shape).
|
|
1848
1923
|
def hash_values_at(shape, _method_name, args)
|
|
1849
1924
|
return nil if args.empty?
|
|
1850
1925
|
|
|
@@ -31,8 +31,7 @@ module Rigor
|
|
|
31
31
|
|
|
32
32
|
module_function
|
|
33
33
|
|
|
34
|
-
# @
|
|
35
|
-
# @return [Rigor::Type, nil] `Nominal[C]` for `C.instance`, or nil to decline.
|
|
34
|
+
# @return `Nominal[C]` for `C.instance`, or nil to decline.
|
|
36
35
|
def try_dispatch(context)
|
|
37
36
|
return nil unless context.method_name == SELECTOR
|
|
38
37
|
return nil unless context.args.empty?
|
|
@@ -45,7 +45,7 @@ module Rigor
|
|
|
45
45
|
# Issue #595 / #525 — the shared materialisation test; see {StructMaterialization}.
|
|
46
46
|
extend StructMaterialization
|
|
47
47
|
|
|
48
|
-
# @return
|
|
48
|
+
# @return the folded result, or nil to defer.
|
|
49
49
|
def try_dispatch(context)
|
|
50
50
|
receiver = context.receiver
|
|
51
51
|
|
|
@@ -344,10 +344,9 @@ module Rigor
|
|
|
344
344
|
# local's true member state at every later read on the path. A non-fold-safe local is left untouched
|
|
345
345
|
# (its reads do not fold, so the binding is never consulted for folding).
|
|
346
346
|
#
|
|
347
|
-
# @param call_node
|
|
348
|
-
# @param assigned_type
|
|
349
|
-
# @
|
|
350
|
-
# @return [Rigor::Scope] the (possibly) rebound scope
|
|
347
|
+
# @param call_node — the `local.member = v` call
|
|
348
|
+
# @param assigned_type — the setter's assigned value type (the call's own result)
|
|
349
|
+
# @return the (possibly) rebound scope
|
|
351
350
|
def apply_setter_writeback(call_node:, assigned_type:, scope:)
|
|
352
351
|
return scope if scope.nil? || assigned_type.nil?
|
|
353
352
|
|
|
@@ -365,7 +364,7 @@ module Rigor
|
|
|
365
364
|
members: widen_unowned_emptiness(current.members.merge(member => assigned_type)),
|
|
366
365
|
class_name: current.class_name
|
|
367
366
|
)
|
|
368
|
-
scope.
|
|
367
|
+
scope.with_mutated_local(receiver.name, rebound)
|
|
369
368
|
end
|
|
370
369
|
end
|
|
371
370
|
end
|