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
|
@@ -7,25 +7,19 @@ require_relative "member_shape_projection"
|
|
|
7
7
|
module Rigor
|
|
8
8
|
module Inference
|
|
9
9
|
module MethodDispatcher
|
|
10
|
-
# ADR-48 — `Data.define` value folding. Three responsibilities, all
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# so the tier is precision-additive and adds no false-positive
|
|
14
|
-
# surface:
|
|
10
|
+
# ADR-48 — `Data.define` value folding. Three responsibilities, all gated on a fully-decidable shape
|
|
11
|
+
# and degrading to today's behaviour (no carrier / the `Data` nominal) the moment a premise is
|
|
12
|
+
# uncertain, so the tier is precision-additive and adds no false-positive surface:
|
|
15
13
|
#
|
|
16
|
-
# 1. `Data.define(:x, :y)` on a `Singleton[Data]` receiver with
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# 2. `.new` / `.[]` on a `DataClass` receiver -> a `DataInstance`
|
|
22
|
-
# whose member map is built from the call's positional or keyword
|
|
23
|
-
# arguments. An arity / key mismatch degrades to the `Data` (or the
|
|
14
|
+
# 1. `Data.define(:x, :y)` on a `Singleton[Data]` receiver with literal-Symbol args and NO block ->
|
|
15
|
+
# `DataClass{members: [...]}`. A block (`Data.define(:x) do ... end`) defers (slice 4 hardens the
|
|
16
|
+
# block-body case); non-literal members (`Data.define(*names)`) defer.
|
|
17
|
+
# 2. `.new` / `.[]` on a `DataClass` receiver -> a `DataInstance` whose member map is built from the
|
|
18
|
+
# call's positional or keyword arguments. An arity / key mismatch degrades to the `Data` (or the
|
|
24
19
|
# tagged class) nominal rather than a wrong member map.
|
|
25
|
-
# 3. member reads + `[]` / `to_h` / `deconstruct` / `deconstruct_keys`
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# projects the instance to its nominal through RbsDispatch.
|
|
20
|
+
# 3. member reads + `[]` / `to_h` / `deconstruct` / `deconstruct_keys` / `members` / `with` on a
|
|
21
|
+
# `DataInstance` receiver -> the precise projected type. Unhandled methods return nil so the
|
|
22
|
+
# pipeline projects the instance to its nominal through RbsDispatch.
|
|
29
23
|
#
|
|
30
24
|
# See docs/adr/48-data-struct-value-folding.md.
|
|
31
25
|
module DataFolding
|
|
@@ -51,11 +45,10 @@ module Rigor
|
|
|
51
45
|
end
|
|
52
46
|
end
|
|
53
47
|
|
|
54
|
-
# A `Data.define` value object assigned to a constant (or a
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
# (`Scope#data_member_layout`) rather than from the receiver carrier.
|
|
48
|
+
# A `Data.define` value object assigned to a constant (or a `class Point < Data.define(...)`
|
|
49
|
+
# subclass) is canonicalised by the engine to `Singleton[Point]`, not a `DataClass` — so its member
|
|
50
|
+
# layout is read from the project side-table the scope indexer built (`Scope#data_member_layout`)
|
|
51
|
+
# rather than from the receiver carrier.
|
|
59
52
|
def fold_named_new(singleton, context)
|
|
60
53
|
scope = context.scope
|
|
61
54
|
return nil if scope.nil?
|
|
@@ -79,8 +72,8 @@ module Rigor
|
|
|
79
72
|
Type::Combinator.data_class_of(members: members)
|
|
80
73
|
end
|
|
81
74
|
|
|
82
|
-
# The ordered Symbol member names, or nil when any argument is not
|
|
83
|
-
#
|
|
75
|
+
# The ordered Symbol member names, or nil when any argument is not a literal `Constant[Symbol]` (a
|
|
76
|
+
# splat or dynamic name).
|
|
84
77
|
def member_names_from_args(args)
|
|
85
78
|
names = args.map do |arg|
|
|
86
79
|
return nil unless arg.is_a?(Type::Constant) && arg.value.is_a?(Symbol)
|
|
@@ -104,9 +97,8 @@ module Rigor
|
|
|
104
97
|
Type::Combinator.data_instance_of(members: map, class_name: class_name)
|
|
105
98
|
end
|
|
106
99
|
|
|
107
|
-
# Builds the member -> type map from the call's arguments, honouring
|
|
108
|
-
#
|
|
109
|
-
# when the arguments cannot soundly populate every member.
|
|
100
|
+
# Builds the member -> type map from the call's arguments, honouring the keyword vs positional
|
|
101
|
+
# distinction read off the call node. nil when the arguments cannot soundly populate every member.
|
|
110
102
|
def member_map_for_new(members, context)
|
|
111
103
|
if keyword_new?(context)
|
|
112
104
|
keyword_member_map(members, context.args)
|
|
@@ -115,10 +107,9 @@ module Rigor
|
|
|
115
107
|
end
|
|
116
108
|
end
|
|
117
109
|
|
|
118
|
-
# `Point.new(x: 1, y: 2)` arrives as a single trailing `HashShape`
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
# call node, since both type to a `HashShape`.
|
|
110
|
+
# `Point.new(x: 1, y: 2)` arrives as a single trailing `HashShape` arg whose call node is a
|
|
111
|
+
# `KeywordHashNode`. Distinguishing it from a positional hash (`Point.new({x: 1})`, a `HashNode`)
|
|
112
|
+
# needs the call node, since both type to a `HashShape`.
|
|
122
113
|
def keyword_new?(context)
|
|
123
114
|
node = context.call_node
|
|
124
115
|
return false if node.nil?
|
|
@@ -146,9 +137,8 @@ module Rigor
|
|
|
146
137
|
members.zip(args).to_h
|
|
147
138
|
end
|
|
148
139
|
|
|
149
|
-
# A `.new` whose arguments do not fold to a precise map still has a
|
|
150
|
-
#
|
|
151
|
-
# tagged class (or the `Data` supertype).
|
|
140
|
+
# A `.new` whose arguments do not fold to a precise map still has a sound, more-precise-than-Dynamic
|
|
141
|
+
# answer: an instance of the tagged class (or the `Data` supertype).
|
|
152
142
|
def degraded_instance(class_name)
|
|
153
143
|
Type::Combinator.nominal_of(class_name || "Data")
|
|
154
144
|
end
|
|
@@ -8,51 +8,36 @@ module Rigor
|
|
|
8
8
|
module MethodDispatcher
|
|
9
9
|
# IO / File support — the pure-path-manipulation tier.
|
|
10
10
|
#
|
|
11
|
-
# File and IO carry a lot of side-effecting surface (filesystem
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# functions over their path-string arguments — they do NOT
|
|
15
|
-
# touch the filesystem and do NOT depend on the current
|
|
16
|
-
# working directory.
|
|
11
|
+
# File and IO carry a lot of side-effecting surface (filesystem reads, descriptor mutations, line iteration)
|
|
12
|
+
# the analyzer cannot fold. Several `File` class methods, however, are functions over their path-string
|
|
13
|
+
# arguments — they do NOT touch the filesystem and do NOT depend on the current working directory.
|
|
17
14
|
#
|
|
18
|
-
# Folding them is platform-sensitive: every recognised method
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# Windows vs POSIX hosts. The Ruby process running the
|
|
23
|
-
# analyzer hosts ONE platform; folding to a `Constant<String>`
|
|
24
|
-
# would silently bake that platform's answer into the
|
|
25
|
-
# analyzer's result and mis-report it on a host with a
|
|
15
|
+
# Folding them is platform-sensitive: every recognised method ([:basename, :dirname, :extname, :join, :split,
|
|
16
|
+
# :absolute_path?]) reads `File::SEPARATOR` / `File::ALT_SEPARATOR` and produces different answers on Windows
|
|
17
|
+
# vs POSIX hosts. The Ruby process running the analyzer hosts ONE platform; folding to a `Constant<String>`
|
|
18
|
+
# would silently bake that platform's answer into the analyzer's result and mis-report it on a host with a
|
|
26
19
|
# different separator policy.
|
|
27
20
|
#
|
|
28
|
-
# Default policy (`fold_platform_specific_paths == false`):
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
# will tighten the basename/dirname/join cases further without
|
|
36
|
-
# leaking platform specifics; today we leave them at the
|
|
37
|
-
# nominal envelope.
|
|
21
|
+
# Default policy (`fold_platform_specific_paths == false`): decline the fold so the RBS tier answers with
|
|
22
|
+
# `Nominal[String]` / `Tuple[Nominal[String], Nominal[String]]` / `bool`. That is the platform-agnostic
|
|
23
|
+
# envelope — every concrete answer the method could legally return on any platform fits inside it. The future
|
|
24
|
+
# `non-empty-string` refinement carrier (see
|
|
25
|
+
# [imported-built-in-types.md](../../../../../docs/type-specification/imported-built-in-types.md)) will
|
|
26
|
+
# tighten the basename/dirname/join cases further without leaking platform specifics; today we leave them at
|
|
27
|
+
# the nominal envelope.
|
|
38
28
|
#
|
|
39
|
-
# Opt-in policy (`fold_platform_specific_paths == true`):
|
|
40
|
-
# the
|
|
41
|
-
#
|
|
42
|
-
# `Constant<String>`. Single-platform projects (most internal
|
|
43
|
-
# tooling, Rails apps deployed to Linux containers) can
|
|
44
|
-
# enable this in `.rigor.yml`:
|
|
29
|
+
# Opt-in policy (`fold_platform_specific_paths == true`): the analyzer trusts that its host platform matches
|
|
30
|
+
# the callers' deployment target and folds to a precise `Constant<String>`. Single-platform projects (most
|
|
31
|
+
# internal tooling, Rails apps deployed to Linux containers) can enable this in `.rigor.yml`:
|
|
45
32
|
#
|
|
46
33
|
# fold_platform_specific_paths: true
|
|
47
34
|
#
|
|
48
|
-
# The runner reads this on startup (`Rigor::Analysis::Runner`)
|
|
49
|
-
#
|
|
35
|
+
# The runner reads this on startup (`Rigor::Analysis::Runner`) and writes the flag here. Tests toggle the
|
|
36
|
+
# flag explicitly.
|
|
50
37
|
#
|
|
51
|
-
# See [ADR-5 — robustness principle](../../../../../docs/adr/5-robustness-principle.md):
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# *correctness-preservingly* proved" excludes Constants whose
|
|
55
|
-
# value is host-specific.
|
|
38
|
+
# See [ADR-5 — robustness principle](../../../../../docs/adr/5-robustness-principle.md): the
|
|
39
|
+
# platform-agnostic default is clause-1 of the principle applied with the constraint that "as strict as can
|
|
40
|
+
# be *correctness-preservingly* proved" excludes Constants whose value is host-specific.
|
|
56
41
|
module FileFolding
|
|
57
42
|
# File class methods the analyzer can fold when the opt-in
|
|
58
43
|
# flag is set. Currently identical to PLATFORM_DEPENDENT_METHODS
|
|
@@ -8,26 +8,20 @@ module Rigor
|
|
|
8
8
|
module MethodDispatcher
|
|
9
9
|
# Iterator-style block-parameter typing.
|
|
10
10
|
#
|
|
11
|
-
# Sits ahead of `RbsDispatch.block_param_types` so the precise
|
|
12
|
-
#
|
|
13
|
-
# `Integer#
|
|
14
|
-
#
|
|
15
|
-
# widens the index to `Nominal[Integer]`, dropping every
|
|
16
|
-
# bound the receiver carries.
|
|
11
|
+
# Sits ahead of `RbsDispatch.block_param_types` so the precise integer bounds for `Integer#times` /
|
|
12
|
+
# `Integer#upto` / `Integer#downto` reach the block body's parameter binder. Without this tier the
|
|
13
|
+
# RBS signature for `Integer#times` widens the index to `Nominal[Integer]`, dropping every bound the
|
|
14
|
+
# receiver carries.
|
|
17
15
|
#
|
|
18
16
|
# Each rule mirrors Ruby's actual iteration semantics:
|
|
19
17
|
#
|
|
20
|
-
# - `n.times { |i| … }` yields `i ∈ [0, n-1]` when `n > 0`,
|
|
21
|
-
#
|
|
22
|
-
# `
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# - `a.
|
|
26
|
-
#
|
|
27
|
-
# argument.
|
|
28
|
-
# - `a.downto(b) { |i| … }` yields the same domain `[b, a]`,
|
|
29
|
-
# just iterated in reverse. Lower bound from the
|
|
30
|
-
# argument, upper bound from the receiver.
|
|
18
|
+
# - `n.times { |i| … }` yields `i ∈ [0, n-1]` when `n > 0`, nothing otherwise. The block-param type is
|
|
19
|
+
# therefore `int<0, n-1>` for a `Constant<Integer>` receiver, `int<0, upper-1>` for a finite
|
|
20
|
+
# `IntegerRange`, and `non_negative_int` for any unbounded-above shape.
|
|
21
|
+
# - `a.upto(b) { |i| … }` yields `i ∈ [a, b]` when `a <= b`. Lower bound from the receiver, upper
|
|
22
|
+
# bound from the argument.
|
|
23
|
+
# - `a.downto(b) { |i| … }` yields the same domain `[b, a]`, just iterated in reverse. Lower bound
|
|
24
|
+
# from the argument, upper bound from the receiver.
|
|
31
25
|
module IteratorDispatch
|
|
32
26
|
module_function
|
|
33
27
|
|
|
@@ -50,15 +44,12 @@ module Rigor
|
|
|
50
44
|
end
|
|
51
45
|
end
|
|
52
46
|
|
|
53
|
-
# `Class.new { |c| … }` and `Class.new(Parent) { |c| … }`
|
|
54
|
-
#
|
|
55
|
-
# class
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
# No parent → `singleton(Object)`. RBS would otherwise widen
|
|
60
|
-
# the block param to bare `Nominal[Class]`, dropping access
|
|
61
|
-
# to the parent's class-side surface.
|
|
47
|
+
# `Class.new { |c| … }` and `Class.new(Parent) { |c| … }` — the block parameter is the
|
|
48
|
+
# freshly-created anonymous class, statically representable as the parent's singleton type (the new
|
|
49
|
+
# class inherits every singleton method the parent exposes, which is what callers use this form to
|
|
50
|
+
# configure: `c.table_name = …`, `c.attribute :foo`, etc.). No parent → `singleton(Object)`. RBS
|
|
51
|
+
# would otherwise widen the block param to bare `Nominal[Class]`, dropping access to the parent's
|
|
52
|
+
# class-side surface.
|
|
62
53
|
def class_new_block_params(receiver, args)
|
|
63
54
|
return nil unless class_metaclass_receiver?(receiver)
|
|
64
55
|
|
|
@@ -95,24 +86,20 @@ module Rigor
|
|
|
95
86
|
[build_index_range(lower_bound_of(end_arg), upper_bound_of(receiver))]
|
|
96
87
|
end
|
|
97
88
|
|
|
98
|
-
# Generalised iterator: every Enumerable-shaped collection
|
|
99
|
-
#
|
|
100
|
-
# always `non-negative-int`. The element comes from the
|
|
101
|
-
# receiver's shape:
|
|
89
|
+
# Generalised iterator: every Enumerable-shaped collection in v0.0.4 yields `(element, index)` where
|
|
90
|
+
# the index is always `non-negative-int`. The element comes from the receiver's shape:
|
|
102
91
|
#
|
|
103
92
|
# - `Array[T]` / `Set[T]` / `Range[T]` → T
|
|
104
93
|
# - `Tuple[A, B, C]` → A | B | C
|
|
105
|
-
# (empty tuple cannot iterate, but we conservatively
|
|
106
|
-
#
|
|
94
|
+
# (empty tuple cannot iterate, but we conservatively fall through to RBS so a missing rule never
|
|
95
|
+
# throws)
|
|
107
96
|
# - `Hash[K, V]` / `HashShape{...}` → Tuple[K, V]
|
|
108
97
|
# (Ruby yields `[key, value]` pairs as the element)
|
|
109
98
|
# - `Constant<Array>` / `Constant<Range>` / `Constant<Set>`
|
|
110
99
|
# → corresponding Constant element
|
|
111
100
|
#
|
|
112
|
-
# Receivers we cannot project (Top, Dynamic, unknown
|
|
113
|
-
#
|
|
114
|
-
# — its element type is correct, only the index would
|
|
115
|
-
# widen to plain Integer.
|
|
101
|
+
# Receivers we cannot project (Top, Dynamic, unknown nominals, IO, …) decline so the RBS tier still
|
|
102
|
+
# answers — its element type is correct, only the index would widen to plain Integer.
|
|
116
103
|
def each_with_index_block_params(receiver)
|
|
117
104
|
element = element_type_of(receiver)
|
|
118
105
|
return nil if element.nil?
|
|
@@ -120,13 +107,11 @@ module Rigor
|
|
|
120
107
|
[element, Type::Combinator.non_negative_int]
|
|
121
108
|
end
|
|
122
109
|
|
|
123
|
-
# `each_with_object(memo) { |elem, memo_inner| … }` yields
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
# When the call has no memo argument the dispatcher
|
|
129
|
-
# declines so the user's RBS / overload selector decides.
|
|
110
|
+
# `each_with_object(memo) { |elem, memo_inner| … }` yields `(element, memo)` where `memo` is the
|
|
111
|
+
# second argument's type (passed by reference and threaded across iterations at runtime — Rigor
|
|
112
|
+
# reflects that by binding the block's second parameter to whatever the call site supplied). When
|
|
113
|
+
# the call has no memo argument the dispatcher declines so the user's RBS / overload selector
|
|
114
|
+
# decides.
|
|
130
115
|
def each_with_object_block_params(receiver, memo_arg)
|
|
131
116
|
return nil if memo_arg.nil?
|
|
132
117
|
|
|
@@ -136,21 +121,15 @@ module Rigor
|
|
|
136
121
|
[element, memo_arg]
|
|
137
122
|
end
|
|
138
123
|
|
|
139
|
-
# `inject(seed) { |memo, elem| … }` and `reduce` accept
|
|
140
|
-
# three call shapes:
|
|
124
|
+
# `inject(seed) { |memo, elem| … }` and `reduce` accept three call shapes:
|
|
141
125
|
#
|
|
142
|
-
# - `(seed) { |memo, elem| … }` — block params `[seed, element]`.
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
#
|
|
147
|
-
# - `(
|
|
148
|
-
#
|
|
149
|
-
# sound binding.
|
|
150
|
-
# - `(seed, :sym)` / `(:sym)` — Symbol method-name forms have
|
|
151
|
-
# no block. `inject` with a Symbol final arg is recognised
|
|
152
|
-
# and declined (returns nil) so the dispatcher does not
|
|
153
|
-
# pretend a block existed.
|
|
126
|
+
# - `(seed) { |memo, elem| … }` — block params `[seed, element]`. The memo's static type is the
|
|
127
|
+
# seed's; we cannot prove the block return type here without round-tripping through the block
|
|
128
|
+
# analyser, so the binding is the seed's type and downstream inference widens as needed.
|
|
129
|
+
# - `() { |memo, elem| … }` — the first iteration uses the first element as the memo, so
|
|
130
|
+
# `[element, element]` is the sound binding.
|
|
131
|
+
# - `(seed, :sym)` / `(:sym)` — Symbol method-name forms have no block. `inject` with a Symbol final
|
|
132
|
+
# arg is recognised and declined (returns nil) so the dispatcher does not pretend a block existed.
|
|
154
133
|
def inject_block_params(receiver, args)
|
|
155
134
|
element = element_type_of(receiver)
|
|
156
135
|
return nil if element.nil?
|
|
@@ -175,18 +154,15 @@ module Rigor
|
|
|
175
154
|
type.is_a?(Type::Constant) && type.value.is_a?(Symbol)
|
|
176
155
|
end
|
|
177
156
|
|
|
178
|
-
# Element-yielding Enumerable methods covered as a placeholder.
|
|
179
|
-
#
|
|
180
|
-
#
|
|
181
|
-
#
|
|
182
|
-
# receivers reach the block body with the precise per-position
|
|
183
|
-
# element union / `Tuple[K, V]` pair rather than the projected
|
|
157
|
+
# Element-yielding Enumerable methods covered as a placeholder. RBS already binds the block
|
|
158
|
+
# parameter correctly for plain `Array[T]` / `Set[T]` / `Range[T]` receivers via generic
|
|
159
|
+
# substitution; this tier exists so Tuple- and HashShape-shaped receivers reach the block body with
|
|
160
|
+
# the precise per-position element union / `Tuple[K, V]` pair rather than the projected
|
|
184
161
|
# `Array[union]` / `Hash[K, V]` widening.
|
|
185
162
|
#
|
|
186
|
-
# NOTE: `Plugin::NodeRuleWalk` (ADR-52 WD4) is now in place as
|
|
187
|
-
#
|
|
188
|
-
#
|
|
189
|
-
# remain here pending that migration.
|
|
163
|
+
# NOTE: `Plugin::NodeRuleWalk` (ADR-52 WD4) is now in place as the intended migration target for
|
|
164
|
+
# these Enumerable projections. The four methods (group_by, partition, each_slice, each_cons) remain
|
|
165
|
+
# here pending that migration.
|
|
190
166
|
def single_element_block_params(receiver)
|
|
191
167
|
element = element_type_of(receiver)
|
|
192
168
|
return nil if element.nil?
|
|
@@ -194,11 +170,9 @@ module Rigor
|
|
|
194
170
|
[element]
|
|
195
171
|
end
|
|
196
172
|
|
|
197
|
-
# `each_slice(n) { |slice| … }` and `each_cons(n) { |window| … }`
|
|
198
|
-
#
|
|
199
|
-
#
|
|
200
|
-
# `n` could in principle bound the slice's length, but a
|
|
201
|
-
# tighter Tuple-of-`n` carrier is reserved for the plugin
|
|
173
|
+
# `each_slice(n) { |slice| … }` and `each_cons(n) { |window| … }` both yield an `Array[element]`
|
|
174
|
+
# once per iteration. The tier ignores the slice-size argument (a Constant<Integer> `n` could in
|
|
175
|
+
# principle bound the slice's length, but a tighter Tuple-of-`n` carrier is reserved for the plugin
|
|
202
176
|
# tier per the NOTE above).
|
|
203
177
|
def slice_block_params(receiver)
|
|
204
178
|
element = element_type_of(receiver)
|
|
@@ -278,14 +252,12 @@ module Rigor
|
|
|
278
252
|
return build_index_range(beg, upper)
|
|
279
253
|
end
|
|
280
254
|
|
|
281
|
-
# Mixed / non-integer ranges decline: the dispatcher
|
|
282
|
-
# falls through to RBS's element-type answer.
|
|
255
|
+
# Mixed / non-integer ranges decline: the dispatcher falls through to RBS's element-type answer.
|
|
283
256
|
nil
|
|
284
257
|
end
|
|
285
258
|
|
|
286
|
-
# `Constant<Integer>`, `IntegerRange`, and `Nominal[Integer]`
|
|
287
|
-
#
|
|
288
|
-
# `Top`/`Dynamic` decline so the RBS tier answers.
|
|
259
|
+
# `Constant<Integer>`, `IntegerRange`, and `Nominal[Integer]` all participate. Non-integer types
|
|
260
|
+
# (Float, String, …) and `Top`/`Dynamic` decline so the RBS tier answers.
|
|
289
261
|
def integer_rooted?(type)
|
|
290
262
|
case type
|
|
291
263
|
when Type::Constant then type.value.is_a?(Integer)
|
|
@@ -311,10 +283,9 @@ module Rigor
|
|
|
311
283
|
end
|
|
312
284
|
end
|
|
313
285
|
|
|
314
|
-
# Builds a `Constant`/`IntegerRange` from possibly-symbolic
|
|
315
|
-
#
|
|
316
|
-
#
|
|
317
|
-
# the body still type-checks against a sensible binding.
|
|
286
|
+
# Builds a `Constant`/`IntegerRange` from possibly-symbolic bounds. Vacuous ranges (lower > upper,
|
|
287
|
+
# indicating the iterator does not fire) collapse to `non_negative_int` so the body still
|
|
288
|
+
# type-checks against a sensible binding.
|
|
318
289
|
def build_index_range(lower, upper)
|
|
319
290
|
return Type::Combinator.non_negative_int if vacuous_range?(lower, upper)
|
|
320
291
|
return Type::Combinator.constant_of(lower) if lower.is_a?(Integer) && lower == upper
|
|
@@ -5,15 +5,13 @@ require_relative "../../type"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
7
|
module MethodDispatcher
|
|
8
|
-
# Kernel intrinsic shape-folding — precision tier for the
|
|
9
|
-
#
|
|
10
|
-
# of the argument's *shape*, not just its class.
|
|
8
|
+
# Kernel intrinsic shape-folding — precision tier for the `Kernel` module-functions whose return type
|
|
9
|
+
# is a function of the argument's *shape*, not just its class.
|
|
11
10
|
#
|
|
12
|
-
# Today the only catalogued intrinsic is `Kernel#Array`. The
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# type lattice tells us what the result element type MUST be:
|
|
11
|
+
# Today the only catalogued intrinsic is `Kernel#Array`. The default RBS sig is
|
|
12
|
+
# `Array(untyped) -> Array[untyped]`, which collapses to `Array[Dynamic[top]]` for every caller. This
|
|
13
|
+
# tier short-circuits with a precise answer when the argument's type lattice tells us what the result
|
|
14
|
+
# element type MUST be:
|
|
17
15
|
#
|
|
18
16
|
# Array(Constant[nil]) -> Array[bot] # `[]`
|
|
19
17
|
# Array(Nominal["Array",[E]]) -> Array[E] # already an Array
|
|
@@ -21,20 +19,17 @@ module Rigor
|
|
|
21
19
|
# Array(Union[A,B,…]) -> distribute, then unify
|
|
22
20
|
# Array(other Nominal[T]) -> Array[Nominal[T]]
|
|
23
21
|
#
|
|
24
|
-
# For receiver shapes we cannot prove (`Top`, `Dynamic`, …)
|
|
25
|
-
#
|
|
26
|
-
# generic `Array[untyped]` envelope.
|
|
22
|
+
# For receiver shapes we cannot prove (`Top`, `Dynamic`, …) the tier returns nil and the RBS tier
|
|
23
|
+
# answers with the generic `Array[untyped]` envelope.
|
|
27
24
|
#
|
|
28
|
-
# See `docs/type-specification/value-lattice.md` for the
|
|
29
|
-
#
|
|
25
|
+
# See `docs/type-specification/value-lattice.md` for the union-distribution contract this tier
|
|
26
|
+
# mirrors.
|
|
30
27
|
module KernelDispatch
|
|
31
28
|
module_function
|
|
32
29
|
|
|
33
|
-
# `Kernel#Rational` / `Kernel#Complex` constructor folds.
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# the result into a `Constant<Rational>` / `Constant<Complex>`.
|
|
37
|
-
# The factory accepts the same shapes as Ruby:
|
|
30
|
+
# `Kernel#Rational` / `Kernel#Complex` constructor folds. When every argument is a `Type::Constant`
|
|
31
|
+
# whose value is numeric, we can run the actual Ruby constructor and lift the result into a
|
|
32
|
+
# `Constant<Rational>` / `Constant<Complex>`. The factory accepts the same shapes as Ruby:
|
|
38
33
|
# `Rational(a)`, `Rational(a, b)`, `Complex(a)`, `Complex(a, b)`.
|
|
39
34
|
NUMERIC_CONSTRUCTORS = Ractor.make_shareable({
|
|
40
35
|
Rational: Ractor.make_shareable(->(*args) { Rational(*args) }),
|
|
@@ -42,21 +37,15 @@ module Rigor
|
|
|
42
37
|
})
|
|
43
38
|
private_constant :NUMERIC_CONSTRUCTORS
|
|
44
39
|
|
|
45
|
-
# `Kernel#Integer(s)` predicate-aware refinement set
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# deliberately NOT in this set at all: since it was widened to
|
|
55
|
-
# the full Ruby numeric-literal grammar (floats, hex, rational,
|
|
56
|
-
# imaginary, signs), `Integer(numeric_string)` would raise for
|
|
57
|
-
# a `"1.5"` / `"2i"` inhabitant — not even total — so it falls
|
|
58
|
-
# through to RBS `Integer`. The `Integer(s, base)` overload is
|
|
59
|
-
# left for a later slice.
|
|
40
|
+
# `Kernel#Integer(s)` predicate-aware refinement set (v0.1.1 Track 1 slice 2b). `decimal-int-string`
|
|
41
|
+
# is the only string refinement whose every inhabitant `Integer(s)` parses without remainder, so
|
|
42
|
+
# the result is a plain `Integer` — but NOT `non-negative-int`: the predicate `/\A-?\d+\z/` admits a
|
|
43
|
+
# leading sign, so `"-7"` is a valid decimal-int-string and `Integer("-7") == -7 < 0`. The narrowing
|
|
44
|
+
# is total (every inhabitant parses) but not `>= 0`, so it lands on `universal_int`.
|
|
45
|
+
# `numeric-string` is deliberately NOT in this set at all: since it was widened to the full Ruby
|
|
46
|
+
# numeric-literal grammar (floats, hex, rational, imaginary, signs), `Integer(numeric_string)` would
|
|
47
|
+
# raise for a `"1.5"` / `"2i"` inhabitant — not even total — so it falls through to RBS `Integer`.
|
|
48
|
+
# The `Integer(s, base)` overload is left for a later slice.
|
|
60
49
|
INTEGER_REFINEMENT_PREDICATES = Set[:decimal_int].freeze
|
|
61
50
|
private_constant :INTEGER_REFINEMENT_PREDICATES
|
|
62
51
|
|
|
@@ -73,16 +62,12 @@ module Rigor
|
|
|
73
62
|
nil
|
|
74
63
|
end
|
|
75
64
|
|
|
76
|
-
# `Kernel#Integer(arg)` / `Integer(arg, base)`. Two folding
|
|
77
|
-
# paths, tried in order:
|
|
65
|
+
# `Kernel#Integer(arg)` / `Integer(arg, base)`. Two folding paths, tried in order:
|
|
78
66
|
#
|
|
79
|
-
# 1. A `Refined[String, predicate]` argument whose predicate
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# with a `Constant[Integer]` base — runs the actual
|
|
84
|
-
# `Integer()` conversion and lifts the result to
|
|
85
|
-
# `Constant[Integer]`.
|
|
67
|
+
# 1. A `Refined[String, predicate]` argument whose predicate is a total-parse carrier narrows to
|
|
68
|
+
# `universal_int` (see {try_integer_from_refinement}).
|
|
69
|
+
# 2. A `Constant` String or Numeric argument — optionally with a `Constant[Integer]` base — runs
|
|
70
|
+
# the actual `Integer()` conversion and lifts the result to `Constant[Integer]`.
|
|
86
71
|
def try_integer(args)
|
|
87
72
|
refined = try_integer_from_refinement(args)
|
|
88
73
|
return refined if refined
|
|
@@ -90,10 +75,9 @@ module Rigor
|
|
|
90
75
|
try_integer_constant(args)
|
|
91
76
|
end
|
|
92
77
|
|
|
93
|
-
# Constant-folding path for `Integer()`. A non-parseable
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
# so the RBS tier answers with the widened `Integer`.
|
|
78
|
+
# Constant-folding path for `Integer()`. A non-parseable string raises `ArgumentError` (or
|
|
79
|
+
# `TypeError` for a base against a non-string) at fold time; the handler declines so the RBS tier
|
|
80
|
+
# answers with the widened `Integer`.
|
|
97
81
|
def try_integer_constant(args)
|
|
98
82
|
return nil unless [1, 2].include?(args.size)
|
|
99
83
|
return nil unless args.all?(Type::Constant)
|
|
@@ -107,9 +91,8 @@ module Rigor
|
|
|
107
91
|
nil
|
|
108
92
|
end
|
|
109
93
|
|
|
110
|
-
# `Kernel#Float(arg)` — folds a `Constant` String or Numeric
|
|
111
|
-
#
|
|
112
|
-
# raises `ArgumentError` at fold time; the handler declines.
|
|
94
|
+
# `Kernel#Float(arg)` — folds a `Constant` String or Numeric argument to `Constant[Float]`. A
|
|
95
|
+
# non-parseable string raises `ArgumentError` at fold time; the handler declines.
|
|
113
96
|
def try_float(args)
|
|
114
97
|
return nil unless args.size == 1
|
|
115
98
|
|
|
@@ -124,17 +107,13 @@ module Rigor
|
|
|
124
107
|
nil
|
|
125
108
|
end
|
|
126
109
|
|
|
127
|
-
# `Kernel#Integer(s)` over a `Refined[String, predicate]`
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
# `
|
|
132
|
-
#
|
|
133
|
-
#
|
|
134
|
-
# the RBS `Nominal[Integer]`) so downstream range narrowing
|
|
135
|
-
# still has a range to intersect. Returns nil for any other
|
|
136
|
-
# arg shape so the RBS tier handles the generic `Integer(arg)`
|
|
137
|
-
# case.
|
|
110
|
+
# `Kernel#Integer(s)` over a `Refined[String, predicate]` whose predicate is in
|
|
111
|
+
# {INTEGER_REFINEMENT_PREDICATES}. Mirrors the `String#to_i` projection in `ShapeDispatch` (v0.1.1
|
|
112
|
+
# slice 2a) — the result is `universal_int`, NOT `non-negative-int`: a decimal-int-string admits a
|
|
113
|
+
# leading sign (`"-7"`), so the parsed Integer can be negative. The carrier stays an `IntegerRange`
|
|
114
|
+
# (rather than declining to the RBS `Nominal[Integer]`) so downstream range narrowing still has a
|
|
115
|
+
# range to intersect. Returns nil for any other arg shape so the RBS tier handles the generic
|
|
116
|
+
# `Integer(arg)` case.
|
|
138
117
|
def try_integer_from_refinement(args)
|
|
139
118
|
return nil unless args.size == 1
|
|
140
119
|
|
|
@@ -157,11 +136,9 @@ module Rigor
|
|
|
157
136
|
Type::Combinator.nominal_of("Array", type_args: [element])
|
|
158
137
|
end
|
|
159
138
|
|
|
160
|
-
# `Rational(int)` / `Rational(num, den)` and `Complex(re)`
|
|
161
|
-
#
|
|
162
|
-
#
|
|
163
|
-
# (host-side), so the result respects Ruby's normalisation
|
|
164
|
-
# (`Rational(2, 4)` → `Rational(1, 2)`).
|
|
139
|
+
# `Rational(int)` / `Rational(num, den)` and `Complex(re)` / `Complex(re, im)` fold when every arg
|
|
140
|
+
# is a numeric Constant. The actual Ruby constructor runs at fold time (host-side), so the result
|
|
141
|
+
# respects Ruby's normalisation (`Rational(2, 4)` → `Rational(1, 2)`).
|
|
165
142
|
def try_numeric_constructor(method_name, args)
|
|
166
143
|
return nil unless [1, 2].include?(args.size)
|
|
167
144
|
return nil unless args.all? { |arg| numeric_constant?(arg) }
|
|
@@ -181,21 +158,17 @@ module Rigor
|
|
|
181
158
|
type.value.is_a?(Complex))
|
|
182
159
|
end
|
|
183
160
|
|
|
184
|
-
# Computes the element type the argument contributes to the
|
|
185
|
-
#
|
|
161
|
+
# Computes the element type the argument contributes to the `Array(arg)` result, mirroring Ruby's
|
|
162
|
+
# coercion contract:
|
|
186
163
|
#
|
|
187
|
-
# - `nil` becomes `[]` (element type Bot — the empty array
|
|
188
|
-
#
|
|
189
|
-
# -
|
|
190
|
-
#
|
|
191
|
-
# -
|
|
192
|
-
# (every tuple inhabitant is a tuple, hence Array-like).
|
|
193
|
-
# - Any other value `v` becomes `[v]`, so the element type
|
|
194
|
-
# is the value's own type.
|
|
164
|
+
# - `nil` becomes `[]` (element type Bot — the empty array contributes no inhabitants).
|
|
165
|
+
# - An existing `Array[E]` is returned as-is, so its element type is `E`.
|
|
166
|
+
# - A `Tuple[T1, T2, …]` is materialised as `Array[T1|T2|…]` (every tuple inhabitant is a tuple,
|
|
167
|
+
# hence Array-like).
|
|
168
|
+
# - Any other value `v` becomes `[v]`, so the element type is the value's own type.
|
|
195
169
|
#
|
|
196
|
-
# Returns nil for receiver shapes the tier cannot prove
|
|
197
|
-
#
|
|
198
|
-
# caller falls back to the RBS-tier envelope.
|
|
170
|
+
# Returns nil for receiver shapes the tier cannot prove (Top, Dynamic, Bot in pre-coercion position)
|
|
171
|
+
# so the caller falls back to the RBS-tier envelope.
|
|
199
172
|
def element_type_of(type)
|
|
200
173
|
case type
|
|
201
174
|
when Type::Union
|