rigortype 0.2.7 → 0.2.8
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/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/15-type-protection-coverage.md +6 -4
- data/lib/rigor/analysis/baseline.rb +56 -96
- data/lib/rigor/analysis/buffer_binding.rb +13 -20
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
- data/lib/rigor/analysis/check_rules.rb +174 -274
- data/lib/rigor/analysis/dependency_recorder.rb +26 -38
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
- data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
- data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
- data/lib/rigor/analysis/diagnostic.rb +48 -75
- data/lib/rigor/analysis/erb_template_detector.rb +13 -18
- data/lib/rigor/analysis/fact_store.rb +12 -22
- data/lib/rigor/analysis/incremental.rb +47 -63
- data/lib/rigor/analysis/incremental_session.rb +74 -100
- data/lib/rigor/analysis/project_scan.rb +12 -23
- data/lib/rigor/analysis/result.rb +3 -5
- data/lib/rigor/analysis/rule_catalog.rb +67 -95
- data/lib/rigor/analysis/run_stats.rb +38 -61
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
- data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
- data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
- data/lib/rigor/analysis/runner.rb +220 -333
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
- data/lib/rigor/analysis/worker_session.rb +64 -102
- data/lib/rigor/ast/type_node.rb +6 -8
- data/lib/rigor/ast.rb +6 -10
- data/lib/rigor/bleeding_edge.rb +27 -35
- data/lib/rigor/builtins/hkt_builtins.rb +7 -14
- data/lib/rigor/builtins/imported_refinements.rb +106 -149
- data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
- data/lib/rigor/builtins/regex_refinement.rb +32 -43
- data/lib/rigor/builtins/static_return_refinements.rb +57 -81
- data/lib/rigor/cache/descriptor.rb +58 -94
- data/lib/rigor/cache/incremental_snapshot.rb +32 -48
- data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
- data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
- data/lib/rigor/cache/rbs_constant_table.rb +8 -13
- data/lib/rigor/cache/rbs_descriptor.rb +8 -13
- data/lib/rigor/cache/rbs_environment.rb +11 -19
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
- data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
- data/lib/rigor/cache/store.rb +96 -151
- data/lib/rigor/cli/annotate_command.rb +51 -88
- data/lib/rigor/cli/baseline_command.rb +10 -17
- data/lib/rigor/cli/check_command.rb +121 -199
- data/lib/rigor/cli/check_runner_factory.rb +8 -14
- data/lib/rigor/cli/ci_detector.rb +9 -14
- data/lib/rigor/cli/command.rb +8 -14
- data/lib/rigor/cli/coverage_command.rb +19 -26
- data/lib/rigor/cli/coverage_mutation.rb +14 -19
- data/lib/rigor/cli/coverage_report.rb +0 -2
- data/lib/rigor/cli/coverage_scan.rb +7 -11
- data/lib/rigor/cli/diagnostic_formats.rb +43 -62
- data/lib/rigor/cli/diff_command.rb +10 -20
- data/lib/rigor/cli/docs_command.rb +26 -40
- data/lib/rigor/cli/doctor_command.rb +8 -9
- data/lib/rigor/cli/explain_command.rb +4 -7
- data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
- data/lib/rigor/cli/fused_protection_report.rb +6 -8
- data/lib/rigor/cli/lsp_command.rb +11 -19
- data/lib/rigor/cli/mcp_command.rb +4 -6
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
- data/lib/rigor/cli/mutation_protection_report.rb +6 -9
- data/lib/rigor/cli/options.rb +11 -19
- data/lib/rigor/cli/plugin_command.rb +18 -30
- data/lib/rigor/cli/plugins_command.rb +29 -51
- data/lib/rigor/cli/plugins_renderer.rb +12 -20
- data/lib/rigor/cli/prism_colorizer.rb +13 -19
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +27 -17
- data/lib/rigor/cli/renderable.rb +4 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
- data/lib/rigor/cli/sig_gen_command.rb +14 -26
- data/lib/rigor/cli/skill_command.rb +30 -47
- data/lib/rigor/cli/skill_describe.rb +40 -64
- data/lib/rigor/cli/trace_command.rb +9 -16
- data/lib/rigor/cli/trace_renderer.rb +35 -51
- data/lib/rigor/cli/triage_command.rb +6 -10
- data/lib/rigor/cli/triage_renderer.rb +1 -2
- data/lib/rigor/cli/type_of_command.rb +14 -23
- data/lib/rigor/cli/type_of_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_command.rb +6 -10
- data/lib/rigor/cli/type_scan_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_report.rb +2 -3
- data/lib/rigor/cli/upgrade_command.rb +2 -3
- data/lib/rigor/cli.rb +16 -28
- data/lib/rigor/config_audit.rb +35 -44
- data/lib/rigor/configuration/dependencies.rb +41 -70
- data/lib/rigor/configuration/severity_profile.rb +28 -42
- data/lib/rigor/configuration.rb +150 -241
- data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
- data/lib/rigor/environment/class_registry.rb +19 -26
- data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
- data/lib/rigor/environment/lockfile_resolver.rb +31 -47
- data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
- data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
- data/lib/rigor/environment/rbs_loader.rb +420 -518
- data/lib/rigor/environment/reflection.rb +28 -53
- data/lib/rigor/environment/reporters.rb +13 -24
- data/lib/rigor/environment.rb +176 -291
- data/lib/rigor/flow_contribution/conflict.rb +16 -27
- data/lib/rigor/flow_contribution/element.rb +7 -12
- data/lib/rigor/flow_contribution/fact.rb +33 -57
- data/lib/rigor/flow_contribution/merge_result.rb +6 -9
- data/lib/rigor/flow_contribution/merger.rb +32 -47
- data/lib/rigor/flow_contribution.rb +37 -55
- data/lib/rigor/inference/acceptance.rb +133 -219
- data/lib/rigor/inference/block_parameter_binder.rb +52 -82
- data/lib/rigor/inference/body_fixpoint.rb +22 -30
- data/lib/rigor/inference/budget_trace.rb +43 -63
- data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
- data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
- data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
- data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
- data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
- data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
- data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
- data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
- data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
- data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
- data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
- data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
- data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
- data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
- data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
- data/lib/rigor/inference/coverage_scanner.rb +13 -18
- data/lib/rigor/inference/def_return_typer.rb +8 -14
- data/lib/rigor/inference/dynamic_origin.rb +23 -20
- data/lib/rigor/inference/expression_typer.rb +774 -1152
- data/lib/rigor/inference/fallback.rb +8 -12
- data/lib/rigor/inference/fallback_tracer.rb +4 -10
- data/lib/rigor/inference/flow_tracer.rb +25 -36
- data/lib/rigor/inference/hkt_body.rb +45 -68
- data/lib/rigor/inference/hkt_body_parser.rb +33 -52
- data/lib/rigor/inference/hkt_reducer.rb +38 -59
- data/lib/rigor/inference/hkt_registry.rb +50 -76
- data/lib/rigor/inference/indexed_narrowing.rb +55 -81
- data/lib/rigor/inference/macro_block_self_type.rb +21 -34
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
- data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
- data/lib/rigor/inference/method_dispatcher.rb +378 -524
- data/lib/rigor/inference/method_parameter_binder.rb +81 -114
- data/lib/rigor/inference/multi_target_binder.rb +51 -68
- data/lib/rigor/inference/mutation_widening.rb +115 -158
- data/lib/rigor/inference/narrowing.rb +509 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
- data/lib/rigor/inference/precision_scanner.rb +26 -35
- data/lib/rigor/inference/project_patched_methods.rb +20 -32
- data/lib/rigor/inference/project_patched_scanner.rb +23 -37
- data/lib/rigor/inference/protection_scanner.rb +16 -18
- data/lib/rigor/inference/rbs_type_translator.rb +49 -66
- data/lib/rigor/inference/scope_indexer.rb +473 -817
- data/lib/rigor/inference/statement_evaluator.rb +706 -1111
- data/lib/rigor/inference/struct_fold_safety.rb +34 -48
- data/lib/rigor/inference/synthetic_method.rb +9 -16
- data/lib/rigor/inference/synthetic_method_index.rb +20 -35
- data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
- data/lib/rigor/language_server/buffer_resolution.rb +6 -9
- data/lib/rigor/language_server/buffer_table.rb +11 -18
- data/lib/rigor/language_server/completion_provider.rb +69 -116
- data/lib/rigor/language_server/debouncer.rb +16 -25
- data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
- data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
- data/lib/rigor/language_server/folding_range_provider.rb +11 -19
- data/lib/rigor/language_server/hover_provider.rb +8 -11
- data/lib/rigor/language_server/hover_renderer.rb +56 -93
- data/lib/rigor/language_server/loop.rb +14 -19
- data/lib/rigor/language_server/project_context.rb +46 -74
- data/lib/rigor/language_server/selection_range_provider.rb +9 -12
- data/lib/rigor/language_server/server.rb +55 -83
- data/lib/rigor/language_server/signature_help_provider.rb +29 -46
- data/lib/rigor/language_server/synchronized_writer.rb +4 -7
- data/lib/rigor/language_server/uri.rb +8 -13
- data/lib/rigor/language_server.rb +4 -6
- data/lib/rigor/mcp/loop.rb +2 -3
- data/lib/rigor/mcp/server.rb +4 -7
- data/lib/rigor/mcp.rb +3 -6
- data/lib/rigor/plugin/access_denied_error.rb +5 -8
- data/lib/rigor/plugin/additional_initializer.rb +21 -31
- data/lib/rigor/plugin/base.rb +335 -518
- data/lib/rigor/plugin/blueprint.rb +14 -23
- data/lib/rigor/plugin/box.rb +18 -29
- data/lib/rigor/plugin/fact_store.rb +16 -26
- data/lib/rigor/plugin/inflector.rb +37 -53
- data/lib/rigor/plugin/io_boundary.rb +33 -56
- data/lib/rigor/plugin/isolation.rb +42 -55
- data/lib/rigor/plugin/load_error.rb +10 -15
- data/lib/rigor/plugin/loader.rb +30 -49
- data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
- data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
- data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
- data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
- data/lib/rigor/plugin/macro.rb +10 -15
- data/lib/rigor/plugin/manifest.rb +85 -144
- data/lib/rigor/plugin/node_context.rb +14 -22
- data/lib/rigor/plugin/node_rule_walk.rb +49 -74
- data/lib/rigor/plugin/protocol_contract.rb +25 -39
- data/lib/rigor/plugin/registry.rb +132 -205
- data/lib/rigor/plugin/services.rb +21 -33
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
- data/lib/rigor/plugin/trust_policy.rb +24 -38
- data/lib/rigor/plugin/type_node_resolver.rb +15 -24
- data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
- data/lib/rigor/protection/mutation_scanner.rb +27 -35
- data/lib/rigor/protection/mutator.rb +50 -70
- data/lib/rigor/protection/test_suite_oracle.rb +20 -27
- data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
- data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
- data/lib/rigor/rbs_extended/reporter.rb +24 -40
- data/lib/rigor/rbs_extended.rb +107 -197
- data/lib/rigor/reflection.rb +68 -86
- data/lib/rigor/scope/discovery_index.rb +14 -19
- data/lib/rigor/scope.rb +255 -310
- data/lib/rigor/sig_gen/classification.rb +6 -10
- data/lib/rigor/sig_gen/generator.rb +197 -323
- data/lib/rigor/sig_gen/layout_index.rb +12 -20
- data/lib/rigor/sig_gen/method_candidate.rb +12 -17
- data/lib/rigor/sig_gen/observation_collector.rb +38 -70
- data/lib/rigor/sig_gen/observed_call.rb +13 -23
- data/lib/rigor/sig_gen/path_mapper.rb +17 -29
- data/lib/rigor/sig_gen/renderer.rb +7 -13
- data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
- data/lib/rigor/sig_gen/write_result.rb +8 -16
- data/lib/rigor/sig_gen/writer.rb +95 -174
- data/lib/rigor/sig_gen.rb +3 -6
- data/lib/rigor/signature_path_audit.rb +24 -30
- data/lib/rigor/source/constant_path.rb +10 -14
- data/lib/rigor/source/literals.rb +31 -45
- data/lib/rigor/source/node_locator.rb +9 -11
- data/lib/rigor/source/node_walker.rb +9 -13
- data/lib/rigor/source.rb +3 -4
- data/lib/rigor/testing.rb +16 -20
- data/lib/rigor/triage/catalogue.rb +38 -62
- data/lib/rigor/triage.rb +31 -52
- data/lib/rigor/trinary.rb +9 -13
- data/lib/rigor/type/acceptance_router.rb +4 -6
- data/lib/rigor/type/accepts_result.rb +10 -14
- data/lib/rigor/type/app.rb +19 -27
- data/lib/rigor/type/bot.rb +4 -6
- data/lib/rigor/type/bound_method.rb +10 -15
- data/lib/rigor/type/combinator.rb +165 -257
- data/lib/rigor/type/constant.rb +23 -34
- data/lib/rigor/type/data_class.rb +10 -15
- data/lib/rigor/type/data_instance.rb +14 -20
- data/lib/rigor/type/difference.rb +21 -32
- data/lib/rigor/type/dynamic.rb +3 -5
- data/lib/rigor/type/hash_shape.rb +32 -18
- data/lib/rigor/type/integer_range.rb +11 -16
- data/lib/rigor/type/intersection.rb +27 -42
- data/lib/rigor/type/nominal.rb +10 -15
- data/lib/rigor/type/plain_lattice.rb +9 -13
- data/lib/rigor/type/refined.rb +67 -114
- data/lib/rigor/type/singleton.rb +4 -6
- data/lib/rigor/type/struct_class.rb +11 -16
- data/lib/rigor/type/struct_instance.rb +15 -21
- data/lib/rigor/type/tuple.rb +14 -19
- data/lib/rigor/type/union.rb +30 -42
- data/lib/rigor/type_node/generic.rb +14 -26
- data/lib/rigor/type_node/identifier.rb +12 -19
- data/lib/rigor/type_node.rb +3 -12
- data/lib/rigor/value_semantics.rb +16 -21
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
- data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
- data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
- data/sig/rigor/scope.rbs +6 -0
- metadata +2 -1
|
@@ -1207,15 +1207,12 @@ module Rigor
|
|
|
1207
1207
|
build_undefined_method_diagnostic(path, call_node, receiver_type)
|
|
1208
1208
|
end
|
|
1209
1209
|
|
|
1210
|
-
# An arm that makes a sound "undefined on every arm" verdict
|
|
1211
|
-
#
|
|
1212
|
-
# (
|
|
1213
|
-
#
|
|
1214
|
-
#
|
|
1215
|
-
#
|
|
1216
|
-
# `.manifest`), an unbounded receiver (ADR-26 open class or a synthesized
|
|
1217
|
-
# stub), or a module mixin whose Object-inherited methods the per-arm
|
|
1218
|
-
# lookup would miss.
|
|
1210
|
+
# An arm that makes a sound "undefined on every arm" verdict impossible: a non-class surface
|
|
1211
|
+
# (Dynamic / Top / Bot), a singleton (slice 1 reasons about instance arms only), the generic
|
|
1212
|
+
# metaclass `Class` / `Module` (a value typed as one is *some* class/module object whose singleton
|
|
1213
|
+
# methods cannot be enumerated from the metaclass — e.g. `plugin_class : Class` really holds a
|
|
1214
|
+
# `Plugin` subclass with `.manifest`), an unbounded receiver (ADR-26 open class or a synthesized
|
|
1215
|
+
# stub), or a module mixin whose Object-inherited methods the per-arm lookup would miss.
|
|
1219
1216
|
METACLASS_ARMS = %w[Class Module].to_set.freeze
|
|
1220
1217
|
private_constant :METACLASS_ARMS
|
|
1221
1218
|
|
|
@@ -1229,15 +1226,11 @@ module Rigor
|
|
|
1229
1226
|
module_mixin_receiver?(member, scope)
|
|
1230
1227
|
end
|
|
1231
1228
|
|
|
1232
|
-
# Slice 7 phase 19 — PHPStan-style `dump_type(value)`.
|
|
1233
|
-
#
|
|
1234
|
-
#
|
|
1235
|
-
#
|
|
1236
|
-
#
|
|
1237
|
-
# showing the inferred type of the argument expression.
|
|
1238
|
-
# The diagnostic does NOT count toward `Result#error_count`
|
|
1239
|
-
# so a fixture peppered with `dump_type` calls still
|
|
1240
|
-
# passes `rigor check`.
|
|
1229
|
+
# Slice 7 phase 19 — PHPStan-style `dump_type(value)`. When the engine recognises a call to
|
|
1230
|
+
# `dump_type` (with any of the supported receiver shapes — implicit self after `include
|
|
1231
|
+
# Rigor::Testing`, `Rigor::Testing.dump_type`, or `Rigor.dump_type`), it emits an `:info` diagnostic
|
|
1232
|
+
# showing the inferred type of the argument expression. The diagnostic does NOT count toward
|
|
1233
|
+
# `Result#error_count` so a fixture peppered with `dump_type` calls still passes `rigor check`.
|
|
1241
1234
|
def dump_type_diagnostic(path, call_node, scope_index)
|
|
1242
1235
|
return nil unless rigor_testing_call?(call_node, :dump_type)
|
|
1243
1236
|
return nil if call_node.arguments.nil? || call_node.arguments.arguments.empty?
|
|
@@ -1257,14 +1250,11 @@ module Rigor
|
|
|
1257
1250
|
)
|
|
1258
1251
|
end
|
|
1259
1252
|
|
|
1260
|
-
# Slice 7 phase 19 — PHPStan-style `assert_type("...", value)`.
|
|
1261
|
-
#
|
|
1262
|
-
# the expected
|
|
1263
|
-
#
|
|
1264
|
-
#
|
|
1265
|
-
# is emitted; matching calls produce no output. This
|
|
1266
|
-
# lets a fixture document its expected types inline:
|
|
1267
|
-
# subsequent `rigor check` runs flag any drift.
|
|
1253
|
+
# Slice 7 phase 19 — PHPStan-style `assert_type("...", value)`. The first argument MUST be a
|
|
1254
|
+
# string literal containing the expected `Type#describe(:short)` rendering. When the inferred
|
|
1255
|
+
# type's short description does not equal the expected literal, an `:error`-severity diagnostic is
|
|
1256
|
+
# emitted; matching calls produce no output. This lets a fixture document its expected types
|
|
1257
|
+
# inline: subsequent `rigor check` runs flag any drift.
|
|
1268
1258
|
def assert_type_diagnostic(path, call_node, scope_index)
|
|
1269
1259
|
return nil unless rigor_testing_call?(call_node, :assert_type)
|
|
1270
1260
|
return nil if call_node.arguments.nil? || call_node.arguments.arguments.size < 2
|
|
@@ -1289,21 +1279,16 @@ module Rigor
|
|
|
1289
1279
|
# `Testing.dump_type(x)`
|
|
1290
1280
|
# `Rigor.dump_type(x)`
|
|
1291
1281
|
# `Rigor::Testing.dump_type(x)`
|
|
1292
|
-
# The receiver check is purely structural — we do not
|
|
1293
|
-
#
|
|
1294
|
-
#
|
|
1295
|
-
# clash is the deliberate trade-off for ergonomic
|
|
1296
|
-
# invocation.
|
|
1282
|
+
# The receiver check is purely structural — we do not consult RBS — because the helpers are no-op
|
|
1283
|
+
# stubs the user MAY shadow with their own definition; a name clash is the deliberate trade-off for
|
|
1284
|
+
# ergonomic invocation.
|
|
1297
1285
|
RIGOR_TESTING_RECEIVERS = ["Rigor", "Rigor::Testing", "Testing"].freeze
|
|
1298
1286
|
private_constant :RIGOR_TESTING_RECEIVERS
|
|
1299
1287
|
|
|
1300
|
-
# The dump/assert helpers' own implementation methods
|
|
1301
|
-
#
|
|
1302
|
-
#
|
|
1303
|
-
#
|
|
1304
|
-
# reflexive plumbing, not user assertions. This filter
|
|
1305
|
-
# skips diagnostics when the call site's `self_type` is
|
|
1306
|
-
# the `Rigor` or `Rigor::Testing` module itself.
|
|
1288
|
+
# The dump/assert helpers' own implementation methods call back into `Testing.dump_type` /
|
|
1289
|
+
# `assert_type` to share the no-op runtime stub. We do NOT want those internal calls to surface
|
|
1290
|
+
# diagnostics — they are reflexive plumbing, not user assertions. This filter skips diagnostics
|
|
1291
|
+
# when the call site's `self_type` is the `Rigor` or `Rigor::Testing` module itself.
|
|
1307
1292
|
SELF_REFERENTIAL_SCOPES = ["Rigor", "Rigor::Testing"].freeze
|
|
1308
1293
|
private_constant :SELF_REFERENTIAL_SCOPES
|
|
1309
1294
|
|
|
@@ -1348,20 +1333,17 @@ module Rigor
|
|
|
1348
1333
|
)
|
|
1349
1334
|
end
|
|
1350
1335
|
|
|
1351
|
-
# Diagnoses calls that the analyzer can prove will always
|
|
1352
|
-
#
|
|
1353
|
-
# division/modulo by a literal zero divisor:
|
|
1336
|
+
# Diagnoses calls that the analyzer can prove will always raise. Today the only triggering shape is
|
|
1337
|
+
# integer division/modulo by a literal zero divisor:
|
|
1354
1338
|
#
|
|
1355
1339
|
# 5 / 0 # => ZeroDivisionError
|
|
1356
1340
|
# x.modulo(0) # => ZeroDivisionError when x: Integer
|
|
1357
1341
|
# xs.size % 0 # same — non_negative_int / Constant[0]
|
|
1358
1342
|
#
|
|
1359
|
-
# Float divmod by zero returns Infinity/NaN at runtime, so
|
|
1360
|
-
#
|
|
1361
|
-
# `
|
|
1362
|
-
#
|
|
1363
|
-
# `Union[Constant[0], Constant[2]]` divisor "may" raise,
|
|
1364
|
-
# which we surface separately (future slice).
|
|
1343
|
+
# Float divmod by zero returns Infinity/NaN at runtime, so the rule restricts to Integer-rooted
|
|
1344
|
+
# receivers (`Constant`, `IntegerRange`, `Nominal[Integer]`). The argument MUST be a
|
|
1345
|
+
# `Constant<Integer>` whose value is exactly zero — a `Union[Constant[0], Constant[2]]` divisor
|
|
1346
|
+
# "may" raise, which we surface separately (future slice).
|
|
1365
1347
|
INTEGER_RAISING_OPERATORS = %i[/ % div modulo divmod].freeze
|
|
1366
1348
|
private_constant :INTEGER_RAISING_OPERATORS
|
|
1367
1349
|
|
|
@@ -1414,41 +1396,27 @@ module Rigor
|
|
|
1414
1396
|
)
|
|
1415
1397
|
end
|
|
1416
1398
|
|
|
1417
|
-
# v0.1.2 — `flow.unreachable-branch`. Fires when an
|
|
1418
|
-
# `
|
|
1419
|
-
#
|
|
1420
|
-
#
|
|
1421
|
-
# at-a-glance) has an observable dead branch. The
|
|
1422
|
-
# diagnostic points at the dead branch (not the
|
|
1423
|
-
# predicate) so the squiggle lands on the code that
|
|
1424
|
-
# never runs.
|
|
1399
|
+
# v0.1.2 — `flow.unreachable-branch`. Fires when an `IfNode` / `UnlessNode` whose predicate is a
|
|
1400
|
+
# literal `true` / `false` / `nil` (or a literal numeric / string / symbol whose Ruby truthiness is
|
|
1401
|
+
# known at-a-glance) has an observable dead branch. The diagnostic points at the dead branch (not
|
|
1402
|
+
# the predicate) so the squiggle lands on the code that never runs.
|
|
1425
1403
|
#
|
|
1426
1404
|
# Conservative envelope — by deliberate v0.1.2 design:
|
|
1427
|
-
# - Only **literal-shaped** predicates fire. Inferred-
|
|
1428
|
-
#
|
|
1429
|
-
#
|
|
1430
|
-
#
|
|
1431
|
-
#
|
|
1432
|
-
#
|
|
1433
|
-
#
|
|
1434
|
-
#
|
|
1435
|
-
#
|
|
1436
|
-
#
|
|
1437
|
-
#
|
|
1438
|
-
#
|
|
1439
|
-
# body) are skipped — there is no useful location to
|
|
1440
|
-
# point at.
|
|
1441
|
-
# - Postfix-`if` / `unless` modifiers with a literal
|
|
1442
|
-
# predicate ARE flagged (`expr if false` body never
|
|
1443
|
-
# runs, exactly like the block form).
|
|
1444
|
-
# - Elsif chains (`subsequent` is itself an `IfNode`)
|
|
1445
|
-
# ARE flagged — the entire downstream chain is
|
|
1446
|
-
# unreachable when the outer predicate is a constant
|
|
1447
|
-
# literal.
|
|
1405
|
+
# - Only **literal-shaped** predicates fire. Inferred-constant predicates (`x.method?` that happens
|
|
1406
|
+
# to fold to `Constant<bool>`) are intentionally skipped — Rigor's loop / mutation /
|
|
1407
|
+
# RBS-strictness modelling is incomplete enough that an inferred constant can be a false positive
|
|
1408
|
+
# (e.g. accumulator `arr << x` doesn't widen the carrier; defensive `module.name.nil?` checks
|
|
1409
|
+
# against anonymous-class nil that the RBS `Module#name -> String` sig hides). The literal-only
|
|
1410
|
+
# envelope captures the clear "user wrote `if false`" case without false alarms.
|
|
1411
|
+
# - Empty dead branches (e.g. `if false; end` with no body) are skipped — there is no useful
|
|
1412
|
+
# location to point at.
|
|
1413
|
+
# - Postfix-`if` / `unless` modifiers with a literal predicate ARE flagged (`expr if false` body
|
|
1414
|
+
# never runs, exactly like the block form).
|
|
1415
|
+
# - Elsif chains (`subsequent` is itself an `IfNode`) ARE flagged — the entire downstream chain is
|
|
1416
|
+
# unreachable when the outer predicate is a constant literal.
|
|
1448
1417
|
#
|
|
1449
|
-
# Broadening to inferred-constant predicates is queued
|
|
1450
|
-
#
|
|
1451
|
-
# gaps named above are closed.
|
|
1418
|
+
# Broadening to inferred-constant predicates is queued for a later v0.1.x release once the loop /
|
|
1419
|
+
# mutation gaps named above are closed.
|
|
1452
1420
|
def unreachable_branch_diagnostic(path, node, scope_index)
|
|
1453
1421
|
scope = scope_index[node]
|
|
1454
1422
|
return nil if scope.nil?
|
|
@@ -1462,12 +1430,9 @@ module Rigor
|
|
|
1462
1430
|
build_unreachable_branch_diagnostic(path, dead_branch, polarity)
|
|
1463
1431
|
end
|
|
1464
1432
|
|
|
1465
|
-
# Returns `:truthy` / `:falsey` for a syntactically-
|
|
1466
|
-
#
|
|
1467
|
-
# `
|
|
1468
|
-
# unambiguous cases. Numeric / string / symbol literals
|
|
1469
|
-
# are always truthy in Ruby (any non-`false` / non-`nil`
|
|
1470
|
-
# value is truthy, including `0` and `""`).
|
|
1433
|
+
# Returns `:truthy` / `:falsey` for a syntactically-literal predicate, or nil for anything else.
|
|
1434
|
+
# `TrueNode`, `FalseNode`, `NilNode` are the unambiguous cases. Numeric / string / symbol literals
|
|
1435
|
+
# are always truthy in Ruby (any non-`false` / non-`nil` value is truthy, including `0` and `""`).
|
|
1471
1436
|
TRUTHY_LITERAL_NODES = [
|
|
1472
1437
|
Prism::TrueNode, Prism::IntegerNode, Prism::FloatNode,
|
|
1473
1438
|
Prism::StringNode, Prism::SymbolNode, Prism::RegularExpressionNode
|
|
@@ -1484,26 +1449,19 @@ module Rigor
|
|
|
1484
1449
|
nil
|
|
1485
1450
|
end
|
|
1486
1451
|
|
|
1487
|
-
# v0.1.2 — `def.method-visibility-mismatch`. Fires when
|
|
1488
|
-
#
|
|
1489
|
-
#
|
|
1490
|
-
# entry is `:private`. The rule is intentionally narrow:
|
|
1452
|
+
# v0.1.2 — `def.method-visibility-mismatch`. Fires when an explicit-receiver `Prism::CallNode`
|
|
1453
|
+
# targets a user-class method whose `discovered_method_visibilities` entry is `:private`. The rule
|
|
1454
|
+
# is intentionally narrow:
|
|
1491
1455
|
#
|
|
1492
|
-
# - Only `:private`. `:protected` access depends on
|
|
1493
|
-
#
|
|
1494
|
-
#
|
|
1495
|
-
#
|
|
1496
|
-
#
|
|
1497
|
-
#
|
|
1498
|
-
#
|
|
1499
|
-
#
|
|
1500
|
-
#
|
|
1501
|
-
# private). Calls whose receiver is `Prism::SelfNode`
|
|
1502
|
-
# are also skipped — Ruby 2.7+ permits `self.foo` for
|
|
1503
|
-
# private methods.
|
|
1504
|
-
# - Receiver MUST resolve to a `Type::Nominal` so the
|
|
1505
|
-
# rule has a single class identity to query. Unions /
|
|
1506
|
-
# Dynamic / shape carriers are skipped.
|
|
1456
|
+
# - Only `:private`. `:protected` access depends on subclass tracking the engine does not yet
|
|
1457
|
+
# model; broadening waits for that surface.
|
|
1458
|
+
# - Only user classes whose visibility table the indexer built. RBS-known classes (stdlib, gems)
|
|
1459
|
+
# are NOT consulted yet — RBS visibility is reliable but surfacing it would broaden the rule to a
|
|
1460
|
+
# level the per-rule false-positive triage hasn't covered.
|
|
1461
|
+
# - Implicit-self calls are skipped (always allowed for private). Calls whose receiver is
|
|
1462
|
+
# `Prism::SelfNode` are also skipped — Ruby 2.7+ permits `self.foo` for private methods.
|
|
1463
|
+
# - Receiver MUST resolve to a `Type::Nominal` so the rule has a single class identity to query.
|
|
1464
|
+
# Unions / Dynamic / shape carriers are skipped.
|
|
1507
1465
|
def visibility_mismatch_diagnostic(path, call_node, scope_index)
|
|
1508
1466
|
return nil unless explicit_non_self_receiver?(call_node.receiver)
|
|
1509
1467
|
|
|
@@ -1538,20 +1496,15 @@ module Rigor
|
|
|
1538
1496
|
)
|
|
1539
1497
|
end
|
|
1540
1498
|
|
|
1541
|
-
# Pulls a single concrete class name from an ivar write's
|
|
1542
|
-
#
|
|
1543
|
-
#
|
|
1544
|
-
#
|
|
1545
|
-
# / Constant / Tuple / HashShape; the wrapper exists so
|
|
1546
|
-
# the ivar rule can extend the envelope (or apply
|
|
1547
|
-
# different filters) without disturbing the call rules.
|
|
1499
|
+
# Pulls a single concrete class name from an ivar write's rvalue type. Returns nil when the type is
|
|
1500
|
+
# too unstable to compare (Union / Dynamic / IntegerRange / etc.). `concrete_class_name` already
|
|
1501
|
+
# covers Nominal / Singleton / Constant / Tuple / HashShape; the wrapper exists so the ivar rule can
|
|
1502
|
+
# extend the envelope (or apply different filters) without disturbing the call rules.
|
|
1548
1503
|
#
|
|
1549
|
-
# `TrueClass` / `FalseClass` are both normalised to
|
|
1550
|
-
# `
|
|
1551
|
-
#
|
|
1552
|
-
#
|
|
1553
|
-
# `bool → String` drift still trips because the second
|
|
1554
|
-
# write's `ivar_class_for` returns `"String"`.
|
|
1504
|
+
# `TrueClass` / `FalseClass` are both normalised to `"bool"` here so the common boolean-flag idiom
|
|
1505
|
+
# (`@loaded = false` in `initialize` then `@loaded = true` on first work) doesn't fire the mismatch
|
|
1506
|
+
# rule. A real `bool → String` drift still trips because the second write's `ivar_class_for` returns
|
|
1507
|
+
# `"String"`.
|
|
1555
1508
|
def ivar_class_for(type)
|
|
1556
1509
|
name = concrete_class_name(type)
|
|
1557
1510
|
return "bool" if %w[TrueClass FalseClass].include?(name)
|
|
@@ -1615,8 +1568,8 @@ module Rigor
|
|
|
1615
1568
|
)
|
|
1616
1569
|
end
|
|
1617
1570
|
|
|
1618
|
-
# Returns the dead-branch node for a literal-predicate
|
|
1619
|
-
#
|
|
1571
|
+
# Returns the dead-branch node for a literal-predicate if/unless, or nil when no observable branch
|
|
1572
|
+
# is dead.
|
|
1620
1573
|
def unreachable_branch_for(node, truthy)
|
|
1621
1574
|
dead =
|
|
1622
1575
|
case node
|
|
@@ -2136,30 +2089,22 @@ module Rigor
|
|
|
2136
2089
|
)
|
|
2137
2090
|
end
|
|
2138
2091
|
|
|
2139
|
-
# ADR-8 § "`def.return-type-mismatch` rule" — flags a
|
|
2140
|
-
#
|
|
2141
|
-
#
|
|
2142
|
-
# Conservative envelope (v0.1.x first cut):
|
|
2092
|
+
# ADR-8 § "`def.return-type-mismatch` rule" — flags a `def m(...) ... end` whose body's last
|
|
2093
|
+
# expression's type cannot satisfy the RBS-declared return type. Conservative envelope (v0.1.x
|
|
2094
|
+
# first cut):
|
|
2143
2095
|
#
|
|
2144
|
-
# - Skips methods without an RBS declaration. The rule
|
|
2145
|
-
#
|
|
2146
|
-
#
|
|
2147
|
-
# -
|
|
2148
|
-
#
|
|
2149
|
-
#
|
|
2150
|
-
# -
|
|
2151
|
-
# absent or types as `Dynamic[top]` (the analyzer's
|
|
2152
|
-
# fail-soft fallback) — emitting on `Dynamic[top]`
|
|
2153
|
-
# would be noise.
|
|
2154
|
-
# - Compares the inferred body type against the
|
|
2155
|
-
# declared return via `accepts?`:
|
|
2096
|
+
# - Skips methods without an RBS declaration. The rule has no contract to compare against for
|
|
2097
|
+
# source-only methods.
|
|
2098
|
+
# - Skips methods whose enclosing class isn't a `Type::Singleton` self_type that we can name
|
|
2099
|
+
# (top-level / module-level methods land outside the rule).
|
|
2100
|
+
# - Skips methods whose body's last expression is absent or types as `Dynamic[top]` (the
|
|
2101
|
+
# analyzer's fail-soft fallback) — emitting on `Dynamic[top]` would be noise.
|
|
2102
|
+
# - Compares the inferred body type against the declared return via `accepts?`:
|
|
2156
2103
|
# :yes → silent
|
|
2157
|
-
# :no → emit at :error (severity_profile may
|
|
2158
|
-
# re-stamp; default `balanced` keeps the
|
|
2104
|
+
# :no → emit at :error (severity_profile may re-stamp; default `balanced` keeps the
|
|
2159
2105
|
# authored severity).
|
|
2160
|
-
# :maybe → emit at :warning. Promoted to :error
|
|
2161
|
-
#
|
|
2162
|
-
# ADR-8 § "Severity profile".
|
|
2106
|
+
# :maybe → emit at :warning. Promoted to :error under `severity_profile: strict` per ADR-8 §
|
|
2107
|
+
# "Severity profile".
|
|
2163
2108
|
def return_type_mismatch_diagnostic(path, def_node, scope_index)
|
|
2164
2109
|
return nil if def_node.body.nil?
|
|
2165
2110
|
|
|
@@ -2181,9 +2126,8 @@ module Rigor
|
|
|
2181
2126
|
build_return_type_mismatch_diagnostic(path, def_node, declared, inferred, severity)
|
|
2182
2127
|
end
|
|
2183
2128
|
|
|
2184
|
-
# The body of a `def` is the last `Prism::StatementsNode`
|
|
2185
|
-
#
|
|
2186
|
-
# Take the last statement; that's the implicit return.
|
|
2129
|
+
# The body of a `def` is the last `Prism::StatementsNode` child (or a single expression for
|
|
2130
|
+
# one-liner defs). Take the last statement; that's the implicit return.
|
|
2187
2131
|
def body_last_expression(body)
|
|
2188
2132
|
case body
|
|
2189
2133
|
when Prism::StatementsNode then body.body.last
|
|
@@ -2192,28 +2136,18 @@ module Rigor
|
|
|
2192
2136
|
end
|
|
2193
2137
|
end
|
|
2194
2138
|
|
|
2195
|
-
# Pulls the declared RBS return type for the def. The
|
|
2196
|
-
#
|
|
2197
|
-
#
|
|
2198
|
-
# `
|
|
2199
|
-
#
|
|
2200
|
-
# plain `def foo` uses `instance_method_definition`.
|
|
2201
|
-
# Method overloads contribute their union of declared
|
|
2202
|
-
# return types (any one of them satisfying the body
|
|
2203
|
-
# silences the rule).
|
|
2139
|
+
# Pulls the declared RBS return type for the def. The enclosing class name comes from the def's
|
|
2140
|
+
# scope's `self_type`; the method name is on the def itself. `def self.foo` is a singleton method
|
|
2141
|
+
# — dispatched through `Reflection.singleton_method_definition`; plain `def foo` uses
|
|
2142
|
+
# `instance_method_definition`. Method overloads contribute their union of declared return types
|
|
2143
|
+
# (any one of them satisfying the body silences the rule).
|
|
2204
2144
|
#
|
|
2205
|
-
# v0.1.2 — when the RBS sig carries a
|
|
2206
|
-
#
|
|
2207
|
-
#
|
|
2208
|
-
#
|
|
2209
|
-
#
|
|
2210
|
-
#
|
|
2211
|
-
# array[Integer]`, etc. — are stricter than the
|
|
2212
|
-
# underlying RBS class, so a body whose inferred type
|
|
2213
|
-
# the bare RBS sig would accept may still fail the
|
|
2214
|
-
# refinement (e.g. `def name; ""; end` returns
|
|
2215
|
-
# `Constant[""]`, accepted by `String` but rejected by
|
|
2216
|
-
# `non-empty-string`).
|
|
2145
|
+
# v0.1.2 — when the RBS sig carries a `%a{rigor:v1:return: <refinement>}` annotation (recognised by
|
|
2146
|
+
# `RbsExtended.read_return_type_override`), the refinement carrier replaces the RBS-declared return
|
|
2147
|
+
# for this rule. Annotation-driven refinements — `non-empty-string`, `positive-int`,
|
|
2148
|
+
# `non-empty-array[Integer]`, etc. — are stricter than the underlying RBS class, so a body whose
|
|
2149
|
+
# inferred type the bare RBS sig would accept may still fail the refinement (e.g. `def name; "";
|
|
2150
|
+
# end` returns `Constant[""]`, accepted by `String` but rejected by `non-empty-string`).
|
|
2217
2151
|
def declared_return_type(def_node, scope_index)
|
|
2218
2152
|
scope = scope_index[def_node]
|
|
2219
2153
|
return nil if scope.nil?
|
|
@@ -2253,16 +2187,12 @@ module Rigor
|
|
|
2253
2187
|
type.is_a?(Type::Dynamic) || (type.respond_to?(:top?) && type.top?.yes?)
|
|
2254
2188
|
end
|
|
2255
2189
|
|
|
2256
|
-
# Returns the severity to emit at, or nil to stay
|
|
2257
|
-
#
|
|
2258
|
-
#
|
|
2259
|
-
#
|
|
2260
|
-
#
|
|
2261
|
-
#
|
|
2262
|
-
# `Set[Symbol]`, …). ADR-8's promise to emit on
|
|
2263
|
-
# `:maybe` under `severity_profile: strict` is
|
|
2264
|
-
# deferred to a follow-up that lands together with the
|
|
2265
|
-
# narrowing precision improvements.
|
|
2190
|
+
# Returns the severity to emit at, or nil to stay silent. The first-cut implementation only fires
|
|
2191
|
+
# on proven (`:no`) mismatches; `:maybe` is treated as silent until the analyzer's narrowing
|
|
2192
|
+
# becomes precise enough to avoid noise on common patterns (`{}` → declared `Hash[K, V]`,
|
|
2193
|
+
# `Set.new` → declared `Set[Symbol]`, …). ADR-8's promise to emit on `:maybe` under
|
|
2194
|
+
# `severity_profile: strict` is deferred to a follow-up that lands together with the narrowing
|
|
2195
|
+
# precision improvements.
|
|
2266
2196
|
def compare_return(declared, inferred)
|
|
2267
2197
|
result = declared.accepts(inferred)
|
|
2268
2198
|
return :error if result.no?
|
|
@@ -2282,22 +2212,17 @@ module Rigor
|
|
|
2282
2212
|
)
|
|
2283
2213
|
end
|
|
2284
2214
|
|
|
2285
|
-
# ADR-35 slice 1 — `def.override-visibility-reduced`. The
|
|
2286
|
-
#
|
|
2287
|
-
#
|
|
2288
|
-
#
|
|
2289
|
-
# because a caller holding the supertype that invokes the
|
|
2290
|
-
# method breaks when handed the subtype.
|
|
2215
|
+
# ADR-35 slice 1 — `def.override-visibility-reduced`. The Liskov signature rule for visibility: an
|
|
2216
|
+
# instance-method override MUST NOT reduce the visibility it inherits (public → protected/private,
|
|
2217
|
+
# or protected → private), because a caller holding the supertype that invokes the method breaks
|
|
2218
|
+
# when handed the subtype.
|
|
2291
2219
|
#
|
|
2292
|
-
# Slice-1 scope (ADR-35 WD1, visibility carve-out): both the
|
|
2293
|
-
#
|
|
2294
|
-
#
|
|
2295
|
-
#
|
|
2296
|
-
#
|
|
2297
|
-
#
|
|
2298
|
-
# accessibility RBS models as public/private only, are a
|
|
2299
|
-
# deferred follow-on). When either side is not observable
|
|
2300
|
-
# the rule stays silent.
|
|
2220
|
+
# Slice-1 scope (ADR-35 WD1, visibility carve-out): both the override and the shadowed method must
|
|
2221
|
+
# have a STATICALLY OBSERVABLE visibility. The override's visibility is read from the
|
|
2222
|
+
# source-discovered table; the parent is resolved against the project-discovered ancestor chain
|
|
2223
|
+
# (user-source classes / modules only — RBS-known ancestors, whose accessibility RBS models as
|
|
2224
|
+
# public/private only, are a deferred follow-on). When either side is not observable the rule stays
|
|
2225
|
+
# silent.
|
|
2301
2226
|
def override_visibility_diagnostic(path, def_node, scope_index)
|
|
2302
2227
|
return nil unless def_node.receiver.nil? # instance methods only
|
|
2303
2228
|
|
|
@@ -2317,8 +2242,8 @@ module Rigor
|
|
|
2317
2242
|
return nil if parent.nil?
|
|
2318
2243
|
|
|
2319
2244
|
parent_class, parent_visibility = parent
|
|
2320
|
-
# Unknown ancestor visibility (e.g. the defining file was not
|
|
2321
|
-
#
|
|
2245
|
+
# Unknown ancestor visibility (e.g. the defining file was not in the analyzed set) → cannot
|
|
2246
|
+
# prove a reduction, stay silent.
|
|
2322
2247
|
return nil if parent_visibility.nil?
|
|
2323
2248
|
return nil unless visibility_reduced?(parent_visibility, override_visibility)
|
|
2324
2249
|
|
|
@@ -2327,9 +2252,8 @@ module Rigor
|
|
|
2327
2252
|
)
|
|
2328
2253
|
end
|
|
2329
2254
|
|
|
2330
|
-
# Returns true when `override_visibility` is strictly more
|
|
2331
|
-
#
|
|
2332
|
-
# public > protected > private ordering.
|
|
2255
|
+
# Returns true when `override_visibility` is strictly more restrictive than `parent_visibility`
|
|
2256
|
+
# under the public > protected > private ordering.
|
|
2333
2257
|
def visibility_reduced?(parent_visibility, override_visibility)
|
|
2334
2258
|
parent_rank = VISIBILITY_RANK[parent_visibility]
|
|
2335
2259
|
override_rank = VISIBILITY_RANK[override_visibility]
|
|
@@ -2338,14 +2262,11 @@ module Rigor
|
|
|
2338
2262
|
override_rank < parent_rank
|
|
2339
2263
|
end
|
|
2340
2264
|
|
|
2341
|
-
# Breadth-first walk of the project-discovered ancestor chain
|
|
2342
|
-
#
|
|
2343
|
-
#
|
|
2344
|
-
#
|
|
2345
|
-
#
|
|
2346
|
-
# the scope tables the runner seeds from the project pre-pass
|
|
2347
|
-
# (ADR-24 WD1). Cycle-guarded and node-count-capped. Mirrors
|
|
2348
|
-
# `ExpressionTyper#resolve_user_def_through_ancestors`.
|
|
2265
|
+
# Breadth-first walk of the project-discovered ancestor chain (included / prepended modules first,
|
|
2266
|
+
# then the superclass — Ruby's MRO ordering), yielding each resolved ancestor class name
|
|
2267
|
+
# nearest-first. Returns the first truthy value the block produces, or nil. Cross-file: the chain
|
|
2268
|
+
# is followed through the scope tables the runner seeds from the project pre-pass (ADR-24 WD1).
|
|
2269
|
+
# Cycle-guarded and node-count-capped. Mirrors `ExpressionTyper#resolve_user_def_through_ancestors`.
|
|
2349
2270
|
def each_project_ancestor(scope, class_name)
|
|
2350
2271
|
queue = ancestor_class_names(scope, class_name)
|
|
2351
2272
|
seen = { class_name.to_s => true }
|
|
@@ -2366,25 +2287,22 @@ module Rigor
|
|
|
2366
2287
|
nil
|
|
2367
2288
|
end
|
|
2368
2289
|
|
|
2369
|
-
# `[defining_class, visibility]` for the nearest user-source
|
|
2370
|
-
#
|
|
2290
|
+
# `[defining_class, visibility]` for the nearest user-source ancestor that defines an instance
|
|
2291
|
+
# method `method_name`, or nil.
|
|
2371
2292
|
def nearest_ancestor_visibility(scope, class_name, method_name)
|
|
2372
2293
|
each_project_ancestor(scope, class_name) do |ancestor|
|
|
2373
|
-
# Stop at the nearest ancestor that DEFINES the method; its
|
|
2374
|
-
#
|
|
2375
|
-
#
|
|
2376
|
-
#
|
|
2377
|
-
# large false-positive cluster on cross-file Rails concerns).
|
|
2294
|
+
# Stop at the nearest ancestor that DEFINES the method; its visibility may be nil (unknown) —
|
|
2295
|
+
# the caller treats unknown as "cannot prove a reduction" and stays silent. Never fabricate
|
|
2296
|
+
# `:public` from a missing entry (that produced a large false-positive cluster on cross-file
|
|
2297
|
+
# Rails concerns).
|
|
2378
2298
|
[ancestor, scope.discovered_method_visibility(ancestor, method_name)] if scope.user_def_for(ancestor,
|
|
2379
2299
|
method_name)
|
|
2380
2300
|
end
|
|
2381
2301
|
end
|
|
2382
2302
|
|
|
2383
|
-
# Direct ancestors of `class_name` as project-discovered,
|
|
2384
|
-
#
|
|
2385
|
-
#
|
|
2386
|
-
# subclass's lexical nesting; names that resolve to no
|
|
2387
|
-
# project class/module (RBS-known / third-party) are dropped.
|
|
2303
|
+
# Direct ancestors of `class_name` as project-discovered, qualified names: included / prepended
|
|
2304
|
+
# modules first, then the superclass. As-written names are resolved against the subclass's lexical
|
|
2305
|
+
# nesting; names that resolve to no project class/module (RBS-known / third-party) are dropped.
|
|
2388
2306
|
def ancestor_class_names(scope, class_name)
|
|
2389
2307
|
names = []
|
|
2390
2308
|
scope.includes_of(class_name).each do |raw|
|
|
@@ -2435,33 +2353,26 @@ module Rigor
|
|
|
2435
2353
|
)
|
|
2436
2354
|
end
|
|
2437
2355
|
|
|
2438
|
-
# ADR-35 slice 2 — `def.override-return-widened`. The Liskov
|
|
2439
|
-
#
|
|
2440
|
-
# *
|
|
2441
|
-
#
|
|
2442
|
-
# the result as the parent's return type; a wider override
|
|
2443
|
-
# return breaks that use.
|
|
2356
|
+
# ADR-35 slice 2 — `def.override-return-widened`. The Liskov signature rule for returns
|
|
2357
|
+
# (covariance): an override may *narrow* the return it inherits (return a more specific type) but
|
|
2358
|
+
# MUST NOT *widen* it. A caller holding the supertype uses the result as the parent's return type;
|
|
2359
|
+
# a wider override return breaks that use.
|
|
2444
2360
|
#
|
|
2445
|
-
# WD1 gate (proper, type-direction): both the override and the
|
|
2446
|
-
#
|
|
2447
|
-
#
|
|
2448
|
-
#
|
|
2449
|
-
#
|
|
2450
|
-
# nearest project-discovered ancestor whose RBS declares the
|
|
2451
|
-
# method. Inference-only either side → silent.
|
|
2361
|
+
# WD1 gate (proper, type-direction): both the override and the shadowed ancestor method must carry
|
|
2362
|
+
# an explicitly-authored RBS signature. The override side is gated by `defined_on?` (the RBS
|
|
2363
|
+
# method is declared on the overriding class itself, not merely inherited); the parent side is the
|
|
2364
|
+
# nearest project-discovered ancestor whose RBS declares the method. Inference-only either side →
|
|
2365
|
+
# silent.
|
|
2452
2366
|
#
|
|
2453
|
-
# Fires only on a proven (`:no`) widening; generic / `untyped`
|
|
2454
|
-
#
|
|
2455
|
-
#
|
|
2456
|
-
#
|
|
2457
|
-
#
|
|
2458
|
-
#
|
|
2459
|
-
#
|
|
2460
|
-
#
|
|
2461
|
-
#
|
|
2462
|
-
# ancestor must also declare it. Returns
|
|
2463
|
-
# `[scope, override_method, parent_class, parent_method]`, or nil
|
|
2464
|
-
# (the rule does not fire) when any gate is unmet.
|
|
2367
|
+
# Fires only on a proven (`:no`) widening; generic / `untyped` / `self` parent returns degrade to
|
|
2368
|
+
# `Dynamic[Top]` and accept everything, so they stay silent (FP-safe). `self`/`instance` are
|
|
2369
|
+
# translated with `self_type: nil` on both sides, so a parent `-> self` and an override `-> self`
|
|
2370
|
+
# never fire.
|
|
2371
|
+
# The authored-override resolution shared by the Liskov override rules
|
|
2372
|
+
# (`def.override-return-widened` and `def.override-param-narrowed`): the def must be an instance
|
|
2373
|
+
# method whose own class declares it in RBS, and a project-discovered ancestor must also declare
|
|
2374
|
+
# it. Returns `[scope, override_method, parent_class, parent_method]`, or nil (the rule does not
|
|
2375
|
+
# fire) when any gate is unmet.
|
|
2465
2376
|
def resolve_authored_override(def_node, scope_index)
|
|
2466
2377
|
return nil unless def_node.receiver.nil? # instance methods only (singleton: follow-on)
|
|
2467
2378
|
|
|
@@ -2502,9 +2413,8 @@ module Rigor
|
|
|
2502
2413
|
)
|
|
2503
2414
|
end
|
|
2504
2415
|
|
|
2505
|
-
# `[defining_class, RBS::Definition::Method]` for the nearest
|
|
2506
|
-
#
|
|
2507
|
-
# (not the starting class's own declaration), or nil.
|
|
2416
|
+
# `[defining_class, RBS::Definition::Method]` for the nearest project-discovered ancestor whose
|
|
2417
|
+
# RBS declares `method_name` (not the starting class's own declaration), or nil.
|
|
2508
2418
|
def nearest_ancestor_method_def(scope, class_name, method_name)
|
|
2509
2419
|
each_project_ancestor(scope, class_name) do |ancestor|
|
|
2510
2420
|
method_def = safe_instance_method_definition(ancestor, method_name, scope)
|
|
@@ -2518,8 +2428,8 @@ module Rigor
|
|
|
2518
2428
|
nil
|
|
2519
2429
|
end
|
|
2520
2430
|
|
|
2521
|
-
# True when `method_def`'s RBS declaration lives on `class_name`
|
|
2522
|
-
#
|
|
2431
|
+
# True when `method_def`'s RBS declaration lives on `class_name` itself (rather than being
|
|
2432
|
+
# inherited from an ancestor).
|
|
2523
2433
|
def defined_on?(method_def, class_name)
|
|
2524
2434
|
defined_in = method_def.defined_in
|
|
2525
2435
|
return false if defined_in.nil?
|
|
@@ -2544,23 +2454,17 @@ module Rigor
|
|
|
2544
2454
|
)
|
|
2545
2455
|
end
|
|
2546
2456
|
|
|
2547
|
-
# ADR-35 slice 3 — `def.override-param-narrowed`. The Liskov
|
|
2548
|
-
#
|
|
2549
|
-
#
|
|
2550
|
-
#
|
|
2551
|
-
# supertype passes a parent-typed argument; a narrowed override
|
|
2552
|
-
# parameter cannot accept it.
|
|
2457
|
+
# ADR-35 slice 3 — `def.override-param-narrowed`. The Liskov signature rule for parameters
|
|
2458
|
+
# (contravariance): an override may *widen* a parameter (accept a supertype — accepting more is
|
|
2459
|
+
# safe) but MUST NOT *narrow* it. A caller holding the supertype passes a parent-typed argument; a
|
|
2460
|
+
# narrowed override parameter cannot accept it.
|
|
2553
2461
|
#
|
|
2554
|
-
# Direction (ADR-35 WD3, corrected): fire on
|
|
2555
|
-
#
|
|
2556
|
-
#
|
|
2557
|
-
#
|
|
2558
|
-
#
|
|
2559
|
-
#
|
|
2560
|
-
# `untyped` / unbound-generic / interface parent params degrade
|
|
2561
|
-
# to `Dynamic[Top]` and are skipped (FP-safe). To avoid
|
|
2562
|
-
# overload-arm ambiguity, both sides must have exactly one
|
|
2563
|
-
# method type.
|
|
2462
|
+
# Direction (ADR-35 WD3, corrected): fire on `override_param.accepts(parent_param) == :no` — the
|
|
2463
|
+
# override's (narrowed) slot cannot accept the wider parent argument type. WD4: type comparison at
|
|
2464
|
+
# matching POSITIONAL parameter indices only; arity / keyword-requiredness divergence is out of
|
|
2465
|
+
# scope for v1. Same WD1 both-sides-authored gate as slice 2; `untyped` / unbound-generic /
|
|
2466
|
+
# interface parent params degrade to `Dynamic[Top]` and are skipped (FP-safe). To avoid
|
|
2467
|
+
# overload-arm ambiguity, both sides must have exactly one method type.
|
|
2564
2468
|
def override_param_narrowed_diagnostic(path, def_node, scope_index)
|
|
2565
2469
|
resolved = resolve_authored_override(def_node, scope_index)
|
|
2566
2470
|
return nil if resolved.nil?
|
|
@@ -2578,13 +2482,11 @@ module Rigor
|
|
|
2578
2482
|
)
|
|
2579
2483
|
end
|
|
2580
2484
|
|
|
2581
|
-
# Translated positional (required + optional) parameter types of
|
|
2582
|
-
#
|
|
2583
|
-
#
|
|
2584
|
-
#
|
|
2585
|
-
#
|
|
2586
|
-
# comparison). `self`/`instance` translate with `self_type: nil`
|
|
2587
|
-
# (→ `Dynamic[Top]`), matching the return-side handling.
|
|
2485
|
+
# Translated positional (required + optional) parameter types of a method's single method type, or
|
|
2486
|
+
# nil when the method is overloaded (multiple method types — arm mapping is ambiguous) or the
|
|
2487
|
+
# parameter list is not introspectable. Per-position translation failures yield `nil` at that slot
|
|
2488
|
+
# (skipped by the comparison). `self`/`instance` translate with `self_type: nil` (→
|
|
2489
|
+
# `Dynamic[Top]`), matching the return-side handling.
|
|
2588
2490
|
def positional_param_types(method_def)
|
|
2589
2491
|
method_types = method_def.method_types
|
|
2590
2492
|
return nil unless method_types.size == 1
|
|
@@ -2601,13 +2503,11 @@ module Rigor
|
|
|
2601
2503
|
end
|
|
2602
2504
|
end
|
|
2603
2505
|
|
|
2604
|
-
# Index of the first positional parameter the override narrows
|
|
2605
|
-
#
|
|
2606
|
-
#
|
|
2607
|
-
#
|
|
2608
|
-
#
|
|
2609
|
-
# type degraded to `Dynamic[Top]` (untyped / unbound generic /
|
|
2610
|
-
# interface), are skipped.
|
|
2506
|
+
# Index of the first positional parameter the override narrows relative to the parent, or nil. A
|
|
2507
|
+
# position is a violation when the override's slot cannot accept the parent's argument type
|
|
2508
|
+
# (`override_param.accepts(parent_param) == :no`). Positions where either side is
|
|
2509
|
+
# missing/untranslatable, or the parent type degraded to `Dynamic[Top]` (untyped / unbound generic
|
|
2510
|
+
# / interface), are skipped.
|
|
2611
2511
|
def first_narrowed_param_index(override_params, parent_params)
|
|
2612
2512
|
count = [override_params.size, parent_params.size].min
|
|
2613
2513
|
count.times do |i|
|