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,21 +5,17 @@ module Rigor
|
|
|
5
5
|
FALLBACK_FAMILIES = %i[prism virtual].freeze
|
|
6
6
|
private_constant :FALLBACK_FAMILIES
|
|
7
7
|
|
|
8
|
-
# Immutable value object recorded by the typer whenever Scope#type_of
|
|
9
|
-
#
|
|
10
|
-
# contract for emitting these events lives in
|
|
8
|
+
# Immutable value object recorded by the typer whenever Scope#type_of falls back to Dynamic[Top] for a
|
|
9
|
+
# node it does not yet recognise. The contract for emitting these events lives in
|
|
11
10
|
# docs/internal-spec/inference-engine.md (Fail-Soft Policy).
|
|
12
11
|
#
|
|
13
12
|
# Fields:
|
|
14
|
-
# - node_class: the Ruby class of the node that triggered the
|
|
15
|
-
#
|
|
16
|
-
# - location: the Prism source location for real Prism nodes, or
|
|
17
|
-
#
|
|
18
|
-
# -
|
|
19
|
-
#
|
|
20
|
-
# - inner_type: the Rigor::Type returned to the caller (currently
|
|
21
|
-
# always Dynamic[Top]; later slices may carry richer fallback
|
|
22
|
-
# types).
|
|
13
|
+
# - node_class: the Ruby class of the node that triggered the fallback (e.g. Prism::CallNode, or a
|
|
14
|
+
# Rigor::AST::Node subclass).
|
|
15
|
+
# - location: the Prism source location for real Prism nodes, or nil for synthetic nodes.
|
|
16
|
+
# - family: :prism for real Prism nodes, :virtual for nodes that include Rigor::AST::Node.
|
|
17
|
+
# - inner_type: the Rigor::Type returned to the caller (currently always Dynamic[Top]; later slices may
|
|
18
|
+
# carry richer fallback types).
|
|
23
19
|
class Fallback < Data.define(:node_class, :location, :family, :inner_type, :origin)
|
|
24
20
|
def initialize(node_class:, location:, family:, inner_type:, origin: nil)
|
|
25
21
|
raise ArgumentError, "node_class must be a Class, got #{node_class.class}" unless node_class.is_a?(Class)
|
|
@@ -4,16 +4,10 @@ require_relative "fallback"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
|
-
# Mutable observer that accumulates Rigor::Inference::Fallback events
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# see docs/internal-spec/inference-engine.md (Fail-Soft Policy).
|
|
12
|
-
#
|
|
13
|
-
# Future slices may add additional record_* methods (e.g.
|
|
14
|
-
# record_dispatch_miss for Slice 3, record_budget_cutoff for Slice 5);
|
|
15
|
-
# the namespaced method names exist so a single tracer can collect
|
|
16
|
-
# multiple event families without confusing them.
|
|
7
|
+
# Mutable observer that accumulates Rigor::Inference::Fallback events emitted by the type-inference
|
|
8
|
+
# engine. Pass an instance to Rigor::Scope#type_of(node, tracer: ...) to record every fail-soft fallback.
|
|
9
|
+
# The tracer MUST NOT change the return value of type_of; see docs/internal-spec/inference-engine.md
|
|
10
|
+
# (Fail-Soft Policy).
|
|
17
11
|
class FallbackTracer
|
|
18
12
|
def initialize
|
|
19
13
|
@events = []
|
|
@@ -2,21 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Inference
|
|
5
|
-
# Thread-local event recorder behind `rigor trace`: while a block runs
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# JSON); the engine itself never reads the events back, so recording
|
|
11
|
-
# is purely observational and MUST NOT change any inferred type.
|
|
5
|
+
# Thread-local event recorder behind `rigor trace`: while a block runs under {record}, the inference engine
|
|
6
|
+
# emits a flat, ordered event stream describing HOW it typed the program — expression enter/result pairs, scope
|
|
7
|
+
# binds, union formation, and method-dispatch outcomes. The CLI replays that stream as a terminal animation (or
|
|
8
|
+
# dumps it as JSON); the engine itself never reads the events back, so recording is purely observational and
|
|
9
|
+
# MUST NOT change any inferred type.
|
|
12
10
|
#
|
|
13
|
-
# Modelled on {Analysis::DependencyRecorder}: thread-local state, a
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# `Scope#with_local`, `Type::Combinator.union`,
|
|
18
|
-
# `MethodDispatcher.dispatch`) each guard their emit behind {active?},
|
|
19
|
-
# so a normal (non-tracing) run pays one integer comparison.
|
|
11
|
+
# Modelled on {Analysis::DependencyRecorder}: thread-local state, a module-level activation count so the
|
|
12
|
+
# disabled fast path ({active?}) is a plain integer read, and a frozen snapshot for consumers. The instrumented
|
|
13
|
+
# hot paths (`ExpressionTyper#type_of`, `Scope#with_local`, `Type::Combinator.union`, `MethodDispatcher.dispatch`)
|
|
14
|
+
# each guard their emit behind {active?}, so a normal (non-tracing) run pays one integer comparison.
|
|
20
15
|
module FlowTracer
|
|
21
16
|
KEY = :__rigor_flow_tracer__
|
|
22
17
|
private_constant :KEY
|
|
@@ -25,18 +20,16 @@ module Rigor
|
|
|
25
20
|
#
|
|
26
21
|
# kind :enter | :result | :bind | :union | :dispatch
|
|
27
22
|
# depth expression-recursion depth at emit time (0 = statement level)
|
|
28
|
-
# location frozen Hash with :start_line/:start_column/:end_line
|
|
29
|
-
# :
|
|
30
|
-
#
|
|
31
|
-
# innermost in-flight expression node's location so the
|
|
32
|
-
# replayer can still highlight the source being evaluated.
|
|
23
|
+
# location frozen Hash with :start_line/:start_column/:end_line/:end_column/:start_offset/:end_offset, or nil.
|
|
24
|
+
# Events without a node of their own (:bind, :union) inherit the innermost in-flight expression
|
|
25
|
+
# node's location so the replayer can still highlight the source being evaluated.
|
|
33
26
|
# stack frozen Array of short node-class names, outermost first
|
|
34
|
-
# data frozen kind-specific Hash (types pre-rendered as Strings
|
|
35
|
-
#
|
|
27
|
+
# data frozen kind-specific Hash (types pre-rendered as Strings via `describe(:short)` so events
|
|
28
|
+
# serialise to JSON as-is)
|
|
36
29
|
Event = Data.define(:kind, :depth, :location, :stack, :data)
|
|
37
30
|
|
|
38
|
-
# Mutable per-thread accumulator; only ever touched by the thread
|
|
39
|
-
#
|
|
31
|
+
# Mutable per-thread accumulator; only ever touched by the thread that activated it, so no locking is needed
|
|
32
|
+
# on the emit path.
|
|
40
33
|
class Recorder
|
|
41
34
|
attr_reader :events
|
|
42
35
|
|
|
@@ -45,9 +38,8 @@ module Rigor
|
|
|
45
38
|
@stack = []
|
|
46
39
|
end
|
|
47
40
|
|
|
48
|
-
# Brackets one `ExpressionTyper#type_of` recursion: emits :enter,
|
|
49
|
-
#
|
|
50
|
-
# and returns the type unchanged.
|
|
41
|
+
# Brackets one `ExpressionTyper#type_of` recursion: emits :enter, runs the real inference, emits :result
|
|
42
|
+
# with the inferred type, and returns the type unchanged.
|
|
51
43
|
def node(node)
|
|
52
44
|
location = location_of(node)
|
|
53
45
|
name = short_name(node.class)
|
|
@@ -100,9 +92,8 @@ module Rigor
|
|
|
100
92
|
|
|
101
93
|
module_function
|
|
102
94
|
|
|
103
|
-
# Activates recording on the current thread for the duration of the
|
|
104
|
-
#
|
|
105
|
-
# the previous recorder on exit.
|
|
95
|
+
# Activates recording on the current thread for the duration of the block and returns the frozen event list.
|
|
96
|
+
# Nests safely; restores the previous recorder on exit.
|
|
106
97
|
def record
|
|
107
98
|
previous = Thread.current[KEY]
|
|
108
99
|
recorder = Recorder.new
|
|
@@ -120,9 +111,8 @@ module Rigor
|
|
|
120
111
|
@active_count.positive?
|
|
121
112
|
end
|
|
122
113
|
|
|
123
|
-
# Brackets one expression-typing recursion. Falls through to the
|
|
124
|
-
#
|
|
125
|
-
# thread may have flipped {active?}).
|
|
114
|
+
# Brackets one expression-typing recursion. Falls through to the bare block when the current thread is not
|
|
115
|
+
# recording (another thread may have flipped {active?}).
|
|
126
116
|
def trace_node(node, &)
|
|
127
117
|
recorder = Thread.current[KEY]
|
|
128
118
|
return yield unless recorder
|
|
@@ -135,8 +125,7 @@ module Rigor
|
|
|
135
125
|
Thread.current[KEY]&.emit(:bind, data: { name: name.to_s, type: describe(type) })
|
|
136
126
|
end
|
|
137
127
|
|
|
138
|
-
# `Type::Combinator.union` — the moment branch types merge
|
|
139
|
-
# (including degenerate collapses like `1 | 1 → 1`).
|
|
128
|
+
# `Type::Combinator.union` — the moment branch types merge (including degenerate collapses like `1 | 1 → 1`).
|
|
140
129
|
def union(members, result)
|
|
141
130
|
Thread.current[KEY]&.emit(
|
|
142
131
|
:union,
|
|
@@ -144,8 +133,8 @@ module Rigor
|
|
|
144
133
|
)
|
|
145
134
|
end
|
|
146
135
|
|
|
147
|
-
# `MethodDispatcher.dispatch` — resolution or the fail-soft `nil`
|
|
148
|
-
#
|
|
136
|
+
# `MethodDispatcher.dispatch` — resolution or the fail-soft `nil` ("no rule matched"; the caller will widen
|
|
137
|
+
# to `Dynamic[Top]`).
|
|
149
138
|
def dispatch(receiver:, method_name:, args:, result:, location: nil)
|
|
150
139
|
recorder = Thread.current[KEY]
|
|
151
140
|
return unless recorder
|
|
@@ -2,45 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Inference
|
|
5
|
-
# ADR-20 Slice 2a — node types for the parsed body of a
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# ({HktReducer}) walks against a concrete argument list.
|
|
5
|
+
# ADR-20 Slice 2a — node types for the parsed body of a type-function `Definition`. Each node
|
|
6
|
+
# represents one piece of a Rigor-side type expression that the reducer ({HktReducer}) walks
|
|
7
|
+
# against a concrete argument list.
|
|
9
8
|
#
|
|
10
|
-
# Slice 2a ships a programmatic constructor surface; plugin
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# (populated by Slice 1's `HktDirectives.parse_define`) into
|
|
15
|
-
# this node tree; `body_tree` is the evaluable form.
|
|
9
|
+
# Slice 2a ships a programmatic constructor surface; plugin and Rigor-bundled overlay authors
|
|
10
|
+
# may build a body tree by hand using these node types. The string-grammar parser
|
|
11
|
+
# (`HktBodyParser`, Slice 2b, shipped) reads `Definition#body` (populated by Slice 1's
|
|
12
|
+
# `HktDirectives.parse_define`) into this node tree; `body_tree` is the evaluable form.
|
|
16
13
|
#
|
|
17
|
-
# The nine node types cover JSON.parse, dry-monads, and the
|
|
18
|
-
#
|
|
14
|
+
# The nine node types cover JSON.parse, dry-monads, and the ADR-20 § D3 conditional /
|
|
15
|
+
# membership forms (shipped):
|
|
19
16
|
#
|
|
20
|
-
# - {TypeLeaf} — wraps a fully-built `Rigor::Type`
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
# carrier as-is when the reference is self-recursive
|
|
30
|
-
# (lazy "tying-the-knot" handling that lets recursive
|
|
31
|
-
# sums like `json::value` reduce without infinite
|
|
32
|
-
# expansion).
|
|
17
|
+
# - {TypeLeaf} — wraps a fully-built `Rigor::Type` (use for atoms like `nil`,
|
|
18
|
+
# `Constant<true>`, `Nominal[Integer]`).
|
|
19
|
+
# - {Param} — reference to a formal parameter declared in the enclosing
|
|
20
|
+
# `Definition#params` list (e.g. `K` in `json::value[K]`). The reducer substitutes from the
|
|
21
|
+
# application's `args`.
|
|
22
|
+
# - {AppRef} — abstract HKT application; the reducer resolves it via the registry, or
|
|
23
|
+
# returns the `App` carrier as-is when the reference is self-recursive (lazy
|
|
24
|
+
# "tying-the-knot" handling that lets recursive sums like `json::value` reduce without
|
|
25
|
+
# infinite expansion).
|
|
33
26
|
# - {Union} — N-ary union of arms.
|
|
34
|
-
# - {NominalApp} — parameterised nominal class
|
|
35
|
-
# (`Array[X]`, `Hash[K, V]`) whose type args are
|
|
27
|
+
# - {NominalApp} — parameterised nominal class (`Array[X]`, `Hash[K, V]`) whose type args are
|
|
36
28
|
# themselves body nodes.
|
|
37
29
|
#
|
|
38
|
-
# Every node is a frozen `Data.define` value; structural
|
|
39
|
-
# equality is by-field.
|
|
30
|
+
# Every node is a frozen `Data.define` value; structural equality is by-field.
|
|
40
31
|
module HktBody
|
|
41
|
-
# Wraps a pre-built `Rigor::Type` value. Use for atoms
|
|
42
|
-
#
|
|
43
|
-
# `Constant<nil>`).
|
|
32
|
+
# Wraps a pre-built `Rigor::Type` value. Use for atoms that need no substitution
|
|
33
|
+
# (e.g. `Nominal[Integer]`, `Constant<nil>`).
|
|
44
34
|
TypeLeaf = Data.define(:type) do
|
|
45
35
|
def initialize(type:)
|
|
46
36
|
raise ArgumentError, "type must not be nil" if type.nil?
|
|
@@ -49,12 +39,10 @@ module Rigor
|
|
|
49
39
|
end
|
|
50
40
|
end
|
|
51
41
|
|
|
52
|
-
# Reference to a formal parameter the enclosing
|
|
53
|
-
# `
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
# reduction (the parser, when it ships, MUST reject
|
|
57
|
-
# unknown names earlier).
|
|
42
|
+
# Reference to a formal parameter the enclosing `Definition#params` declared. The reducer
|
|
43
|
+
# substitutes this node with the matching positional arg from the `App` being reduced; an
|
|
44
|
+
# unknown name raises during reduction (the parser, when it ships, MUST reject unknown names
|
|
45
|
+
# earlier).
|
|
58
46
|
Param = Data.define(:name) do
|
|
59
47
|
def initialize(name:)
|
|
60
48
|
raise ArgumentError, "name must be a Symbol, got #{name.class}" unless name.is_a?(Symbol)
|
|
@@ -63,11 +51,9 @@ module Rigor
|
|
|
63
51
|
end
|
|
64
52
|
end
|
|
65
53
|
|
|
66
|
-
# Abstract HKT application — the reducer's primary
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
# is an Array of body nodes (each gets substituted /
|
|
70
|
-
# resolved before being used).
|
|
54
|
+
# Abstract HKT application — the reducer's primary recursion point. `uri` is a namespaced
|
|
55
|
+
# Symbol matching some `Registration` in the registry; `args` is an Array of body nodes
|
|
56
|
+
# (each gets substituted / resolved before being used).
|
|
71
57
|
AppRef = Data.define(:uri, :args) do
|
|
72
58
|
def initialize(uri:, args:)
|
|
73
59
|
raise ArgumentError, "uri must be a Symbol, got #{uri.class}" unless uri.is_a?(Symbol)
|
|
@@ -79,9 +65,8 @@ module Rigor
|
|
|
79
65
|
end
|
|
80
66
|
end
|
|
81
67
|
|
|
82
|
-
# N-ary union. The reducer builds the result through
|
|
83
|
-
#
|
|
84
|
-
# normalization (flattening, dedup, Bot drop) applies.
|
|
68
|
+
# N-ary union. The reducer builds the result through `Type::Combinator.union(*reduced_arms)`
|
|
69
|
+
# so normalization (flattening, dedup, Bot drop) applies.
|
|
85
70
|
Union = Data.define(:arms) do
|
|
86
71
|
def initialize(arms:)
|
|
87
72
|
raise ArgumentError, "arms must be an Array, got #{arms.class}" unless arms.is_a?(Array)
|
|
@@ -91,12 +76,9 @@ module Rigor
|
|
|
91
76
|
end
|
|
92
77
|
end
|
|
93
78
|
|
|
94
|
-
# Parameterised nominal class. `class_name` is the
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
# reducer builds the result through
|
|
98
|
-
# `Type::Combinator.nominal_of(class_name, type_args:
|
|
99
|
-
# reduced_args)`.
|
|
79
|
+
# Parameterised nominal class. `class_name` is the Ruby class name (`"Array"`, `"Hash"`);
|
|
80
|
+
# `args` is an Array of body nodes for the type arguments. The reducer builds the result
|
|
81
|
+
# through `Type::Combinator.nominal_of(class_name, type_args: reduced_args)`.
|
|
100
82
|
NominalApp = Data.define(:class_name, :args) do
|
|
101
83
|
def initialize(class_name:, args:)
|
|
102
84
|
unless class_name.is_a?(String) && !class_name.empty?
|
|
@@ -109,17 +91,14 @@ module Rigor
|
|
|
109
91
|
end
|
|
110
92
|
end
|
|
111
93
|
|
|
112
|
-
# ADR-20 § D3 — conditional type form. `test` is a
|
|
113
|
-
# {
|
|
114
|
-
#
|
|
115
|
-
# current bindings; `then_branch` / `else_branch` are
|
|
116
|
-
# body nodes. The reducer's trinary handling:
|
|
94
|
+
# ADR-20 § D3 — conditional type form. `test` is a {TestSubtype} / {TestEquality} /
|
|
95
|
+
# {TestMembership} value object the reducer evaluates against the current bindings;
|
|
96
|
+
# `then_branch` / `else_branch` are body nodes. The reducer's trinary handling:
|
|
117
97
|
#
|
|
118
98
|
# - test = `yes` → return the reduced `then_branch`.
|
|
119
99
|
# - test = `no` → return the reduced `else_branch`.
|
|
120
|
-
# - test = `maybe` → widen to the union of both
|
|
121
|
-
#
|
|
122
|
-
# principle).
|
|
100
|
+
# - test = `maybe` → widen to the union of both reduced branches (per ADR-20 WD7 /
|
|
101
|
+
# robustness principle).
|
|
123
102
|
Conditional = Data.define(:test, :then_branch, :else_branch) do
|
|
124
103
|
def initialize(test:, then_branch:, else_branch:)
|
|
125
104
|
raise ArgumentError, "test must not be nil" if test.nil?
|
|
@@ -130,8 +109,8 @@ module Rigor
|
|
|
130
109
|
end
|
|
131
110
|
end
|
|
132
111
|
|
|
133
|
-
# `left <: right` — subtype check. `left` is typically
|
|
134
|
-
#
|
|
112
|
+
# `left <: right` — subtype check. `left` is typically a {Param} reference; `right` is any
|
|
113
|
+
# body expression.
|
|
135
114
|
TestSubtype = Data.define(:left, :right) do
|
|
136
115
|
def initialize(left:, right:)
|
|
137
116
|
raise ArgumentError, "left/right must not be nil" if left.nil? || right.nil?
|
|
@@ -140,9 +119,8 @@ module Rigor
|
|
|
140
119
|
end
|
|
141
120
|
end
|
|
142
121
|
|
|
143
|
-
# `left == right` — structural equality. Useful for
|
|
144
|
-
#
|
|
145
|
-
# (`E == :symbol`).
|
|
122
|
+
# `left == right` — structural equality. Useful for discriminating against literal
|
|
123
|
+
# constants (`E == :symbol`).
|
|
146
124
|
TestEquality = Data.define(:left, :right) do
|
|
147
125
|
def initialize(left:, right:)
|
|
148
126
|
raise ArgumentError, "left/right must not be nil" if left.nil? || right.nil?
|
|
@@ -151,9 +129,8 @@ module Rigor
|
|
|
151
129
|
end
|
|
152
130
|
end
|
|
153
131
|
|
|
154
|
-
# `left in [opt1, opt2, ...]` — set membership. Each
|
|
155
|
-
# `
|
|
156
|
-
# is structurally equal to any of the options.
|
|
132
|
+
# `left in [opt1, opt2, ...]` — set membership. Each `option` is a body node; the test
|
|
133
|
+
# passes iff `left` is structurally equal to any of the options.
|
|
157
134
|
TestMembership = Data.define(:left, :options) do
|
|
158
135
|
def initialize(left:, options:)
|
|
159
136
|
raise ArgumentError, "left must not be nil" if left.nil?
|
|
@@ -5,17 +5,13 @@ require_relative "../type"
|
|
|
5
5
|
|
|
6
6
|
module Rigor
|
|
7
7
|
module Inference
|
|
8
|
-
# ADR-20 slice 2b — parses the body of an
|
|
9
|
-
# `
|
|
10
|
-
# Slice
|
|
11
|
-
# `%a{rigor:v1:hkt_define}` payloads) into the `HktBody`
|
|
12
|
-
# node tree the Slice 2a reducer evaluates against.
|
|
8
|
+
# ADR-20 slice 2b — parses the body of an `HktRegistry::Definition` (a `String`, as populated
|
|
9
|
+
# by Slice 1's `HktDirectives.parse_define` from `%a{rigor:v1:hkt_define}` payloads) into the
|
|
10
|
+
# `HktBody` node tree the Slice 2a reducer evaluates against.
|
|
13
11
|
#
|
|
14
|
-
# The grammar implements the full ADR-20 § D3 subset:
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# membership forms shipped in subsequent slices. Indexed-access
|
|
18
|
-
# forms remain deferred (no concrete demand yet).
|
|
12
|
+
# The grammar implements the full ADR-20 § D3 subset: union-of-atoms/parameterised-forms for
|
|
13
|
+
# `JSON.parse`'s `json::value` recursive sum, plus the conditional and membership forms
|
|
14
|
+
# shipped in subsequent slices. Indexed-access forms remain deferred (no concrete demand yet).
|
|
19
15
|
#
|
|
20
16
|
# ## Grammar
|
|
21
17
|
#
|
|
@@ -37,22 +33,17 @@ module Rigor
|
|
|
37
33
|
#
|
|
38
34
|
# ## Disambiguation
|
|
39
35
|
#
|
|
40
|
-
# The same syntactic UCNAME spells both a parameter
|
|
41
|
-
#
|
|
42
|
-
# name
|
|
43
|
-
# `
|
|
44
|
-
#
|
|
45
|
-
# the head position of an `App[...]` form; using `App` as
|
|
46
|
-
# a class name is therefore not supported.
|
|
36
|
+
# The same syntactic UCNAME spells both a parameter reference (`K` when `params = [:K]`) and
|
|
37
|
+
# a nominal class name (`Integer`). The parser resolves by checking the `params` set passed
|
|
38
|
+
# to {.parse}; an unknown UCNAME is treated as a nominal class name. `App` is reserved at the
|
|
39
|
+
# head position of an `App[...]` form; using `App` as a class name is therefore not
|
|
40
|
+
# supported.
|
|
47
41
|
#
|
|
48
|
-
# Atoms are kept verbatim as `HktBody::TypeLeaf` nodes
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# `
|
|
52
|
-
#
|
|
53
|
-
# (i.e. `Dynamic[Top]`). Nominal class names produce raw
|
|
54
|
-
# `Type::Nominal` carriers (no `name_scope` resolution at
|
|
55
|
-
# this slice — the reducer trusts the name verbatim).
|
|
42
|
+
# Atoms are kept verbatim as `HktBody::TypeLeaf` nodes wrapping the appropriate
|
|
43
|
+
# `Rigor::Type::*` carrier: `nil` / `true` / `false` produce `Constant` carriers; `bool`
|
|
44
|
+
# produces the `Constant<true> | Constant<false>` union; `untyped` produces
|
|
45
|
+
# `Combinator.untyped` (i.e. `Dynamic[Top]`). Nominal class names produce raw `Type::Nominal`
|
|
46
|
+
# carriers (no `name_scope` resolution at this slice — the reducer trusts the name verbatim).
|
|
56
47
|
module HktBodyParser
|
|
57
48
|
class ParseError < StandardError; end
|
|
58
49
|
|
|
@@ -159,14 +150,11 @@ module Rigor
|
|
|
159
150
|
# conditional := "(" test "?" union ":" union ")"
|
|
160
151
|
# test := type_expr ("<:" | "==") type_expr
|
|
161
152
|
#
|
|
162
|
-
# Parens delimit a conditional unambiguously — bare
|
|
163
|
-
#
|
|
164
|
-
# (
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
# tests are programmatically supported via
|
|
168
|
-
# `HktBody::TestMembership` but the parser does not yet
|
|
169
|
-
# recognise the `in` keyword (no concrete demand yet).
|
|
153
|
+
# Parens delimit a conditional unambiguously — bare `(type_expr)` grouping is not
|
|
154
|
+
# supported at this slice (no use case yet). Branches can be unions; test sides are
|
|
155
|
+
# single arms (wrap in `App[my_union, ...]` if you need a union there). `in [opt1, opt2]`
|
|
156
|
+
# membership tests are programmatically supported via `HktBody::TestMembership` but the
|
|
157
|
+
# parser does not yet recognise the `in` keyword (no concrete demand yet).
|
|
170
158
|
def parse_conditional
|
|
171
159
|
expect!(:lparen)
|
|
172
160
|
test = parse_test
|
|
@@ -196,11 +184,9 @@ module Rigor
|
|
|
196
184
|
end
|
|
197
185
|
end
|
|
198
186
|
|
|
199
|
-
# `left in [opt1, opt2, ...]` membership test.
|
|
200
|
-
#
|
|
201
|
-
#
|
|
202
|
-
# `in` is permitted at this position is membership
|
|
203
|
-
# syntax.
|
|
187
|
+
# `left in [opt1, opt2, ...]` membership test. Distinguished from a lowercase atom by the
|
|
188
|
+
# subsequent `[` — the only place an identifier `in` is permitted at this position is
|
|
189
|
+
# membership syntax.
|
|
204
190
|
def parse_in_membership(left, op_token:)
|
|
205
191
|
unless op_token.value == "in"
|
|
206
192
|
raise ParseError,
|
|
@@ -243,11 +229,9 @@ module Rigor
|
|
|
243
229
|
parse_nominal_or_param_with_args
|
|
244
230
|
end
|
|
245
231
|
|
|
246
|
-
# Returns true when the current UCName is followed by
|
|
247
|
-
#
|
|
248
|
-
#
|
|
249
|
-
# token is a nominal, not a param ref — Slice 2b's
|
|
250
|
-
# `Param` nodes are always single bare identifiers.
|
|
232
|
+
# Returns true when the current UCName is followed by `::` (qualified class name
|
|
233
|
+
# continuation) or `[` (parameterised application). In either case the token is a
|
|
234
|
+
# nominal, not a param ref — Slice 2b's `Param` nodes are always single bare identifiers.
|
|
251
235
|
def class_continuation?
|
|
252
236
|
next_tok = @tokens[@pos + 1]
|
|
253
237
|
next_tok && %i[sep lb].include?(next_tok.kind)
|
|
@@ -266,8 +250,8 @@ module Rigor
|
|
|
266
250
|
end
|
|
267
251
|
|
|
268
252
|
def parse_classname_with_leading_sep
|
|
269
|
-
# The leading "::" form (`::Foo::Bar`). Consume the
|
|
270
|
-
#
|
|
253
|
+
# The leading "::" form (`::Foo::Bar`). Consume the separator so the rest threads
|
|
254
|
+
# through parse_class_name.
|
|
271
255
|
consume
|
|
272
256
|
tok = peek
|
|
273
257
|
raise ParseError, "expected class name after `::`" if tok.nil? || tok.kind != :ucname
|
|
@@ -307,13 +291,10 @@ module Rigor
|
|
|
307
291
|
parts.join("::").to_sym
|
|
308
292
|
end
|
|
309
293
|
|
|
310
|
-
# Arg list for `Foo[A, B, C]` and `App[uri, A, B]`
|
|
311
|
-
# forms
|
|
312
|
-
#
|
|
313
|
-
#
|
|
314
|
-
# `Hash[K, V]` reads as two args (each a single-arm
|
|
315
|
-
# union that collapses to the arm) rather than one
|
|
316
|
-
# union of two.
|
|
294
|
+
# Arg list for `Foo[A, B, C]` and `App[uri, A, B]` forms. Each arg is parsed as a union so
|
|
295
|
+
# per-arg `A | B` forms work (`Array[K | nil]`); the COMMA at the top level still
|
|
296
|
+
# separates args, so `Hash[K, V]` reads as two args (each a single-arm union that
|
|
297
|
+
# collapses to the arm) rather than one union of two.
|
|
317
298
|
def parse_arg_list
|
|
318
299
|
args = [parse_union]
|
|
319
300
|
while peek_kind == :comma
|