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
|
@@ -5,40 +5,29 @@ require_relative "budget_trace"
|
|
|
5
5
|
|
|
6
6
|
module Rigor
|
|
7
7
|
module Inference
|
|
8
|
-
# ADR-20 Slice 2a — reducer that walks a `Definition`'s
|
|
9
|
-
# `
|
|
10
|
-
# fully-typed `Rigor::Type`.
|
|
8
|
+
# ADR-20 Slice 2a — reducer that walks a `Definition`'s `body_tree` against a concrete
|
|
9
|
+
# `Type::App` and returns a fully-typed `Rigor::Type`.
|
|
11
10
|
#
|
|
12
|
-
# Reduction is the operational interpretation of ADR-20
|
|
13
|
-
# § D4 ("Evaluation rules"):
|
|
11
|
+
# Reduction is the operational interpretation of ADR-20 § D4 ("Evaluation rules"):
|
|
14
12
|
#
|
|
15
|
-
# 1. **Resolve `F`.** Look up the registered body via
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# `
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
# self-reference handling — the standard "tying the
|
|
30
|
-
# knot" trick for recursive type aliases like
|
|
31
|
-
# `json::value`). Otherwise build a fresh
|
|
32
|
-
# `Type::App` and recursively reduce it against the
|
|
33
|
-
# same registry, sharing the fuel budget.
|
|
34
|
-
# 5. **Fuel budget.** Each visited node consumes one unit.
|
|
35
|
-
# On exhaustion, reduction unwinds to `app.bound`.
|
|
13
|
+
# 1. **Resolve `F`.** Look up the registered body via `registry.definition(uri)`.
|
|
14
|
+
# 2. **Substitute arguments.** Walk the body tree, replacing `{HktBody::Param}` nodes with
|
|
15
|
+
# the matching positional arg from the application.
|
|
16
|
+
# 3. **Build types.** `{HktBody::TypeLeaf}` returns its wrapped type as-is; `{HktBody::Union}`
|
|
17
|
+
# and `{HktBody::NominalApp}` route their reduced children through
|
|
18
|
+
# `Type::Combinator.union` / `.nominal_of` so normalization applies.
|
|
19
|
+
# 4. **Recurse on `{HktBody::AppRef}` nodes.** Reduce the args first; if the resulting
|
|
20
|
+
# `(uri, args)` matches an App already on the current reduction stack, return the
|
|
21
|
+
# in-progress `Type::App` carrier as-is (lazy self-reference handling — the standard
|
|
22
|
+
# "tying the knot" trick for recursive type aliases like `json::value`). Otherwise build a
|
|
23
|
+
# fresh `Type::App` and recursively reduce it against the same registry, sharing the fuel
|
|
24
|
+
# budget.
|
|
25
|
+
# 5. **Fuel budget.** Each visited node consumes one unit. On exhaustion, reduction unwinds to
|
|
26
|
+
# `app.bound`.
|
|
36
27
|
#
|
|
37
|
-
# The reducer is **pure** with respect to its inputs (the
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# MUST allocate fresh reducers (or fresh `_reduce` calls)
|
|
41
|
-
# — the per-call state is not shared.
|
|
28
|
+
# The reducer is **pure** with respect to its inputs (the registry + the App) but uses a
|
|
29
|
+
# per-call mutable state bag for fuel + cycle tracking. Concurrent reductions MUST allocate
|
|
30
|
+
# fresh reducers (or fresh `_reduce` calls) — the per-call state is not shared.
|
|
42
31
|
class HktReducer
|
|
43
32
|
DEFAULT_FUEL = 64
|
|
44
33
|
|
|
@@ -53,12 +42,10 @@ module Rigor
|
|
|
53
42
|
# Reduce `app` against the registry.
|
|
54
43
|
#
|
|
55
44
|
# @param app [Rigor::Type::App]
|
|
56
|
-
# @param fuel [Integer] reduction-step budget (default 64
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
# when reduction is impossible (URI not defined, arity
|
|
61
|
-
# mismatch, body_tree absent, fuel exhausted).
|
|
45
|
+
# @param fuel [Integer] reduction-step budget (default 64 per ADR-20 WD3). Each visited
|
|
46
|
+
# body node costs one unit. On exhaustion the reduction returns `app.bound`.
|
|
47
|
+
# @return [Rigor::Type] the reduced type, or `app.bound` when reduction is impossible (URI
|
|
48
|
+
# not defined, arity mismatch, body_tree absent, fuel exhausted).
|
|
62
49
|
def reduce(app, fuel: DEFAULT_FUEL)
|
|
63
50
|
raise ArgumentError, "expected a Rigor::Type::App, got #{app.class}" unless app.is_a?(Type::App)
|
|
64
51
|
|
|
@@ -109,13 +96,12 @@ module Rigor
|
|
|
109
96
|
end
|
|
110
97
|
end
|
|
111
98
|
|
|
112
|
-
# ADR-20 § D3 conditional reduction. Resolves the test
|
|
113
|
-
#
|
|
99
|
+
# ADR-20 § D3 conditional reduction. Resolves the test against the current bindings and
|
|
100
|
+
# picks a branch:
|
|
114
101
|
#
|
|
115
102
|
# - test = `yes` → return the reduced `then_branch`.
|
|
116
103
|
# - test = `no` → return the reduced `else_branch`.
|
|
117
|
-
# - test = `maybe` → widen to the union of both
|
|
118
|
-
# reduced branches (per ADR-20 WD7).
|
|
104
|
+
# - test = `maybe` → widen to the union of both reduced branches (per ADR-20 WD7).
|
|
119
105
|
def walk_conditional(node, bindings:, state:)
|
|
120
106
|
verdict = evaluate_test(node.test, bindings: bindings, state: state)
|
|
121
107
|
case verdict
|
|
@@ -150,25 +136,21 @@ module Rigor
|
|
|
150
136
|
end
|
|
151
137
|
end
|
|
152
138
|
|
|
153
|
-
# `left <: right`. Slice 7a verdict policy: structural
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
# (widens to the union per ADR-20 WD7 — robustness
|
|
157
|
-
# principle keeps us conservative on undecided tests).
|
|
139
|
+
# `left <: right`. Slice 7a verdict policy: structural equality is `:yes`; clearly-disjoint
|
|
140
|
+
# nominal / constant pairs are `:no`; everything else is `:maybe` (widens to the union per
|
|
141
|
+
# ADR-20 WD7 — robustness principle keeps us conservative on undecided tests).
|
|
158
142
|
def subtype_verdict(left, right)
|
|
159
143
|
return :yes if left == right
|
|
160
144
|
|
|
161
|
-
# Both Nominals with different class names AND
|
|
162
|
-
#
|
|
163
|
-
# disjoint). For any other shape pair, `:maybe`.
|
|
145
|
+
# Both Nominals with different class names AND neither carries Dynamic — `:no`
|
|
146
|
+
# (statically disjoint). For any other shape pair, `:maybe`.
|
|
164
147
|
return :no if disjoint_nominals?(left, right)
|
|
165
148
|
return :no if disjoint_constants?(left, right)
|
|
166
149
|
|
|
167
150
|
:maybe
|
|
168
151
|
end
|
|
169
152
|
|
|
170
|
-
# Structural equality verdict — same shape as
|
|
171
|
-
# subtype_verdict but symmetric.
|
|
153
|
+
# Structural equality verdict — same shape as subtype_verdict but symmetric.
|
|
172
154
|
def equality_verdict(left, right)
|
|
173
155
|
return :yes if left == right
|
|
174
156
|
return :no if disjoint_nominals?(left, right)
|
|
@@ -198,11 +180,9 @@ module Rigor
|
|
|
198
180
|
end
|
|
199
181
|
|
|
200
182
|
def reduce_app_ref(uri, reduced_args, state:)
|
|
201
|
-
# Cycle detection — when the same `(uri, args)` is
|
|
202
|
-
#
|
|
203
|
-
#
|
|
204
|
-
# aliases (`Array[App[json::value, K]]` inside the
|
|
205
|
-
# `json::value` body) terminate.
|
|
183
|
+
# Cycle detection — when the same `(uri, args)` is already on the reduction stack, return
|
|
184
|
+
# the in-progress App carrier as-is so recursive type aliases (`Array[App[json::value,
|
|
185
|
+
# K]]` inside the `json::value` body) terminate.
|
|
206
186
|
existing = state.in_progress_for(uri, reduced_args)
|
|
207
187
|
return existing if existing
|
|
208
188
|
|
|
@@ -219,9 +199,8 @@ module Rigor
|
|
|
219
199
|
end
|
|
220
200
|
end
|
|
221
201
|
|
|
222
|
-
# Per-call mutable bag carrying the remaining fuel
|
|
223
|
-
#
|
|
224
|
-
# detection). Not shared across `reduce` calls.
|
|
202
|
+
# Per-call mutable bag carrying the remaining fuel budget and the active reduction stack
|
|
203
|
+
# (for cycle detection). Not shared across `reduce` calls.
|
|
225
204
|
class State
|
|
226
205
|
def initialize(fuel:)
|
|
227
206
|
@fuel = fuel
|
|
@@ -4,41 +4,32 @@ require_relative "hkt_body"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
|
-
# ADR-20 § "Decision D1 / D2" — registry of Lightweight HKT
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# `%a{rigor:v1:hkt_define: ...}` annotations in shipped
|
|
11
|
-
# `.rbs` files.
|
|
7
|
+
# ADR-20 § "Decision D1 / D2" — registry of Lightweight HKT tag registrations + type-function
|
|
8
|
+
# bodies parsed off the `%a{rigor:v1:hkt_register: ...}` / `%a{rigor:v1:hkt_define: ...}`
|
|
9
|
+
# annotations in shipped `.rbs` files.
|
|
12
10
|
#
|
|
13
|
-
# The registry stores registration metadata (arity, variance,
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# `
|
|
18
|
-
# never needs to read from the registry
|
|
19
|
-
# because Slice 1's `Type::App` carries its `bound` directly;
|
|
20
|
-
# the registry exists at this slice solely so the parser
|
|
11
|
+
# The registry stores registration metadata (arity, variance, bound) and the definition body
|
|
12
|
+
# as both a raw String and an evaluable `HktBody` node tree. `HktReducer` (Slice 2a) and
|
|
13
|
+
# `HktBodyParser` (Slice 2b) are both shipped and reduce `Type::App` instances against the
|
|
14
|
+
# definition. The carrier never needs to read from the registry because Slice 1's `Type::App`
|
|
15
|
+
# carries its `bound` directly; the registry exists at this slice solely so the parser
|
|
21
16
|
# round-trip and downstream slices have a stable target API.
|
|
22
17
|
#
|
|
23
|
-
# The registry is immutable after construction. Callers that
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# registry shareable across Ractor boundaries per ADR-15.
|
|
18
|
+
# The registry is immutable after construction. Callers that need to extend it (e.g. plugin
|
|
19
|
+
# registrations layered on top of stdlib registrations) MUST build a new registry via `merge`
|
|
20
|
+
# rather than mutating an existing one. This keeps the registry shareable across Ractor
|
|
21
|
+
# boundaries per ADR-15.
|
|
28
22
|
class HktRegistry
|
|
29
23
|
# Frozen value object recording one tag registration.
|
|
30
24
|
#
|
|
31
|
-
# - `uri`: namespaced Symbol per ADR-20 WD1 (must include
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
# - `variance`: ordered Array of Symbols, one per
|
|
36
|
-
# parameter, each `:out` (covariant), `:in`
|
|
25
|
+
# - `uri`: namespaced Symbol per ADR-20 WD1 (must include `"::"`).
|
|
26
|
+
# - `arity`: positive Integer — the number of formal parameters the registered constructor
|
|
27
|
+
# takes.
|
|
28
|
+
# - `variance`: ordered Array of Symbols, one per parameter, each `:out` (covariant), `:in`
|
|
37
29
|
# (contravariant), or `:inv` (invariant; default).
|
|
38
|
-
# - `bound`: a `Rigor::Type` to erase to when an `App`
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
# the annotation omits `bound:`).
|
|
30
|
+
# - `bound`: a `Rigor::Type` to erase to when an `App` referring to this URI cannot be
|
|
31
|
+
# reduced. Defaults to `Dynamic[Top]` (the parser fills in the default when the
|
|
32
|
+
# annotation omits `bound:`).
|
|
42
33
|
Registration = Data.define(:uri, :arity, :variance, :bound) do
|
|
43
34
|
def initialize(uri:, arity:, variance:, bound:)
|
|
44
35
|
raise ArgumentError, "uri must be a Symbol, got #{uri.class}" unless uri.is_a?(Symbol)
|
|
@@ -61,21 +52,16 @@ module Rigor
|
|
|
61
52
|
end
|
|
62
53
|
end
|
|
63
54
|
|
|
64
|
-
# Frozen value object recording one type-function
|
|
65
|
-
# definition.
|
|
55
|
+
# Frozen value object recording one type-function definition.
|
|
66
56
|
#
|
|
67
|
-
# `body` is the raw String payload from the `%a{...}`
|
|
68
|
-
#
|
|
69
|
-
# `body_tree` by `HktBodyParser` (Slice 2b, shipped).
|
|
57
|
+
# `body` is the raw String payload from the `%a{...}` annotation (Slice 1's parser
|
|
58
|
+
# populates it); parsed into `body_tree` by `HktBodyParser` (Slice 2b, shipped).
|
|
70
59
|
#
|
|
71
|
-
# `body_tree` is the evaluable form: a
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
# {.definition_with_body_tree}. The reducer treats a
|
|
77
|
-
# `nil` `body_tree` as "definition not yet evaluable"
|
|
78
|
-
# and returns the registered bound.
|
|
60
|
+
# `body_tree` is the evaluable form: a `Rigor::Inference::HktBody::*` node tree the Slice 2a
|
|
61
|
+
# reducer walks against the application's concrete arguments. Plugin and Rigor-bundled
|
|
62
|
+
# overlay authors construct it programmatically through {.definition_with_body_tree}. The
|
|
63
|
+
# reducer treats a `nil` `body_tree` as "definition not yet evaluable" and returns the
|
|
64
|
+
# registered bound.
|
|
79
65
|
Definition = Data.define(:uri, :params, :body, :body_tree, :source_path, :source_line) do
|
|
80
66
|
def initialize(uri:, params:, body:, body_tree: nil, source_path: nil, source_line: nil)
|
|
81
67
|
raise ArgumentError, "uri must be a Symbol, got #{uri.class}" unless uri.is_a?(Symbol)
|
|
@@ -97,11 +83,9 @@ module Rigor
|
|
|
97
83
|
end
|
|
98
84
|
end
|
|
99
85
|
|
|
100
|
-
# Convenience constructor for callers that have a body
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
# raw `body` slot is filled with an empty placeholder
|
|
104
|
-
# so existing consumers keep their type contract.
|
|
86
|
+
# Convenience constructor for callers that have a body tree but no raw String — typically
|
|
87
|
+
# Rigor-bundled HKT overlays that build the body programmatically. The raw `body` slot is
|
|
88
|
+
# filled with an empty placeholder so existing consumers keep their type contract.
|
|
105
89
|
def self.definition_with_body_tree(uri:, params:, body_tree:, source_path: nil, source_line: nil)
|
|
106
90
|
Definition.new(
|
|
107
91
|
uri: uri,
|
|
@@ -139,10 +123,8 @@ module Rigor
|
|
|
139
123
|
@definitions[uri]
|
|
140
124
|
end
|
|
141
125
|
|
|
142
|
-
# @return [HktRegistry] a new registry whose entries are
|
|
143
|
-
#
|
|
144
|
-
# collisions `other`'s entries win (last-write-wins; OQ3
|
|
145
|
-
# tentative).
|
|
126
|
+
# @return [HktRegistry] a new registry whose entries are the union of this registry's and
|
|
127
|
+
# `other`'s. On URI collisions `other`'s entries win (last-write-wins; OQ3 tentative).
|
|
146
128
|
def merge(other)
|
|
147
129
|
raise ArgumentError, "merge target must be an HktRegistry, got #{other.class}" unless other.is_a?(HktRegistry)
|
|
148
130
|
|
|
@@ -156,41 +138,33 @@ module Rigor
|
|
|
156
138
|
@registrations.empty? && @definitions.empty?
|
|
157
139
|
end
|
|
158
140
|
|
|
159
|
-
# ADR-20 Slice 2a — reduce an `App` against this
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
# reductions are safe.
|
|
141
|
+
# ADR-20 Slice 2a — reduce an `App` against this registry. Convenience wrapper around
|
|
142
|
+
# `HktReducer.new(self).reduce`. Each call allocates a fresh reducer; concurrent reductions
|
|
143
|
+
# are safe.
|
|
163
144
|
def reduce(app, fuel: HktReducer::DEFAULT_FUEL)
|
|
164
145
|
HktReducer.new(self).reduce(app, fuel: fuel)
|
|
165
146
|
end
|
|
166
147
|
|
|
167
|
-
# ADR-20 slice 2e — scan a Rigor RbsLoader for
|
|
168
|
-
# `rigor:v1:
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
# {
|
|
172
|
-
#
|
|
173
|
-
# entry. Last-write-wins on URI collisions per
|
|
174
|
-
# {#merge}'s contract. Fail-soft on per-annotation parse
|
|
175
|
-
# errors (the reporter records an `:info` entry; the
|
|
176
|
-
# other annotations still apply).
|
|
148
|
+
# ADR-20 slice 2e — scan a Rigor RbsLoader for `rigor:v1:hkt_register` /
|
|
149
|
+
# `rigor:v1:hkt_define` annotations attached to class- or module-level declarations in the
|
|
150
|
+
# loaded RBS env, parse them via {Rigor::RbsExtended::HktDirectives}, and return a new
|
|
151
|
+
# registry that is the union of `base` and every parsed entry. Last-write-wins on URI
|
|
152
|
+
# collisions per {#merge}'s contract. Fail-soft on per-annotation parse errors (the reporter
|
|
153
|
+
# records an `:info` entry; the other annotations still apply).
|
|
177
154
|
#
|
|
178
155
|
# @param rbs_loader [Rigor::Environment::RbsLoader]
|
|
179
|
-
# @param base [HktRegistry] starting registry (typically
|
|
180
|
-
#
|
|
181
|
-
# @param name_scope [Rigor::Environment::NameScope, nil]
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
# contract the other RBS-extended parsers use.
|
|
156
|
+
# @param base [HktRegistry] starting registry (typically the bundled
|
|
157
|
+
# `Rigor::Builtins::HktBuiltins.registry`).
|
|
158
|
+
# @param name_scope [Rigor::Environment::NameScope, nil] threaded through to the bound
|
|
159
|
+
# resolver for class-name lookups; safe to omit during scanning since hkt bounds are
|
|
160
|
+
# typically `untyped` or stdlib classes.
|
|
161
|
+
# @param reporter [#record, nil] same fail-soft reporter contract the other RBS-extended
|
|
162
|
+
# parsers use.
|
|
187
163
|
def self.scan_rbs_loader(rbs_loader, base: EMPTY, name_scope: nil, reporter: nil)
|
|
188
164
|
return base if rbs_loader.nil?
|
|
189
165
|
|
|
190
|
-
# Required lazily here to avoid a hard circular
|
|
191
|
-
#
|
|
192
|
-
# HktDirectives requires HktRegistry to construct its
|
|
193
|
-
# value objects.
|
|
166
|
+
# Required lazily here to avoid a hard circular require between hkt_registry /
|
|
167
|
+
# hkt_directives; HktDirectives requires HktRegistry to construct its value objects.
|
|
194
168
|
require_relative "../rbs_extended/hkt_directives"
|
|
195
169
|
|
|
196
170
|
registrations = []
|
|
@@ -7,62 +7,50 @@ require_relative "mutation_widening"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Inference
|
|
10
|
-
# Closes the "`params[:f] ||= []; params[:f] << x`" precision
|
|
11
|
-
#
|
|
12
|
-
# (ROADMAP § Future cycles / Type-language / engine —
|
|
10
|
+
# Closes the "`params[:f] ||= []; params[:f] << x`" precision gap surfaced by the Redmine
|
|
11
|
+
# 6.1.2 `Query#as_params` survey (ROADMAP § Future cycles / Type-language / engine —
|
|
13
12
|
# "Indexed-collection narrowing through `Hash[k] ||= default`").
|
|
14
13
|
#
|
|
15
|
-
# After `receiver[key] ||= default` the next read at
|
|
16
|
-
# `
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# which on a `HashShape{}` carrier folds to `Constant[nil]`.
|
|
14
|
+
# After `receiver[key] ||= default` the next read at `receiver[key]` is known non-nil, but
|
|
15
|
+
# Rigor types each `Hash#[]` independently and the subsequent `<<` / `[]=` / other mutator
|
|
16
|
+
# dispatches against the un-narrowed result — which on a `HashShape{}` carrier folds to
|
|
17
|
+
# `Constant[nil]`.
|
|
20
18
|
#
|
|
21
|
-
# This module is the address-recogniser + invalidator shared
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
# (which
|
|
25
|
-
#
|
|
26
|
-
# CONSUMES the narrowing when typing a follow-up `[]` read).
|
|
19
|
+
# This module is the address-recogniser + invalidator shared by
|
|
20
|
+
# {Inference::StatementEvaluator}'s `eval_index_or_write` handler (which RECORDS the
|
|
21
|
+
# narrowing) and `eval_call` (which INVALIDATES on intervening writes / mutators) and by
|
|
22
|
+
# {Inference::ExpressionTyper}'s `call_type_for` (which CONSUMES the narrowing when typing a
|
|
23
|
+
# follow-up `[]` read).
|
|
27
24
|
#
|
|
28
|
-
# **Stable receivers.** A receiver is "stable" iff it is a
|
|
29
|
-
# `
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
# looking AST chain has no guarantee of resolving to the
|
|
33
|
-
# same runtime value — narrowing it would invent a fact.
|
|
25
|
+
# **Stable receivers.** A receiver is "stable" iff it is a `LocalVariableReadNode` or
|
|
26
|
+
# `InstanceVariableReadNode`. Method-call chains (`foo.bar[:k]`) and other shapes are
|
|
27
|
+
# rejected because a follow-up read against an identical-looking AST chain has no guarantee
|
|
28
|
+
# of resolving to the same runtime value — narrowing it would invent a fact.
|
|
34
29
|
#
|
|
35
|
-
# **Stable keys.** A key is "stable" iff it is a literal
|
|
36
|
-
# `
|
|
37
|
-
#
|
|
38
|
-
# invent-a-fact reason: the local could be rebound between
|
|
39
|
-
# the `||=` and the read.
|
|
30
|
+
# **Stable keys.** A key is "stable" iff it is a literal `SymbolNode` / `StringNode` /
|
|
31
|
+
# `IntegerNode`. Local-variable keys (`params[field]`) are excluded for the same
|
|
32
|
+
# invent-a-fact reason: the local could be rebound between the `||=` and the read.
|
|
40
33
|
#
|
|
41
|
-
# **Invalidation.** Three conditions drop a recorded
|
|
42
|
-
#
|
|
43
|
-
# -
|
|
44
|
-
#
|
|
45
|
-
# - An intervening
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
# - An intervening mutator from {MutationWidening::HASH_MUTATORS}
|
|
49
|
-
# or {MutationWidening::ARRAY_MUTATORS} runs against the
|
|
50
|
-
# receiver (e.g. `params.delete(:f)`, `params.clear`).
|
|
34
|
+
# **Invalidation.** Three conditions drop a recorded narrowing:
|
|
35
|
+
# - The receiver variable is rebound (handled inside `Scope#with_local` / `Scope#with_ivar`).
|
|
36
|
+
# - An intervening `receiver[key] = value` writes the same slot — `:[]=` could rebind the
|
|
37
|
+
# slot to nil; conservative drop.
|
|
38
|
+
# - An intervening mutator from {MutationWidening::HASH_MUTATORS} or
|
|
39
|
+
# {MutationWidening::ARRAY_MUTATORS} runs against the receiver (e.g. `params.delete(:f)`,
|
|
40
|
+
# `params.clear`).
|
|
51
41
|
#
|
|
52
|
-
# All three are implemented in `StatementEvaluator#eval_call`'s
|
|
53
|
-
#
|
|
42
|
+
# All three are implemented in `StatementEvaluator#eval_call`'s post-dispatch path through
|
|
43
|
+
# {.invalidate_after_call}.
|
|
54
44
|
module IndexedNarrowing
|
|
55
|
-
# Literal Prism nodes whose Ruby value the analyzer trusts
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
# and Array indices.
|
|
45
|
+
# Literal Prism nodes whose Ruby value the analyzer trusts as a stable address. Symbol /
|
|
46
|
+
# String are the dominant Hash key shapes; Integer covers numerically-keyed Hashes and
|
|
47
|
+
# Array indices.
|
|
59
48
|
STABLE_KEY_NODES = [Prism::SymbolNode, Prism::StringNode, Prism::IntegerNode].freeze
|
|
60
49
|
|
|
61
50
|
module_function
|
|
62
51
|
|
|
63
|
-
# Returns `[receiver_kind, receiver_name]` when `node` is a
|
|
64
|
-
# `
|
|
65
|
-
# otherwise nil.
|
|
52
|
+
# Returns `[receiver_kind, receiver_name]` when `node` is a `LocalVariableReadNode` or
|
|
53
|
+
# `InstanceVariableReadNode`, otherwise nil.
|
|
66
54
|
def stable_receiver(node)
|
|
67
55
|
case node
|
|
68
56
|
when Prism::LocalVariableReadNode then [:local, node.name]
|
|
@@ -70,9 +58,8 @@ module Rigor
|
|
|
70
58
|
end
|
|
71
59
|
end
|
|
72
60
|
|
|
73
|
-
# Returns the literal Ruby value when `node` is a stable
|
|
74
|
-
#
|
|
75
|
-
# Strings → `String` (unescaped), Integers → `Integer`.
|
|
61
|
+
# Returns the literal Ruby value when `node` is a stable key shape, otherwise nil.
|
|
62
|
+
# Symbols → `Symbol`, Strings → `String` (unescaped), Integers → `Integer`.
|
|
76
63
|
def stable_key(node)
|
|
77
64
|
case node
|
|
78
65
|
when Prism::SymbolNode then node.unescaped.to_sym
|
|
@@ -81,14 +68,11 @@ module Rigor
|
|
|
81
68
|
end
|
|
82
69
|
end
|
|
83
70
|
|
|
84
|
-
# Returns `[receiver_kind, receiver_name, key]` when the
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
# `CallNode :[]=` / mutator calls). Treats only the FIRST
|
|
90
|
-
# argument as the key; `:[]=`'s second argument is the
|
|
91
|
-
# rvalue and is not part of the address.
|
|
71
|
+
# Returns `[receiver_kind, receiver_name, key]` when the CallNode is a `receiver[key]` read
|
|
72
|
+
# or write whose receiver and key are both stable, otherwise nil. Used by both the recorder
|
|
73
|
+
# (for `IndexOrWriteNode`'s receiver/arguments triplet) and the invalidator (for `CallNode
|
|
74
|
+
# :[]=` / mutator calls). Treats only the FIRST argument as the key; `:[]=`'s second
|
|
75
|
+
# argument is the rvalue and is not part of the address.
|
|
92
76
|
def stable_address(receiver_node, key_node)
|
|
93
77
|
receiver = stable_receiver(receiver_node)
|
|
94
78
|
return nil if receiver.nil?
|
|
@@ -99,10 +83,9 @@ module Rigor
|
|
|
99
83
|
[receiver.first, receiver.last, key]
|
|
100
84
|
end
|
|
101
85
|
|
|
102
|
-
# Looks up a recorded narrowing for `receiver[key]` against
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
# to refine the result of a stable indexed read.
|
|
86
|
+
# Looks up a recorded narrowing for `receiver[key]` against `scope`, returning the narrowed
|
|
87
|
+
# type or nil when no entry applies. Used by ExpressionTyper's `[]` dispatch to refine the
|
|
88
|
+
# result of a stable indexed read.
|
|
106
89
|
def lookup_for_call(node, scope)
|
|
107
90
|
return nil unless node.is_a?(Prism::CallNode)
|
|
108
91
|
return nil unless node.name == :[]
|
|
@@ -115,18 +98,14 @@ module Rigor
|
|
|
115
98
|
scope.indexed_narrowing(*address)
|
|
116
99
|
end
|
|
117
100
|
|
|
118
|
-
# Removes recorded narrowings invalidated by `call_node`.
|
|
119
|
-
# Two patterns:
|
|
101
|
+
# Removes recorded narrowings invalidated by `call_node`. Two patterns:
|
|
120
102
|
#
|
|
121
|
-
# - `receiver[key] = value` (a `:[]=` against a stable
|
|
122
|
-
#
|
|
123
|
-
# - Any mutator from `HASH_MUTATORS` / `ARRAY_MUTATORS`
|
|
124
|
-
#
|
|
125
|
-
# at that receiver, because the mutator could rebind
|
|
126
|
-
# any slot.
|
|
103
|
+
# - `receiver[key] = value` (a `:[]=` against a stable address): drop the specific
|
|
104
|
+
# `(receiver, key)` entry.
|
|
105
|
+
# - Any mutator from `HASH_MUTATORS` / `ARRAY_MUTATORS` against a stable receiver: drop
|
|
106
|
+
# EVERY entry rooted at that receiver, because the mutator could rebind any slot.
|
|
127
107
|
#
|
|
128
|
-
# Returns the updated scope. Always-safe (only forgets;
|
|
129
|
-
# never invents).
|
|
108
|
+
# Returns the updated scope. Always-safe (only forgets; never invents).
|
|
130
109
|
def invalidate_after_call(call_node:, current_scope:)
|
|
131
110
|
return current_scope unless call_node.is_a?(Prism::CallNode)
|
|
132
111
|
|
|
@@ -161,18 +140,13 @@ module Rigor
|
|
|
161
140
|
current_scope.without_indexed_narrowings_for(*receiver)
|
|
162
141
|
end
|
|
163
142
|
|
|
164
|
-
# Companion invalidator for single-hop method-chain
|
|
165
|
-
#
|
|
166
|
-
# receiver narrowing
|
|
167
|
-
# the
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
# criterion. A call against `x.last` (the OUTER receiver
|
|
172
|
-
# is a `CallNode`, not a stable root) does NOT drop
|
|
173
|
-
# narrowings keyed on `x`, so the worked-site
|
|
174
|
-
# `x.last << y` pattern correctly preserves the chain
|
|
175
|
-
# narrowing for any further `x.last` read in the same
|
|
143
|
+
# Companion invalidator for single-hop method-chain narrowings (ROADMAP § Future cycles —
|
|
144
|
+
# "Method-call receiver narrowing across stable receivers", B2 from the slice's design
|
|
145
|
+
# notes). Drops every `(receiver, *)` chain narrowing rooted at the call's OUTER stable
|
|
146
|
+
# receiver — matching the ROADMAP's "any intervening method call against the same
|
|
147
|
+
# receiver" criterion. A call against `x.last` (the OUTER receiver is a `CallNode`, not a
|
|
148
|
+
# stable root) does NOT drop narrowings keyed on `x`, so the worked-site `x.last << y`
|
|
149
|
+
# pattern correctly preserves the chain narrowing for any further `x.last` read in the same
|
|
176
150
|
# body. Always-safe (only forgets; never invents).
|
|
177
151
|
def invalidate_chain_after_call(call_node:, current_scope:)
|
|
178
152
|
return current_scope unless call_node.is_a?(Prism::CallNode)
|
|
@@ -4,35 +4,27 @@ require_relative "../type"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
|
-
# ADR-16 Tier A — engine hook. Consults every registered
|
|
8
|
-
#
|
|
9
|
-
# whether a block call site qualifies for `Scope#self_type`
|
|
10
|
-
# narrowing.
|
|
7
|
+
# ADR-16 Tier A — engine hook. Consults every registered plugin manifest's `block_as_methods`
|
|
8
|
+
# entries to decide whether a block call site qualifies for `Scope#self_type` narrowing.
|
|
11
9
|
#
|
|
12
10
|
# The match contract for a class-level DSL like Sinatra's
|
|
13
11
|
# `class MyApp < Sinatra::Base; get '/foo' do ... end; end`:
|
|
14
12
|
#
|
|
15
|
-
# - the call's lexical receiver type is `Singleton[X]`
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# - the underlying class `X` equals or inherits from the
|
|
19
|
-
# entry's `receiver_constraint`;
|
|
13
|
+
# - the call's lexical receiver type is `Singleton[X]` (the implicit-self in a class body, or
|
|
14
|
+
# an explicit `MyApp.get(...)` call);
|
|
15
|
+
# - the underlying class `X` equals or inherits from the entry's `receiver_constraint`;
|
|
20
16
|
# - the call's method name is in the entry's `method_names`.
|
|
21
17
|
#
|
|
22
|
-
# On a match the helper returns the **instance** type of
|
|
23
|
-
# the
|
|
24
|
-
# `
|
|
25
|
-
#
|
|
26
|
-
# turns the block into an instance method of the user's
|
|
27
|
-
# app class.
|
|
18
|
+
# On a match the helper returns the **instance** type of the receiver class (`Nominal[X]`) —
|
|
19
|
+
# the narrowed `self_type` for the block body, matching Sinatra's runtime semantics where
|
|
20
|
+
# `Sinatra::Base#generate_method` turns the block into an instance method of the user's app
|
|
21
|
+
# class.
|
|
28
22
|
#
|
|
29
|
-
# Slice 1b ships the floor only (per ADR-16 § WD13):
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
# parameter-typed block params, declared per-verb argument
|
|
35
|
-
# contracts — are ceiling concerns for later slices.
|
|
23
|
+
# Slice 1b ships the floor only (per ADR-16 § WD13): bare-identifier method lookups inside the
|
|
24
|
+
# block resolve through the inference engine's normal `self_type`-driven path, so methods
|
|
25
|
+
# declared on `Sinatra::Base` (RBS or otherwise) become visible. Precision additions —
|
|
26
|
+
# parameter-typed block params, declared per-verb argument contracts — are ceiling concerns
|
|
27
|
+
# for later slices.
|
|
36
28
|
module MacroBlockSelfType
|
|
37
29
|
module_function
|
|
38
30
|
|
|
@@ -51,12 +43,9 @@ module Rigor
|
|
|
51
43
|
receiver_class_name = singleton_receiver_class_name(receiver_type)
|
|
52
44
|
return nil if receiver_class_name.nil?
|
|
53
45
|
|
|
54
|
-
# ADR-52 WD1 — the verb-keyed table compiled at registry build
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
# the first ancestry match below is the same entry the previous
|
|
58
|
-
# walk returned; the method-name membership the old `matches?` checked
|
|
59
|
-
# is guaranteed by the table key.
|
|
46
|
+
# ADR-52 WD1 — the verb-keyed table compiled at registry build. Entries arrive in
|
|
47
|
+
# (plugin registration, declaration) order; the method-name membership is guaranteed
|
|
48
|
+
# by the table key.
|
|
60
49
|
entries = registry.contribution_index.block_entries_for(call_node.name)
|
|
61
50
|
entries.each do |entry|
|
|
62
51
|
if receiver_class_inherits_from?(receiver_class_name, entry.receiver_constraint, environment)
|
|
@@ -66,12 +55,10 @@ module Rigor
|
|
|
66
55
|
nil
|
|
67
56
|
end
|
|
68
57
|
|
|
69
|
-
# Tier A's match contract is intentionally narrow:
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
# `instance_eval { ... }`) are handled by later slices
|
|
74
|
-
# (Concern walker, Tier D, etc.) — not Tier A.
|
|
58
|
+
# Tier A's match contract is intentionally narrow: class-level DSL calls (receiver is
|
|
59
|
+
# `Singleton[X]`) only. Instance-receiver calls and DSL forms whose block body binds a
|
|
60
|
+
# different `self` (Concern's `included do`, `instance_eval { ... }`) are handled by later
|
|
61
|
+
# slices (Concern walker, Tier D, etc.) — not Tier A.
|
|
75
62
|
def singleton_receiver_class_name(receiver_type)
|
|
76
63
|
return nil unless receiver_type.is_a?(Type::Singleton)
|
|
77
64
|
|