rigortype 0.3.7 → 0.3.9
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 +1 -1
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +109 -13
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +37 -4
- 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 +14 -1
- data/docs/handbook/11-sig-gen.md +96 -15
- 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 +39 -4
- data/docs/manual/03-configuration.md +11 -0
- data/docs/manual/04-diagnostics.md +12 -1
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -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 +6 -1
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/plugins/rigor-actionpack.md +18 -0
- data/docs/manual/plugins/rigor-activerecord.md +28 -0
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +32 -2
- data/docs/manual/plugins/rigor-rbs-inline.md +42 -1
- data/lib/rigor/analysis/baseline.rb +2 -2
- 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/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +39 -4
- 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/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +200 -32
- data/lib/rigor/analysis/crash_signature.rb +69 -13
- 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 +6 -1
- data/lib/rigor/analysis/incremental.rb +16 -0
- data/lib/rigor/analysis/incremental_session.rb +100 -29
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -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 +2 -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 +4 -1
- data/lib/rigor/analysis/run_cache_key.rb +1 -1
- 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 +316 -40
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -10
- data/lib/rigor/analysis/runner/pool_coordinator.rb +430 -77
- data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
- data/lib/rigor/analysis/runner/run_snapshots.rb +13 -3
- data/lib/rigor/analysis/runner.rb +200 -43
- data/lib/rigor/analysis/worker_session.rb +36 -12
- data/lib/rigor/bleeding_edge.rb +12 -24
- data/lib/rigor/builtins/hkt_builtins.rb +2 -2
- data/lib/rigor/builtins/imported_refinements.rb +166 -30
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +4 -4
- data/lib/rigor/builtins/static_return_refinements.rb +5 -6
- data/lib/rigor/cache/annotation_location.rb +70 -0
- data/lib/rigor/cache/descriptor.rb +58 -20
- data/lib/rigor/cache/engine_source.rb +4 -4
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +40 -6
- 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 +79 -11
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +39 -0
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +85 -33
- 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 +3 -3
- data/lib/rigor/cli/docs_command.rb +2 -2
- 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 +1 -1
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +2 -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 +31 -2
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +36 -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 +10 -6
- 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 +68 -6
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +6 -6
- data/lib/rigor/configuration.rb +43 -4
- data/lib/rigor/effects/attribution.rb +1 -3
- data/lib/rigor/effects/config_envelopes.rb +6 -8
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +0 -1
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +8 -8
- data/lib/rigor/effects/envelope_index.rb +5 -8
- data/lib/rigor/effects/framework_units.rb +4 -6
- data/lib/rigor/effects/identity.rb +4 -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/method_key.rb +1 -1
- data/lib/rigor/effects/plugin_facts.rb +4 -6
- data/lib/rigor/effects/propagator.rb +2 -3
- data/lib/rigor/effects/scanner.rb +1 -1
- data/lib/rigor/effects/signature_sources.rb +3 -5
- data/lib/rigor/effects/snapshot.rb +10 -10
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/unit_scan.rb +10 -10
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- 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 +28 -0
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +51 -4
- 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 +613 -113
- data/lib/rigor/environment.rb +189 -27
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/inference/acceptance.rb +153 -8
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/body_fixpoint.rb +5 -5
- data/lib/rigor/inference/budget_trace.rb +1 -5
- data/lib/rigor/inference/captured_locals.rb +2 -3
- data/lib/rigor/inference/closure_escape_analyzer.rb +2 -4
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +168 -0
- data/lib/rigor/inference/expression_typer.rb +763 -143
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +19 -10
- data/lib/rigor/inference/hkt_sugar_translator.rb +15 -21
- data/lib/rigor/inference/index_write_widening.rb +1 -5
- data/lib/rigor/inference/macro_block_self_type.rb +1 -4
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +2 -9
- 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/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +2 -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/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 +61 -47
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +165 -31
- 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/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -1
- 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 +4 -5
- 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 +12 -13
- data/lib/rigor/inference/method_parameter_binder.rb +4 -6
- data/lib/rigor/inference/multi_target_binder.rb +1 -3
- data/lib/rigor/inference/mutation_rejoin.rb +168 -0
- data/lib/rigor/inference/mutation_widening.rb +100 -51
- data/lib/rigor/inference/narrowing.rb +299 -46
- data/lib/rigor/inference/optimistic_origin.rb +1 -7
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_patched_methods.rb +2 -2
- data/lib/rigor/inference/project_patched_scanner.rb +3 -3
- 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 +3 -3
- data/lib/rigor/inference/refinement_mutation.rb +72 -0
- data/lib/rigor/inference/scope_indexer.rb +688 -151
- data/lib/rigor/inference/statement_evaluator.rb +221 -50
- data/lib/rigor/inference/string_mutation.rb +60 -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/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 +1 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
- 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 +2 -2
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +2 -5
- 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/plugin/base.rb +90 -21
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +7 -7
- 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 +31 -12
- 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 +23 -1
- data/lib/rigor/plugin/registry.rb +67 -14
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +12 -1
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- 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 +11 -11
- data/lib/rigor/protection/kill_signature.rb +2 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +6 -9
- 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 +12 -13
- data/lib/rigor/rbs_extended/hkt_directives.rb +16 -1
- data/lib/rigor/rbs_extended/reporter.rb +122 -16
- data/lib/rigor/rbs_extended.rb +67 -22
- data/lib/rigor/reflection/constant_path.rb +126 -0
- data/lib/rigor/reflection.rb +26 -10
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +30 -0
- data/lib/rigor/scope.rb +203 -4
- data/lib/rigor/sig_gen/generator.rb +181 -102
- 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/observation_collector.rb +17 -15
- 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 +17 -11
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +111 -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/writer.rb +23 -6
- 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 +2 -5
- 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 +68 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +5 -5
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +3 -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/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.rb +1 -0
- 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 +1 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +33 -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.rb +28 -2
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -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 +1 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +3 -4
- 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 +42 -7
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -0
- 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 +119 -14
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +1 -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 +1 -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.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +6 -3
- 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 +0 -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 +1 -0
- 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 +1 -0
- 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 +1 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +3 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +2 -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 +1 -0
- 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.rb +128 -3
- 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 +1 -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 +1 -0
- 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 +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +5 -5
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/environment.rbs +11 -0
- data/sig/rigor/inference.rbs +3 -10
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/manifest.rbs +2 -1
- data/sig/rigor/reflection.rbs +3 -1
- data/sig/rigor/scope.rbs +24 -3
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -0
- data/sig/rigor/type.rbs +27 -1
- data/sig/rigor.rbs +1 -0
- data/skills/rigor-ask/SKILL.md +8 -6
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +13 -2
- data/skills/rigor-project-init/SKILL.md +6 -3
- data/skills/rigor-project-init/references/02-configure.md +10 -6
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-type-oracle/SKILL.md +228 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +261 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +128 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +8 -5
- metadata +28 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "prism"
|
|
4
4
|
|
|
5
5
|
require_relative "../environment"
|
|
6
|
+
require_relative "../project_environment"
|
|
6
7
|
require_relative "../scope"
|
|
7
8
|
require_relative "../cache/store"
|
|
8
9
|
require_relative "../plugin"
|
|
@@ -16,6 +17,7 @@ require_relative "../effects/envelope_index"
|
|
|
16
17
|
require_relative "../inference/scope_indexer"
|
|
17
18
|
require_relative "../inference/method_dispatcher/file_folding"
|
|
18
19
|
require_relative "check_rules"
|
|
20
|
+
require_relative "crash_signature"
|
|
19
21
|
require_relative "dependency_recorder"
|
|
20
22
|
require_relative "dependency_source_inference"
|
|
21
23
|
require_relative "diagnostic"
|
|
@@ -72,12 +74,11 @@ module Rigor
|
|
|
72
74
|
:rbs_extended_reporter, :boundary_cross_reporter,
|
|
73
75
|
:prepare_diagnostics
|
|
74
76
|
|
|
75
|
-
# @param
|
|
76
|
-
# @param cache_store [Rigor::Cache::Store, nil] persistent cache the session exposes to plugin-side
|
|
77
|
+
# @param cache_store — persistent cache the session exposes to plugin-side
|
|
77
78
|
# producers and the RBS loader. Pass `nil` to disable caching.
|
|
78
|
-
# @param plugin_blueprints
|
|
79
|
+
# @param plugin_blueprints — replay descriptors. Empty array yields a
|
|
79
80
|
# session with no plugin contributions.
|
|
80
|
-
# @param explain
|
|
81
|
+
# @param explain — when true, `#analyze` additionally emits one `:info` `fallback` diagnostic
|
|
81
82
|
# per directly-unrecognised node, mirroring {Rigor::Analysis::Runner#explain_diagnostics}.
|
|
82
83
|
def initialize(configuration:, cache_store: nil, # rubocop:disable Metrics/MethodLength,Metrics/ParameterLists
|
|
83
84
|
plugin_blueprints: [], explain: false, buffer: nil,
|
|
@@ -136,11 +137,7 @@ module Rigor
|
|
|
136
137
|
rbs_extended_reporter: @rbs_extended_reporter,
|
|
137
138
|
boundary_cross_reporter: @boundary_cross_reporter,
|
|
138
139
|
source_rbs_synthesis_reporter: @source_rbs_synthesis_reporter,
|
|
139
|
-
|
|
140
|
-
bundler_auto_detect: configuration.bundler_auto_detect,
|
|
141
|
-
bundler_lockfile: configuration.bundler_lockfile,
|
|
142
|
-
rbs_collection_lockfile: configuration.rbs_collection_lockfile,
|
|
143
|
-
rbs_collection_auto_detect: configuration.rbs_collection_auto_detect,
|
|
140
|
+
**ProjectEnvironment.dependency_discovery_options(configuration),
|
|
144
141
|
synthetic_method_index: @synthetic_method_index,
|
|
145
142
|
project_patched_methods: @project_patched_methods,
|
|
146
143
|
source_files: @source_files
|
|
@@ -228,7 +225,7 @@ module Rigor
|
|
|
228
225
|
rescue Errno::ENOENT => e
|
|
229
226
|
[analyzer_error(path, e.message)]
|
|
230
227
|
rescue StandardError => e
|
|
231
|
-
[analyzer_error(path,
|
|
228
|
+
[analyzer_error(path, CrashSignature.check_rule_message(e))]
|
|
232
229
|
end
|
|
233
230
|
private :analyze_body
|
|
234
231
|
|
|
@@ -243,15 +240,42 @@ module Rigor
|
|
|
243
240
|
# how you ran it" defect the diagnostic exists to end. Draining it out of the workers is what makes
|
|
244
241
|
# the two paths say the same thing. The payload is `[String, String, String, Array<String>]` tuples —
|
|
245
242
|
# Marshal-clean for the fork backend and shareable for the Ractor one.
|
|
243
|
+
#
|
|
244
|
+
# Issue #784 — `hkt_scan_failure` rides the same channel for the same reason: the PARENT's own
|
|
245
|
+
# Environment never demands `#hkt_registry` under the pool, so its slot is always nil, and draining it
|
|
246
|
+
# out of the workers is the only way `--workers=N` says what `--workers=0` says.
|
|
247
|
+
#
|
|
248
|
+
# Issue #805 — the Marshal-clean requirement binds every stream here, not just the ones written for it.
|
|
249
|
+
# The `RbsExtended::Reporter`'s unresolved / lossy-projection entries used to carry the `RBS::Location`
|
|
250
|
+
# itself, and `Marshal.dump` on one raises `TypeError` (a C-extension object with no `_dump`), so a
|
|
251
|
+
# project whose `sig/` produced a single such event killed each worker HERE — after its files were
|
|
252
|
+
# analysed — and the run degraded to in-process re-analysis with a `pool-degraded` row. All three
|
|
253
|
+
# streams now carry `(path, line, column)` primitives.
|
|
246
254
|
def drain_reporters
|
|
255
|
+
# Issue #784 — demand the registry once per worker before reading the slot, so a worker whose share
|
|
256
|
+
# of files happened to contain no `Klass.method` call still reports the run's outcome (the same
|
|
257
|
+
# reason `PoolCoordinator#hkt_scan_outcome` demands it on the sequential path). The Environment
|
|
258
|
+
# object is built in the constructor, but its RBS env is lazy: on a worker that analysed a file this
|
|
259
|
+
# is a memoised read; on one that demanded nothing it is the same cache-served env load that file
|
|
260
|
+
# would have paid. The fork backend never hands a worker an empty slice, so no idle worker pays it.
|
|
261
|
+
@environment&.hkt_registry
|
|
247
262
|
{
|
|
248
263
|
rbs_extended: {
|
|
249
264
|
unresolved_payloads: @rbs_extended_reporter.unresolved_payloads,
|
|
250
|
-
lossy_projections: @rbs_extended_reporter.lossy_projections
|
|
265
|
+
lossy_projections: @rbs_extended_reporter.lossy_projections,
|
|
266
|
+
# Issue #785 — the HKT directive stream rides the same channel for the same reason
|
|
267
|
+
# `hkt_scan_failure` does: the directives are read by the registry scan, and under the pool the
|
|
268
|
+
# PARENT never demands that scan, so a diagnostic wired off the parent's reporter would appear
|
|
269
|
+
# at `--workers=0` and vanish at `--workers=N`. The demand above is what fills this.
|
|
270
|
+
hkt_directive_errors: @rbs_extended_reporter.hkt_directive_errors,
|
|
271
|
+
# ADR-109 WD3 — the deprecated-form stream rides the same channel: the payload is read where
|
|
272
|
+
# the annotated method is dispatched, which under the pool is only ever inside a worker.
|
|
273
|
+
deprecated_forms: @rbs_extended_reporter.deprecated_forms
|
|
251
274
|
},
|
|
252
275
|
boundary_cross: @boundary_cross_reporter.entries,
|
|
253
276
|
source_rbs_synthesis: @source_rbs_synthesis_reporter.entries,
|
|
254
|
-
definition_build_failures: @environment&.rbs_loader&.definition_build_failures || []
|
|
277
|
+
definition_build_failures: @environment&.rbs_loader&.definition_build_failures || [],
|
|
278
|
+
hkt_scan_failure: @environment&.hkt_scan_failure
|
|
255
279
|
}
|
|
256
280
|
end
|
|
257
281
|
|
data/lib/rigor/bleeding_edge.rb
CHANGED
|
@@ -51,14 +51,14 @@ module Rigor
|
|
|
51
51
|
# migration note and a user's `bleeding_edge:` list both key on.
|
|
52
52
|
#
|
|
53
53
|
# @!attribute id
|
|
54
|
-
# @return
|
|
54
|
+
# @return the stable feature id (contract vocabulary).
|
|
55
55
|
# @!attribute summary
|
|
56
|
-
# @return
|
|
56
|
+
# @return a one-line description of what it changes. For a `:behaviour`
|
|
57
57
|
# feature this is the *whole* explanation — there is no severity diff to read.
|
|
58
58
|
# @!attribute kind
|
|
59
|
-
# @return
|
|
59
|
+
# @return one of {KINDS}.
|
|
60
60
|
# @!attribute severity_overrides
|
|
61
|
-
# @return
|
|
61
|
+
# @return canonical rule id → the severity this feature
|
|
62
62
|
# imposes. Composed *below* the user's own `severity_overrides:` and *above* the
|
|
63
63
|
# active `severity_profile` (see {Configuration::SeverityProfile.resolve}). Empty for
|
|
64
64
|
# a `:behaviour` feature.
|
|
@@ -76,12 +76,10 @@ module Rigor
|
|
|
76
76
|
super
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
# @return [Boolean]
|
|
80
79
|
def severity?
|
|
81
80
|
kind == :severity
|
|
82
81
|
end
|
|
83
82
|
|
|
84
|
-
# @return [Boolean]
|
|
85
83
|
def behaviour?
|
|
86
84
|
kind == :behaviour
|
|
87
85
|
end
|
|
@@ -193,36 +191,30 @@ module Rigor
|
|
|
193
191
|
# cleanup can lag graduation by as many releases as it takes. The id also stays in the
|
|
194
192
|
# contract vocabulary the CHANGELOG migration note keys on. Entries are removed only once
|
|
195
193
|
# no call site names them.
|
|
196
|
-
#
|
|
197
|
-
# @return [Array<String>]
|
|
198
194
|
GRADUATED = [].freeze
|
|
199
195
|
|
|
200
196
|
module_function
|
|
201
197
|
|
|
202
|
-
# @return
|
|
198
|
+
# @return the whole overlay.
|
|
203
199
|
def features
|
|
204
200
|
FEATURES
|
|
205
201
|
end
|
|
206
202
|
|
|
207
|
-
# @return
|
|
203
|
+
# @return every feature id in the overlay.
|
|
208
204
|
def feature_ids
|
|
209
205
|
FEATURES.map(&:id)
|
|
210
206
|
end
|
|
211
207
|
|
|
212
|
-
# @param id [String]
|
|
213
|
-
# @return [Feature, nil]
|
|
214
208
|
def feature(id)
|
|
215
209
|
FEATURES.find { |f| f.id == id }
|
|
216
210
|
end
|
|
217
211
|
|
|
218
|
-
# @
|
|
219
|
-
# @return [Boolean] whether the id has graduated to default-on ({GRADUATED}).
|
|
212
|
+
# @return whether the id has graduated to default-on ({GRADUATED}).
|
|
220
213
|
def graduated?(id)
|
|
221
214
|
GRADUATED.include?(id)
|
|
222
215
|
end
|
|
223
216
|
|
|
224
|
-
# @
|
|
225
|
-
# @return [Boolean] whether the id names a feature this gem knows at all — queued or
|
|
217
|
+
# @return whether the id names a feature this gem knows at all — queued or
|
|
226
218
|
# graduated. Distinct from "adopted"; see {Configuration#bleeding_edge_active?}.
|
|
227
219
|
def known_id?(id)
|
|
228
220
|
graduated?(id) || FEATURES.any? { |f| f.id == id }
|
|
@@ -234,10 +226,9 @@ module Rigor
|
|
|
234
226
|
# `severity_overrides:` keeps an unknown rule id inert until it lands (robust across gem
|
|
235
227
|
# versions).
|
|
236
228
|
#
|
|
237
|
-
# @param selector
|
|
229
|
+
# @param selector — `{ "mode" => "none" }`,
|
|
238
230
|
# `{ "mode" => "all" }`, `{ "mode" => "all", "except" => [ids] }`,
|
|
239
231
|
# or `{ "mode" => "list", "ids" => [ids] }`.
|
|
240
|
-
# @return [Array<Feature>]
|
|
241
232
|
def active_features(selector)
|
|
242
233
|
case selector["mode"]
|
|
243
234
|
when "all"
|
|
@@ -254,8 +245,7 @@ module Rigor
|
|
|
254
245
|
# The merged severity-override map the active features impose for a selector. Frozen so
|
|
255
246
|
# the result is `Ractor.shareable?`.
|
|
256
247
|
#
|
|
257
|
-
# @param selector
|
|
258
|
-
# @return [Hash{String => Symbol}]
|
|
248
|
+
# @param selector — see {#active_features}.
|
|
259
249
|
def severity_overrides_for(selector)
|
|
260
250
|
active_features(selector).each_with_object({}) do |feature, acc|
|
|
261
251
|
acc.merge!(feature.severity_overrides)
|
|
@@ -267,8 +257,7 @@ module Rigor
|
|
|
267
257
|
# Precomputed once per Configuration; frozen (with frozen members) so the carrier stays
|
|
268
258
|
# `Ractor.shareable?` across the worker boundary.
|
|
269
259
|
#
|
|
270
|
-
# @param selector
|
|
271
|
-
# @return [Set<String>]
|
|
260
|
+
# @param selector — see {#active_features}.
|
|
272
261
|
def active_ids_for(selector)
|
|
273
262
|
Set.new(active_features(selector).map(&:id)).freeze
|
|
274
263
|
end
|
|
@@ -276,8 +265,7 @@ module Rigor
|
|
|
276
265
|
# Feature ids named by a selector that are NOT in the overlay (typo / graduated / from a
|
|
277
266
|
# newer gem). Surfaced by `rigor show-bleedingedge` as a hint; never an error.
|
|
278
267
|
#
|
|
279
|
-
# @param selector
|
|
280
|
-
# @return [Array<String>]
|
|
268
|
+
# @param selector — see {#active_features}.
|
|
281
269
|
def unknown_selected_ids(selector)
|
|
282
270
|
named =
|
|
283
271
|
case selector["mode"]
|
|
@@ -118,7 +118,7 @@ module Rigor
|
|
|
118
118
|
)
|
|
119
119
|
end
|
|
120
120
|
|
|
121
|
-
# @return
|
|
121
|
+
# @return frozen registry
|
|
122
122
|
# pre-seeded with all bundled HKT registrations +
|
|
123
123
|
# bodies. Allocated fresh each call rather than
|
|
124
124
|
# memoised — memoisation through a module-level
|
|
@@ -242,7 +242,7 @@ module Rigor
|
|
|
242
242
|
["CSV", :parse_line, :singleton] => CSV_ROW_SPEC
|
|
243
243
|
}.freeze
|
|
244
244
|
|
|
245
|
-
# @return
|
|
245
|
+
# @return the reduced HKT type for
|
|
246
246
|
# the given (class_name, method_name, kind) triple,
|
|
247
247
|
# or `nil` when no built-in override is registered.
|
|
248
248
|
# When `arg_types` is supplied AND the entry carries a
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "strscan"
|
|
4
4
|
|
|
5
|
+
require_relative "../rbs_extended/reporter"
|
|
5
6
|
require_relative "../type"
|
|
6
7
|
require_relative "../type_node"
|
|
7
8
|
|
|
@@ -30,11 +31,12 @@ module Rigor
|
|
|
30
31
|
# - **No-argument refinement names** (`non-empty-string`, `non-zero-int`,
|
|
31
32
|
# `lowercase-string`, …) live in `REGISTRY` and resolve through `lookup(name)`.
|
|
32
33
|
# - **Parameterised refinement payloads** (`non-empty-array[Integer]`,
|
|
33
|
-
# `non-empty-hash[Symbol, Integer]`, `int<5, 10>`)
|
|
34
|
-
# full grammar is documented on `Parser`. The two
|
|
35
|
-
# no-arg head names; the parameterised head names live
|
|
36
|
-
# (square-bracket form, type args)
|
|
37
|
-
#
|
|
34
|
+
# `non-empty-hash[Symbol, Integer]`, `Integer[5..10]`, and the deprecated `int<5, 10>`)
|
|
35
|
+
# are accepted by `parse(payload)`. The full grammar is documented on `Parser`. The two
|
|
36
|
+
# surfaces share `REGISTRY` for the no-arg head names; the parameterised head names live
|
|
37
|
+
# in `PARAMETERISED_TYPE_BUILDERS` (square-bracket form, type args), `RANGE_HEAD_BUILDERS`
|
|
38
|
+
# (a numeric class over a range literal) and `PARAMETERISED_INT_BUILDERS` (the deprecated
|
|
39
|
+
# angle-bracket form, integer bounds).
|
|
38
40
|
module ImportedRefinements
|
|
39
41
|
REGISTRY = {
|
|
40
42
|
"non-empty-string" => -> { Type::Combinator.non_empty_string },
|
|
@@ -57,7 +59,10 @@ module Rigor
|
|
|
57
59
|
"non-empty-lowercase-string" => -> { Type::Combinator.non_empty_lowercase_string },
|
|
58
60
|
"non-empty-uppercase-string" => -> { Type::Combinator.non_empty_uppercase_string },
|
|
59
61
|
"literal-string" => -> { Type::Combinator.literal_string },
|
|
60
|
-
"non-empty-literal-string" => -> { Type::Combinator.non_empty_literal_string }
|
|
62
|
+
"non-empty-literal-string" => -> { Type::Combinator.non_empty_literal_string },
|
|
63
|
+
# ADR-109 WD4 — names for the two Float ranges people mean most; each is an alias of a range.
|
|
64
|
+
"non-nan-float" => -> { Type::Combinator.non_nan_float },
|
|
65
|
+
"finite-float" => -> { Type::Combinator.finite_float }
|
|
61
66
|
}.freeze
|
|
62
67
|
private_constant :REGISTRY
|
|
63
68
|
|
|
@@ -138,13 +143,52 @@ module Rigor
|
|
|
138
143
|
}.freeze
|
|
139
144
|
private_constant :PARAMETERISED_TYPE_BUILDERS
|
|
140
145
|
|
|
141
|
-
# `
|
|
146
|
+
# `Class[range]` — a numeric class head bounded by a Ruby range literal (ADR-109). The
|
|
147
|
+
# builder receives the `Range` value and returns the carrier, or `nil` when the range is
|
|
148
|
+
# empty or its endpoints are not literals of the head class; `nil` surfaces as the ordinary
|
|
149
|
+
# unresolved-payload diagnostic. `Float` joins this table with the `FloatRange` carrier.
|
|
150
|
+
RANGE_HEAD_BUILDERS = {
|
|
151
|
+
"Integer" => lambda { |range|
|
|
152
|
+
lo = range.begin
|
|
153
|
+
hi = range.end
|
|
154
|
+
return nil unless (lo.nil? || lo.is_a?(Integer)) && (hi.nil? || hi.is_a?(Integer))
|
|
155
|
+
|
|
156
|
+
# `1...10` is the set `1..9`: Integer ranges canonicalise to the closed form.
|
|
157
|
+
hi -= 1 if range.exclude_end? && hi.is_a?(Integer)
|
|
158
|
+
return nil if lo.is_a?(Integer) && hi.is_a?(Integer) && lo > hi
|
|
159
|
+
|
|
160
|
+
Type::Combinator.integer_range(lo || Type::IntegerRange::NEG_INFINITY, hi || Type::IntegerRange::POS_INFINITY)
|
|
161
|
+
},
|
|
162
|
+
# ADR-109 WD4 — `Float[R]` is the set of Floats `R.cover?` accepts. A missing or `nil` endpoint
|
|
163
|
+
# is the infinity on that side, except that `nil..nil` covers NaN in Ruby and so is `Float`
|
|
164
|
+
# itself; an Integer endpoint coerces (`(0..1).cover?(0.5)` is true); an exclusive end is kept
|
|
165
|
+
# (the carrier canonicalises it for equality), and an empty range declines.
|
|
166
|
+
"Float" => lambda { |range|
|
|
167
|
+
return Type::Combinator.nominal_of("Float") if range.begin.nil? && range.end.nil?
|
|
168
|
+
|
|
169
|
+
lo = ImportedRefinements.float_range_endpoint(range.begin, -Float::INFINITY)
|
|
170
|
+
hi = ImportedRefinements.float_range_endpoint(range.end, Float::INFINITY)
|
|
171
|
+
return nil if lo.nil? || hi.nil?
|
|
172
|
+
|
|
173
|
+
exclusive = range.exclude_end? && !range.end.nil?
|
|
174
|
+
return nil if lo > (exclusive ? hi.prev_float : hi)
|
|
175
|
+
|
|
176
|
+
Type::Combinator.float_range(lo, hi, exclude_end: exclusive)
|
|
177
|
+
}
|
|
178
|
+
}.freeze
|
|
179
|
+
private_constant :RANGE_HEAD_BUILDERS
|
|
180
|
+
|
|
181
|
+
# `name<min, max>` — the PHPStan-style integer-bound form ADR-109 deprecates: still parsed so
|
|
182
|
+
# signatures written against v0.1–v0.3 keep resolving, never displayed. Each builder takes an
|
|
142
183
|
# `Array<Integer>` and returns a `Rigor::Type` (or `nil`). Bounds are signed integer
|
|
143
|
-
# literals
|
|
144
|
-
#
|
|
184
|
+
# literals. A reversed pair (`min` > `max`) is declined as `nil` like every other shape
|
|
185
|
+
# mismatch, so the caller surfaces `dynamic.rbs-extended.unresolved` at the annotation;
|
|
186
|
+
# `Type::IntegerRange` raises on it instead, and that `ArgumentError` used to escape as an
|
|
187
|
+
# `internal analyzer error` that abandoned the whole Ruby file.
|
|
145
188
|
PARAMETERISED_INT_BUILDERS = {
|
|
146
189
|
"int" => lambda { |bounds|
|
|
147
190
|
return nil unless bounds.size == 2
|
|
191
|
+
return nil if bounds[0] > bounds[1]
|
|
148
192
|
|
|
149
193
|
Type::Combinator.integer_range(bounds[0], bounds[1])
|
|
150
194
|
}
|
|
@@ -153,32 +197,32 @@ module Rigor
|
|
|
153
197
|
|
|
154
198
|
module_function
|
|
155
199
|
|
|
156
|
-
# @param name
|
|
157
|
-
# @return
|
|
200
|
+
# @param name — kebab-case refinement name.
|
|
201
|
+
# @return the matching refinement carrier, or `nil` if the name is
|
|
158
202
|
# not registered.
|
|
159
203
|
def lookup(name)
|
|
160
204
|
builder = REGISTRY[name.to_s]
|
|
161
205
|
builder&.call
|
|
162
206
|
end
|
|
163
207
|
|
|
164
|
-
# @param payload
|
|
208
|
+
# @param payload — the trailing payload of a `rigor:v1:return:` (or sibling)
|
|
165
209
|
# directive. Accepts the bare-name forms `lookup` already handles plus the
|
|
166
210
|
# parameterised forms documented on {Parser}.
|
|
167
|
-
# @param name_scope
|
|
211
|
+
# @param name_scope —
|
|
168
212
|
# ADR-13 slice 3 — when provided, the parser consults the scope's `#resolver` chain
|
|
169
213
|
# after the built-in registry and built-in parametric forms but before the RBS
|
|
170
214
|
# Nominal fallback. `nil` (default) preserves the slice-1 / slice-2 behaviour of
|
|
171
215
|
# consulting only built-ins + RBS.
|
|
172
|
-
# @param reporter
|
|
216
|
+
# @param reporter —
|
|
173
217
|
# ADR-13 slice 3b — collector that the Resolver feeds `dynamic.shape.lossy-projection`
|
|
174
218
|
# events into when a shape-projection head (`pick_of`, `omit_of`, `partial_of`,
|
|
175
219
|
# `required_of`, `readonly_of`) is applied to a carrier that does not preserve shape
|
|
176
220
|
# information. `nil` (default) suppresses event accumulation; legacy call sites that
|
|
177
221
|
# have no reporter to thread keep the pre-slice-3b silent fall-through.
|
|
178
|
-
# @param source_location
|
|
222
|
+
# @param source_location — location attribution for the events the
|
|
179
223
|
# Resolver records. Carries the annotation's filename / line / column so the runner
|
|
180
224
|
# can stamp diagnostics with the user-visible source site.
|
|
181
|
-
# @return
|
|
225
|
+
# @return the resolved refinement carrier, or `nil` when the payload
|
|
182
226
|
# is unparseable or names a refinement / class no registered source resolved.
|
|
183
227
|
def parse(payload, name_scope: nil, reporter: nil, source_location: nil)
|
|
184
228
|
Parser.new(
|
|
@@ -200,6 +244,20 @@ module Rigor
|
|
|
200
244
|
PARAMETERISED_INT_BUILDERS[name]
|
|
201
245
|
end
|
|
202
246
|
|
|
247
|
+
def range_head_builder(name)
|
|
248
|
+
RANGE_HEAD_BUILDERS[name]
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# A Float-head range endpoint as a double: `nil` (absent) is `default`, an Integer literal
|
|
252
|
+
# coerces, a non-NaN Float stands, anything else declines with `nil`.
|
|
253
|
+
def float_range_endpoint(value, default)
|
|
254
|
+
case value
|
|
255
|
+
when nil then default
|
|
256
|
+
when Integer then value.to_f
|
|
257
|
+
when Float then value.nan? ? nil : value
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
203
261
|
def known?(name)
|
|
204
262
|
REGISTRY.key?(name.to_s) ||
|
|
205
263
|
PARAMETERISED_TYPE_BUILDERS.key?(name.to_s) ||
|
|
@@ -218,8 +276,10 @@ module Rigor
|
|
|
218
276
|
# parametric := simple_name '[' type_arg_list ']'
|
|
219
277
|
# | simple_name '<' int_bound_list '>'
|
|
220
278
|
# type_arg_list := type_arg (',' type_arg)*
|
|
221
|
-
# type_arg := type | class_name
|
|
279
|
+
# type_arg := range_literal | type | class_name
|
|
222
280
|
# class_name := /[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*/
|
|
281
|
+
# range_literal := endpoint? ('..' | '...') endpoint? (at least one side written)
|
|
282
|
+
# endpoint := signed_int | 'nil'
|
|
223
283
|
# int_bound_list := signed_int (',' signed_int)*
|
|
224
284
|
# signed_int := /-?\d+/
|
|
225
285
|
#
|
|
@@ -273,7 +333,16 @@ module Rigor
|
|
|
273
333
|
# delimiter.
|
|
274
334
|
SYMBOL_LITERAL = /:(?<value>[a-zA-Z_][a-zA-Z0-9_]*[?!=]?)/
|
|
275
335
|
STRING_LITERAL = /"(?<value>[^"\\]*)"/
|
|
276
|
-
|
|
336
|
+
# ADR-109 — a Ruby range literal at type-arg position, `1..10` / `1...10` / `1..` / `..10` /
|
|
337
|
+
# `nil..nil`, and for the Float head `0.0...1.0` / `1e-3..` / `-Float::INFINITY..Float::MAX`.
|
|
338
|
+
# Tried before the class-name and integer scans so `Float::INFINITY..` and `1..10` are not
|
|
339
|
+
# consumed as a class name or a bare integer; the operator is mandatory, so a bare integer or
|
|
340
|
+
# constant never matches. `..` with nothing on either side is not Ruby and is rejected after
|
|
341
|
+
# the match.
|
|
342
|
+
RANGE_ENDPOINT = /-?(?:\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|Float::INFINITY|Float::MAX)|nil/
|
|
343
|
+
RANGE_LITERAL = /(?<lo>#{RANGE_ENDPOINT})?\s*(?<op>\.\.\.?)\s*(?<hi>#{RANGE_ENDPOINT})?/
|
|
344
|
+
private_constant :SIMPLE_NAME, :CLASS_NAME, :SIGNED_INT, :SYMBOL_LITERAL, :STRING_LITERAL,
|
|
345
|
+
:RANGE_ENDPOINT, :RANGE_LITERAL
|
|
277
346
|
|
|
278
347
|
def parse_type_ast
|
|
279
348
|
if (class_name = @scanner.scan(CLASS_NAME))
|
|
@@ -381,7 +450,9 @@ module Rigor
|
|
|
381
450
|
end
|
|
382
451
|
|
|
383
452
|
def parse_single_type_arg_ast
|
|
384
|
-
if (
|
|
453
|
+
if (range = scan_range_literal)
|
|
454
|
+
range
|
|
455
|
+
elsif (class_name = @scanner.scan(CLASS_NAME))
|
|
385
456
|
parse_class_arg_tail_ast(class_name)
|
|
386
457
|
elsif (literal = @scanner.scan(SIGNED_INT))
|
|
387
458
|
TypeNode::IntegerLiteral.new(value: Integer(literal))
|
|
@@ -420,6 +491,36 @@ module Rigor
|
|
|
420
491
|
Integer(literal)
|
|
421
492
|
end
|
|
422
493
|
|
|
494
|
+
# Returns a {TypeNode::RangeLiteral} when the scanner sits on a Ruby range literal, `nil`
|
|
495
|
+
# (without consuming input) otherwise. `nil` and an absent endpoint both become Ruby's
|
|
496
|
+
# `nil` endpoint; the two spellings denote the same range.
|
|
497
|
+
def scan_range_literal
|
|
498
|
+
return nil unless @scanner.scan(RANGE_LITERAL)
|
|
499
|
+
|
|
500
|
+
lo = @scanner[:lo]
|
|
501
|
+
hi = @scanner[:hi]
|
|
502
|
+
return nil if lo.nil? && hi.nil?
|
|
503
|
+
|
|
504
|
+
TypeNode::RangeLiteral.new(
|
|
505
|
+
value: Range.new(range_endpoint(lo), range_endpoint(hi), @scanner[:op] == "...")
|
|
506
|
+
)
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
# The endpoint as the Ruby value the token denotes: an Integer literal stays an Integer (the
|
|
510
|
+
# `Integer` head needs to tell `1` from `1.0`), a Float literal or one of the four spelled
|
|
511
|
+
# constants becomes the double.
|
|
512
|
+
def range_endpoint(token)
|
|
513
|
+
case token
|
|
514
|
+
when nil, "nil" then nil
|
|
515
|
+
when "Float::INFINITY" then Float::INFINITY
|
|
516
|
+
when "-Float::INFINITY" then -Float::INFINITY
|
|
517
|
+
when "Float::MAX" then Float::MAX
|
|
518
|
+
when "-Float::MAX" then -Float::MAX
|
|
519
|
+
when /[.eE]/ then Float(token)
|
|
520
|
+
else Integer(token)
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
|
|
423
524
|
def skip_ws
|
|
424
525
|
@scanner.skip(/\s+/)
|
|
425
526
|
end
|
|
@@ -462,7 +563,7 @@ module Rigor
|
|
|
462
563
|
# `StringLiteral`) carries a Ruby value that lifts directly to a `Constant<value>`
|
|
463
564
|
# carrier through the same helper.
|
|
464
565
|
LITERAL_AST_NODES = [
|
|
465
|
-
TypeNode::IntegerLiteral, TypeNode::SymbolLiteral, TypeNode::StringLiteral
|
|
566
|
+
TypeNode::IntegerLiteral, TypeNode::SymbolLiteral, TypeNode::StringLiteral, TypeNode::RangeLiteral
|
|
466
567
|
].freeze
|
|
467
568
|
private_constant :LITERAL_AST_NODES
|
|
468
569
|
|
|
@@ -518,6 +619,11 @@ module Rigor
|
|
|
518
619
|
end
|
|
519
620
|
|
|
520
621
|
def resolve_generic(node)
|
|
622
|
+
# ADR-109 — `Integer[1..10]`. A range literal under a numeric head is that head's range
|
|
623
|
+
# refinement or nothing: an empty or malformed range declines here rather than falling
|
|
624
|
+
# through to a `Nominal[Integer, [Constant<Range>]]` the RBS fallback would otherwise build.
|
|
625
|
+
return resolve_range_head(node) if range_headed?(node)
|
|
626
|
+
|
|
521
627
|
builtin = try_builtin_parametric(node)
|
|
522
628
|
return builtin unless builtin.nil?
|
|
523
629
|
|
|
@@ -546,6 +652,19 @@ module Rigor
|
|
|
546
652
|
try_parametric_type_builder(node) || try_parametric_int_builder(node)
|
|
547
653
|
end
|
|
548
654
|
|
|
655
|
+
def range_headed?(node)
|
|
656
|
+
!ImportedRefinements.range_head_builder(node.head).nil? &&
|
|
657
|
+
node.args.any?(TypeNode::RangeLiteral)
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
# Exactly one range literal under the head; `Integer[1..10, 3]` is not a range refinement.
|
|
661
|
+
# Anything else under the same head (`Integer[Foo]`) keeps its pre-ADR-109 path.
|
|
662
|
+
def resolve_range_head(node)
|
|
663
|
+
return nil unless node.args.size == 1
|
|
664
|
+
|
|
665
|
+
ImportedRefinements.range_head_builder(node.head).call(node.args.first.value)
|
|
666
|
+
end
|
|
667
|
+
|
|
549
668
|
def try_parametric_type_builder(node)
|
|
550
669
|
builder = ImportedRefinements.parametric_type_builder(node.head)
|
|
551
670
|
return nil if builder.nil?
|
|
@@ -558,11 +677,14 @@ module Rigor
|
|
|
558
677
|
result
|
|
559
678
|
end
|
|
560
679
|
|
|
561
|
-
# ADR-13 slice 3b — record one `dynamic.shape.lossy-projection` event per (head,
|
|
562
|
-
#
|
|
563
|
-
#
|
|
564
|
-
# `
|
|
565
|
-
#
|
|
680
|
+
# ADR-13 slice 3b — record one `dynamic.shape.lossy-projection` event per (head, position) pair when
|
|
681
|
+
# the projection actually degraded. The builders return the source carrier unchanged on
|
|
682
|
+
# non-HashShape / non-Tuple receivers (see `Type::Combinator.pick_of` / `omit_of` and the
|
|
683
|
+
# HashShape-only `partial_of` / `required_of` / `readonly_of`), so detection is "first arg was lossy".
|
|
684
|
+
#
|
|
685
|
+
# Issue #805 — the `RBS::Location` is flattened to `(path, line, column)` here, at record time: the
|
|
686
|
+
# entry is drained out of every fork-pool worker, and a location survives neither the drain's
|
|
687
|
+
# `Marshal.dump` nor its cross-worker dedup (see {Rigor::RbsExtended::Reporter}).
|
|
566
688
|
def record_lossy_projection_if_applicable(node, args, result)
|
|
567
689
|
return if @reporter.nil?
|
|
568
690
|
return if result.nil?
|
|
@@ -570,10 +692,8 @@ module Rigor
|
|
|
570
692
|
return if args.empty?
|
|
571
693
|
return unless Type::Combinator.shape_projection_lossy?(args.first)
|
|
572
694
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
source_location: @source_location
|
|
576
|
-
)
|
|
695
|
+
path, line, column = RbsExtended::Reporter.position_of(@source_location)
|
|
696
|
+
@reporter.record_lossy_projection(head: node.head, path: path, line: line, column: column)
|
|
577
697
|
end
|
|
578
698
|
|
|
579
699
|
def try_parametric_int_builder(node)
|
|
@@ -583,7 +703,23 @@ module Rigor
|
|
|
583
703
|
bounds = node.args.map { |a| a.is_a?(TypeNode::IntegerLiteral) ? a.value : nil }
|
|
584
704
|
return nil if bounds.any?(&:nil?)
|
|
585
705
|
|
|
586
|
-
builder.call(bounds)
|
|
706
|
+
result = builder.call(bounds)
|
|
707
|
+
record_deprecated_form(node, bounds, result) unless result.nil?
|
|
708
|
+
result
|
|
709
|
+
end
|
|
710
|
+
|
|
711
|
+
# ADR-109 WD3 — the angle-bracket form still resolves, and the run says so once per annotation with
|
|
712
|
+
# the spelling the same type now displays as. Recorded only when the payload resolved: an
|
|
713
|
+
# unresolvable one already surfaces as `dynamic.rbs-extended.unresolved`, and a second row for it
|
|
714
|
+
# would name a replacement for something that never parsed.
|
|
715
|
+
def record_deprecated_form(node, bounds, result)
|
|
716
|
+
return if @reporter.nil?
|
|
717
|
+
|
|
718
|
+
path, line, column = RbsExtended::Reporter.position_of(@source_location)
|
|
719
|
+
@reporter.record_deprecated_form(
|
|
720
|
+
payload: "#{node.head}<#{bounds.join(', ')}>", replacement: result.describe,
|
|
721
|
+
path: path, line: line, column: column
|
|
722
|
+
)
|
|
587
723
|
end
|
|
588
724
|
|
|
589
725
|
def resolve_args(args)
|
|
@@ -117,8 +117,7 @@ module Rigor
|
|
|
117
117
|
|
|
118
118
|
# --- private ------------------------------------------------------
|
|
119
119
|
|
|
120
|
-
# @param value
|
|
121
|
-
# @return [Rigor::Type]
|
|
120
|
+
# @param value — a non-empty string
|
|
122
121
|
def self.classify_string(value)
|
|
123
122
|
if Type::Refined.ruby_numeric_literal?(value)
|
|
124
123
|
NUMERIC_STRING
|
|
@@ -133,8 +132,7 @@ module Rigor
|
|
|
133
132
|
# Called ONLY with the names in {RUNTIME_STRING_CONSTANTS} — Rigor's own source — and only
|
|
134
133
|
# while this file is being loaded. It is never handed a name from the analysed program.
|
|
135
134
|
#
|
|
136
|
-
# @param name
|
|
137
|
-
# @return [String, nil]
|
|
135
|
+
# @param name — a qualified constant path without a leading "::"
|
|
138
136
|
def self.runtime_string_value(name)
|
|
139
137
|
mod = ::Object
|
|
140
138
|
name.split("::").each do |part|
|
|
@@ -161,7 +159,7 @@ module Rigor
|
|
|
161
159
|
end
|
|
162
160
|
private_class_method :runtime_string_value
|
|
163
161
|
|
|
164
|
-
# @return
|
|
162
|
+
# @return frozen, built once at load time.
|
|
165
163
|
def self.build_runtime_string_refinements
|
|
166
164
|
RUNTIME_STRING_CONSTANTS.each_with_object({}) do |name, table|
|
|
167
165
|
value = runtime_string_value(name)
|
|
@@ -175,9 +173,9 @@ module Rigor
|
|
|
175
173
|
|
|
176
174
|
# --- public API ---------------------------------------------------
|
|
177
175
|
|
|
178
|
-
# @param name
|
|
176
|
+
# @param name — unqualified constant name (e.g. `"Math::PI"`,
|
|
179
177
|
# `"RUBY_VERSION"`, `"Ruby::ENGINE"`)
|
|
180
|
-
# @return
|
|
178
|
+
# @return refined type, or nil to fall through
|
|
181
179
|
def self.lookup(name)
|
|
182
180
|
FOLDED_CONSTANTS[name] || RUNTIME_STRING_REFINEMENTS[name]
|
|
183
181
|
end
|
|
@@ -62,11 +62,11 @@ module Rigor
|
|
|
62
62
|
|
|
63
63
|
module_function
|
|
64
64
|
|
|
65
|
-
# @param body
|
|
65
|
+
# @param body — a regex sub-pattern, typically the inner body of a
|
|
66
66
|
# `(?<name>body)` named capture. Anchors (`\A`, `\z`, `^`, `$`) are not stripped — the
|
|
67
67
|
# recogniser table targets bodies that the regex engine treats as anchored to the
|
|
68
68
|
# capture group bounds.
|
|
69
|
-
# @return
|
|
69
|
+
# @return the matching imported refinement carrier, or `nil` if
|
|
70
70
|
# `body` is not a recognised shape.
|
|
71
71
|
def for_capture_body(body)
|
|
72
72
|
return nil if body.nil? || body.empty?
|
|
@@ -100,8 +100,8 @@ module Rigor
|
|
|
100
100
|
# free-whitespace/`#`-comment flag from the `source` alone, so consumers bail on it before
|
|
101
101
|
# calling here.
|
|
102
102
|
#
|
|
103
|
-
# @param source
|
|
104
|
-
# @return
|
|
103
|
+
# @param source — the full regex source string.
|
|
104
|
+
# @return the matching imported refinement carrier, or `nil`.
|
|
105
105
|
def for_whole_pattern(source)
|
|
106
106
|
return nil if source.nil?
|
|
107
107
|
return nil unless source.start_with?('\A') && source.end_with?('\z')
|
|
@@ -97,16 +97,15 @@ module Rigor
|
|
|
97
97
|
|
|
98
98
|
# Looks up a refined return type for the given call.
|
|
99
99
|
#
|
|
100
|
-
# @param owner_class_name
|
|
100
|
+
# @param owner_class_name — the class on which the method is defined
|
|
101
101
|
# (e.g., `"Kernel"`). Pass `nil` when the caller hasn't resolved a defining owner
|
|
102
102
|
# yet — the lookup will then fall back to matching by `(method_name, kind)` against
|
|
103
103
|
# entries whose owner is currently in the table.
|
|
104
|
-
# @param
|
|
105
|
-
# @param kind [Symbol] one of `:singleton`, `:instance`. The caller passes the shape of
|
|
104
|
+
# @param kind — one of `:singleton`, `:instance`. The caller passes the shape of
|
|
106
105
|
# the actual call site; the table stores `:both` for entries that match either.
|
|
107
|
-
# @param arg_types
|
|
106
|
+
# @param arg_types — positional argument types. Forwarded to the
|
|
108
107
|
# handler so future entries can discriminate on argument shape.
|
|
109
|
-
# @return
|
|
108
|
+
# @return the refined return type, or `nil` when no override
|
|
110
109
|
# matches.
|
|
111
110
|
def self.lookup(owner_class_name:, method_name:, kind:, arg_types: [])
|
|
112
111
|
return nil if owner_class_name.nil?
|
|
@@ -127,7 +126,7 @@ module Rigor
|
|
|
127
126
|
end.freeze
|
|
128
127
|
private_constant :OWNERS_BY_METHOD
|
|
129
128
|
|
|
130
|
-
# @return
|
|
129
|
+
# @return the candidate owner class names for a bare method-name
|
|
131
130
|
# lookup. Empty when no override names this method.
|
|
132
131
|
NO_OWNERS = [].freeze
|
|
133
132
|
private_constant :NO_OWNERS
|