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
data/lib/rigor/type/constant.rb
CHANGED
|
@@ -7,15 +7,13 @@ require_relative "plain_lattice"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Type
|
|
10
|
-
# A literal carrier under ADR-3 OQ1 Option C (Hybrid). Wraps a Ruby
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# known enough for tuple slicing.
|
|
10
|
+
# A literal carrier under ADR-3 OQ1 Option C (Hybrid). Wraps a Ruby literal value of one of the
|
|
11
|
+
# supported immutable-ish classes. Compound literal shapes (Tuple, HashShape, Record) get dedicated
|
|
12
|
+
# classes in later slices; Range is carried only when both static endpoints are known enough for
|
|
13
|
+
# tuple slicing.
|
|
15
14
|
#
|
|
16
|
-
# See docs/adr/4-type-inference-engine.md for the tentative answer to
|
|
17
|
-
#
|
|
18
|
-
# the refinement neighbourhood this carrier lives in.
|
|
15
|
+
# See docs/adr/4-type-inference-engine.md for the tentative answer to the open question and
|
|
16
|
+
# docs/type-specification/rigor-extensions.md for the refinement neighbourhood this carrier lives in.
|
|
19
17
|
class Constant
|
|
20
18
|
SCALAR_CLASSES = [
|
|
21
19
|
Integer,
|
|
@@ -28,10 +26,9 @@ module Rigor
|
|
|
28
26
|
Regexp,
|
|
29
27
|
Pathname,
|
|
30
28
|
::Set,
|
|
31
|
-
# `Date` covers `DateTime` (a subclass). `Time` is core.
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
# literal node — so a `Constant` carrier is always sound.
|
|
29
|
+
# `Date` covers `DateTime` (a subclass). `Time` is core. Both arise only from deterministic
|
|
30
|
+
# constructor folding (`Date.new` / `Time.utc`) — there is no Date / Time literal node — so a
|
|
31
|
+
# `Constant` carrier is always sound.
|
|
35
32
|
Date,
|
|
36
33
|
Time,
|
|
37
34
|
TrueClass,
|
|
@@ -56,22 +53,18 @@ module Rigor
|
|
|
56
53
|
freeze
|
|
57
54
|
end
|
|
58
55
|
|
|
59
|
-
# Mutable-ish carriers are stored as a frozen copy so a later
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
# (the catalog also blocklists the mutators). `Date` is already
|
|
64
|
-
# immutable, but is duped-and-frozen for symmetry.
|
|
56
|
+
# Mutable-ish carriers are stored as a frozen copy so a later in-place mutation cannot rewrite the
|
|
57
|
+
# literal under us. `Time` joins `String` / `Set` here: `Time#localtime` mutates the receiver's
|
|
58
|
+
# zone in place, so the carrier holds a frozen copy (the catalog also blocklists the mutators).
|
|
59
|
+
# `Date` is already immutable, but is duped-and-frozen for symmetry.
|
|
65
60
|
def freezable_carrier?(value)
|
|
66
61
|
value.is_a?(String) || value.is_a?(::Set) ||
|
|
67
62
|
value.is_a?(Date) || value.is_a?(Time)
|
|
68
63
|
end
|
|
69
64
|
|
|
70
|
-
# `Date#inspect` / `DateTime#inspect` spell out the internal
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
# form. `Time#inspect` is already compact (`2026-01-01
|
|
74
|
-
# 00:00:00 UTC`), so it keeps the default.
|
|
65
|
+
# `Date#inspect` / `DateTime#inspect` spell out the internal astronomical-Julian-day representation,
|
|
66
|
+
# which is unreadable in a diagnostic. ISO-8601 is the compact, deterministic form. `Time#inspect`
|
|
67
|
+
# is already compact (`2026-01-01 00:00:00 UTC`), so it keeps the default.
|
|
75
68
|
def describe(_verbosity = :short)
|
|
76
69
|
case value
|
|
77
70
|
when Date then value.iso8601
|
|
@@ -79,17 +72,13 @@ module Rigor
|
|
|
79
72
|
end
|
|
80
73
|
end
|
|
81
74
|
|
|
82
|
-
# RBS supports `Literal` types for booleans, nil, integer
|
|
83
|
-
# literals
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
# without RBS Literal support (Float, Range, Rational,
|
|
90
|
-
# Complex, Regexp, Pathname) keep their pre-existing
|
|
91
|
-
# widen-to-class-name behaviour because RBS rejects their
|
|
92
|
-
# literal spellings as syntax errors.
|
|
75
|
+
# RBS supports `Literal` types for booleans, nil, integer literals (positive and negative), symbol
|
|
76
|
+
# literals, and string literals. Erasing to these preserves the carrier's precision at the RBS
|
|
77
|
+
# boundary — `Constant<64>` round-trips as `64`, not as `Integer` — and
|
|
78
|
+
# `RbsTypeTranslator#translate_literal` already maps the parsed RBS Literal back to `Constant`.
|
|
79
|
+
# Scalar carriers without RBS Literal support (Float, Range, Rational, Complex, Regexp, Pathname)
|
|
80
|
+
# keep their pre-existing widen-to-class-name behaviour because RBS rejects their literal spellings
|
|
81
|
+
# as syntax errors.
|
|
93
82
|
def erase_to_rbs
|
|
94
83
|
case value
|
|
95
84
|
when true then "true"
|
|
@@ -7,23 +7,18 @@ require_relative "plain_lattice"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Type
|
|
10
|
-
# The class object produced by `Data.define(:x, :y)` (ADR-48). Models
|
|
11
|
-
# the
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# member-name list so that `Point.new(...)` can materialise a precise
|
|
15
|
-
# {DataInstance}.
|
|
10
|
+
# The class object produced by `Data.define(:x, :y)` (ADR-48). Models the *class*, not an instance —
|
|
11
|
+
# the value bound to `Point` in `Point = Data.define(:x, :y)` or the anonymous superclass in `class
|
|
12
|
+
# Point < Data.define(:x, :y)`. Parameterised by the ordered member-name list so that `Point.new(...)`
|
|
13
|
+
# can materialise a precise {DataInstance}.
|
|
16
14
|
#
|
|
17
|
-
# `class_name` carries the binding name when known (the named-subclass
|
|
18
|
-
#
|
|
19
|
-
# `
|
|
20
|
-
# instances `.new` produces; it does not change the carrier's folding
|
|
21
|
-
# behaviour.
|
|
15
|
+
# `class_name` carries the binding name when known (the named-subclass form, ADR-48 slice 3) and is
|
|
16
|
+
# `nil` for the anonymous result of a bare `Data.define(...)` before it is assigned to a constant. It
|
|
17
|
+
# tags the instances `.new` produces; it does not change the carrier's folding behaviour.
|
|
22
18
|
#
|
|
23
|
-
# Equality and hashing are structural over the member list and the
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# constants they are bound to by the binding, not by the carrier.
|
|
19
|
+
# Equality and hashing are structural over the member list and the class name. Two distinct
|
|
20
|
+
# `Data.define(:x)` results are equal *as types* — they describe the same shape; the engine
|
|
21
|
+
# distinguishes the constants they are bound to by the binding, not by the carrier.
|
|
27
22
|
#
|
|
28
23
|
# See docs/adr/48-data-struct-value-folding.md.
|
|
29
24
|
class DataClass
|
|
@@ -7,26 +7,21 @@ require_relative "plain_lattice"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Type
|
|
10
|
-
# A `Data.define` value instance (ADR-48) — `Point.new(1, 2)`. Models a
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# and it erases to its class nominal rather than an RBS record.
|
|
10
|
+
# A `Data.define` value instance (ADR-48) — `Point.new(1, 2)`. Models a closed, total, class-tagged
|
|
11
|
+
# member map (member name -> value type). HashShape-shaped, but nominal: a `DataInstance` tagged
|
|
12
|
+
# `Point` is a different type from one tagged `Line` even with identical members, and it erases to
|
|
13
|
+
# its class nominal rather than an RBS record.
|
|
15
14
|
#
|
|
16
|
-
# `Data` instances are frozen, so the member map is sound for the
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# would invalidate the map; that follow-up is deferred — see ADR-48).
|
|
15
|
+
# `Data` instances are frozen, so the member map is sound for the instance's whole lifetime — the
|
|
16
|
+
# reason `Data` is the first target (a `Struct` instance can be mutated through a setter or `[]=`,
|
|
17
|
+
# which would invalidate the map; that follow-up is deferred — see ADR-48).
|
|
20
18
|
#
|
|
21
|
-
# Member reads fold to the member's type (`Point.new(1, 2).x` ->
|
|
22
|
-
# `
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# {RbsDispatch}'s `receiver_descriptor`, so non-member calls resolve
|
|
26
|
-
# without mis-firing undefined-method.
|
|
19
|
+
# Member reads fold to the member's type (`Point.new(1, 2).x` -> `Constant[1]`); `[]`, `to_h`,
|
|
20
|
+
# `deconstruct`, `deconstruct_keys`, `members`, and `with` project precisely. Methods this carrier
|
|
21
|
+
# does not fold project to the `Data` nominal (or the tagged class) through {RbsDispatch}'s
|
|
22
|
+
# `receiver_descriptor`, so non-member calls resolve without mis-firing undefined-method.
|
|
27
23
|
#
|
|
28
|
-
# Equality and hashing are structural over the (member -> type) map and
|
|
29
|
-
# the class name.
|
|
24
|
+
# Equality and hashing are structural over the (member -> type) map and the class name.
|
|
30
25
|
#
|
|
31
26
|
# See docs/adr/48-data-struct-value-folding.md.
|
|
32
27
|
class DataInstance
|
|
@@ -65,9 +60,8 @@ module Rigor
|
|
|
65
60
|
"#{class_name || 'Data'}(#{rendered.join(', ')})"
|
|
66
61
|
end
|
|
67
62
|
|
|
68
|
-
# Erases to the tagging class nominal (conservative: the structural
|
|
69
|
-
#
|
|
70
|
-
# anonymous case erases to the `Data` supertype.
|
|
63
|
+
# Erases to the tagging class nominal (conservative: the structural members are not RBS-expressible
|
|
64
|
+
# as a class instance). The anonymous case erases to the `Data` supertype.
|
|
71
65
|
def erase_to_rbs
|
|
72
66
|
name = class_name
|
|
73
67
|
return "Data" if name.nil?
|
|
@@ -6,35 +6,26 @@ require_relative "acceptance_router"
|
|
|
6
6
|
|
|
7
7
|
module Rigor
|
|
8
8
|
module Type
|
|
9
|
-
# `Difference[base, removed]` — the value set of `base` minus
|
|
10
|
-
# the
|
|
11
|
-
#
|
|
12
|
-
# ([ADR-3](docs/adr/3-type-representation.md), Working
|
|
13
|
-
# Decision Option C):
|
|
9
|
+
# `Difference[base, removed]` — the value set of `base` minus the value set of `removed`. Implements
|
|
10
|
+
# the point-removal half of the OQ3 refinement-carrier strategy ([ADR-3](docs/adr/3-type-representation.md),
|
|
11
|
+
# Working Decision Option C):
|
|
14
12
|
#
|
|
15
13
|
# non-empty-string = Difference[Nominal[String], Constant[""]]
|
|
16
14
|
# non-zero-int = Difference[Nominal[Integer], Constant[0]]
|
|
17
15
|
# non-empty-array[T] = Difference[Nominal[Array, [T]], Tuple[]]
|
|
18
16
|
# non-empty-hash[K,V] = Difference[Nominal[Hash, [K,V]], HashShape{}]
|
|
19
17
|
#
|
|
20
|
-
# The carrier itself is structural: it stores `base` and
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# `Rigor::Type::Combinator` and prints kebab-case names like
|
|
27
|
-
# `non-empty-string` for the recognised shapes; unrecognised
|
|
28
|
-
# differences fall back to the raw `base - removed`
|
|
29
|
-
# operator form per [`type-operators.md`](docs/type-specification/type-operators.md).
|
|
18
|
+
# The carrier itself is structural: it stores `base` and `removed` as inner `Type` references and
|
|
19
|
+
# answers projection / acceptance / display questions by composing those inner answers per the
|
|
20
|
+
# lattice algebra in [`value-lattice.md`](docs/type-specification/value-lattice.md). The
|
|
21
|
+
# canonical-name registry (display side) lives in `Rigor::Type::Combinator` and prints kebab-case
|
|
22
|
+
# names like `non-empty-string` for the recognised shapes; unrecognised differences fall back to the
|
|
23
|
+
# raw `base - removed` operator form per [`type-operators.md`](docs/type-specification/type-operators.md).
|
|
30
24
|
#
|
|
31
|
-
# Construction goes through `Type::Combinator.difference` /
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
# subtype-or-equal of `base` (otherwise the difference does
|
|
36
|
-
# not narrow anything and a normalisation upstream should
|
|
37
|
-
# collapse to `base`).
|
|
25
|
+
# Construction goes through `Type::Combinator.difference` / `Combinator.non_empty_string` etc. —
|
|
26
|
+
# direct `.new` calls are an internal contract; callers MUST ensure both bounds are valid
|
|
27
|
+
# `Rigor::Type` values and that `removed` is a subtype-or-equal of `base` (otherwise the difference
|
|
28
|
+
# does not narrow anything and a normalisation upstream should collapse to `base`).
|
|
38
29
|
class Difference
|
|
39
30
|
attr_reader :base, :removed
|
|
40
31
|
|
|
@@ -51,8 +42,8 @@ module Rigor
|
|
|
51
42
|
"#{base.describe(verbosity)} - #{removed.describe(verbosity)}"
|
|
52
43
|
end
|
|
53
44
|
|
|
54
|
-
# Erases to the base nominal: every refinement MUST erase
|
|
55
|
-
#
|
|
45
|
+
# Erases to the base nominal: every refinement MUST erase to its base per
|
|
46
|
+
# [`rbs-erasure.md`](docs/type-specification/rbs-erasure.md).
|
|
56
47
|
def erase_to_rbs
|
|
57
48
|
base.erase_to_rbs
|
|
58
49
|
end
|
|
@@ -81,15 +72,13 @@ module Rigor
|
|
|
81
72
|
|
|
82
73
|
private
|
|
83
74
|
|
|
84
|
-
# Renders the kebab-case shorthand for recognised
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
# `
|
|
88
|
-
# display round-trip. Unrecognised shapes fall back to the
|
|
89
|
-
# raw `base - removed` operator form.
|
|
75
|
+
# Renders the kebab-case shorthand for recognised imported-built-in shapes. Parameterised bases
|
|
76
|
+
# keep their type-args in the canonical form (`non-empty-array[T]`, `non-empty-hash[K, V]`) so
|
|
77
|
+
# element-precision survives the display round-trip. Unrecognised shapes fall back to the raw
|
|
78
|
+
# `base - removed` operator form.
|
|
90
79
|
#
|
|
91
|
-
# The recognised set is kept in sync with the imported-built-in
|
|
92
|
-
#
|
|
80
|
+
# The recognised set is kept in sync with the imported-built-in catalogue
|
|
81
|
+
# ([`imported-built-in-types.md`](docs/type-specification/imported-built-in-types.md)).
|
|
93
82
|
def canonical_name
|
|
94
83
|
return nil unless base.is_a?(Nominal)
|
|
95
84
|
|
data/lib/rigor/type/dynamic.rb
CHANGED
|
@@ -6,11 +6,9 @@ require_relative "acceptance_router"
|
|
|
6
6
|
|
|
7
7
|
module Rigor
|
|
8
8
|
module Type
|
|
9
|
-
# The dynamic-origin wrapper: marks values whose type came from an
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# for the algebra and docs/type-specification/special-types.md for the
|
|
13
|
-
# untyped/Dynamic[T] relationship.
|
|
9
|
+
# The dynamic-origin wrapper: marks values whose type came from an unchecked source. Carries a static
|
|
10
|
+
# facet that records the analyzer's best static knowledge. See docs/type-specification/value-lattice.md
|
|
11
|
+
# for the algebra and docs/type-specification/special-types.md for the untyped/Dynamic[T] relationship.
|
|
14
12
|
#
|
|
15
13
|
# Construct via Rigor::Type::Combinator.dynamic(static_facet).
|
|
16
14
|
class Dynamic
|
|
@@ -7,20 +7,16 @@ require_relative "plain_lattice"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Type
|
|
10
|
-
# A hash shape with statically known keys. Inhabitants are Ruby
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# Rigor extends that carrier with optional keys, read-only entry
|
|
14
|
-
# views, and an open/closed extra-key policy.
|
|
10
|
+
# A hash shape with statically known keys. Inhabitants are Ruby `Hash` instances whose known entries
|
|
11
|
+
# inhabit the corresponding value types. RBS records correspond to the exact closed subset; Rigor
|
|
12
|
+
# extends that carrier with optional keys, read-only entry views, and an open/closed extra-key policy.
|
|
15
13
|
#
|
|
16
|
-
# Keys are restricted to Symbol and String values. Exact closed
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# `Hash[K, V]` or raw `Hash` when no useful bounds are available.
|
|
14
|
+
# Keys are restricted to Symbol and String values. Exact closed symbol-keyed shapes erase to the RBS
|
|
15
|
+
# record syntax `{ a: Integer, ?b: String }`; all other shapes degrade to `Hash[K, V]` or raw `Hash`
|
|
16
|
+
# when no useful bounds are available.
|
|
20
17
|
#
|
|
21
|
-
# Equality and hashing are structural over the (key -> Rigor::Type)
|
|
22
|
-
#
|
|
23
|
-
# the underlying storage but does NOT affect equality (matching
|
|
18
|
+
# Equality and hashing are structural over the (key -> Rigor::Type) pair set and policy fields. Hash
|
|
19
|
+
# insertion order is preserved by the underlying storage but does NOT affect equality (matching
|
|
24
20
|
# Ruby's `Hash#==`).
|
|
25
21
|
#
|
|
26
22
|
# See docs/type-specification/rbs-compatible-types.md (records) and
|
|
@@ -29,6 +25,9 @@ module Rigor
|
|
|
29
25
|
ALLOWED_KEY_CLASSES = [Symbol, String].freeze
|
|
30
26
|
EXTRA_KEY_POLICIES = %i[open closed].freeze
|
|
31
27
|
POLICY_KEYWORDS = %i[required_keys optional_keys read_only_keys extra_keys].freeze
|
|
28
|
+
# A Symbol whose text matches renders as a bare RBS record key (`lang:`) in {#erase_to_rbs};
|
|
29
|
+
# anything else must be quoted with a fat arrow (`"data-contrast" =>`). See {#erase_key_prefix}.
|
|
30
|
+
BARE_RECORD_KEY = /\A[A-Za-z_][A-Za-z0-9_]*[?!]?\z/
|
|
32
31
|
|
|
33
32
|
attr_reader :pairs, :required_keys, :optional_keys, :read_only_keys, :extra_keys
|
|
34
33
|
|
|
@@ -65,15 +64,14 @@ module Rigor
|
|
|
65
64
|
"{ #{rendered.join(', ')} }"
|
|
66
65
|
end
|
|
67
66
|
|
|
68
|
-
# Erases to the RBS record form `{ a: Integer, ?b: String }`
|
|
69
|
-
#
|
|
70
|
-
# string-keyed closed shapes degrade to a generic Hash bound.
|
|
67
|
+
# Erases to the RBS record form `{ a: Integer, ?b: String }` for exact closed symbol-keyed shapes.
|
|
68
|
+
# Open shapes and string-keyed closed shapes degrade to a generic Hash bound.
|
|
71
69
|
def erase_to_rbs
|
|
72
70
|
return "{}" if pairs.empty? && closed?
|
|
73
71
|
return hash_erasure unless closed?
|
|
74
72
|
return hash_erasure if pairs.each_key.any? { |k| !k.is_a?(Symbol) }
|
|
75
73
|
|
|
76
|
-
rendered = pairs.map { |k, v| "#{
|
|
74
|
+
rendered = pairs.map { |k, v| "#{erase_key_prefix(k)} #{v.erase_to_rbs}" }
|
|
77
75
|
"{ #{rendered.join(', ')} }"
|
|
78
76
|
end
|
|
79
77
|
|
|
@@ -196,6 +194,9 @@ module Rigor
|
|
|
196
194
|
"#{prefix.join(' ')} #{value.describe(verbosity)}"
|
|
197
195
|
end
|
|
198
196
|
|
|
197
|
+
# `describe` is a human-facing display contract (it feeds diagnostic messages, never a parser),
|
|
198
|
+
# so it keeps the compact `"a":` form for a quoted key. The RBS-erasure path uses
|
|
199
|
+
# {#erase_key_prefix} instead, which must emit a parseable key.
|
|
199
200
|
def render_key(key)
|
|
200
201
|
case key
|
|
201
202
|
when Symbol then key.to_s
|
|
@@ -203,8 +204,21 @@ module Rigor
|
|
|
203
204
|
end
|
|
204
205
|
end
|
|
205
206
|
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
# An RBS record entry's key + separator, for the {#erase_to_rbs} path (which only ever sees
|
|
208
|
+
# Symbol keys — string-keyed shapes degrade to `Hash[...]` before reaching here). A Symbol whose
|
|
209
|
+
# text is a plain identifier is a bare key with a colon (`lang:`); a hyphenated / punctuated
|
|
210
|
+
# Symbol MUST use the quoted `"data-contrast" =>` form, because RBS rejects both a bare
|
|
211
|
+
# non-identifier (`data-contrast:`) and a quoted key with a colon (`"data-contrast":`). Getting
|
|
212
|
+
# this wrong made sig-gen emit an unparseable Mastodon `html_attributes` shape that crashed the
|
|
213
|
+
# whole RBS env build. Valid identifier keys (incl. Ruby keywords like `class`) keep the colon
|
|
214
|
+
# form, so only genuinely non-identifier keys change. Optional keys carry a leading `?`.
|
|
215
|
+
def erase_key_prefix(key)
|
|
216
|
+
optional = optional_key?(key) ? "?" : ""
|
|
217
|
+
if BARE_RECORD_KEY.match?(key.to_s)
|
|
218
|
+
"#{optional}#{key}:"
|
|
219
|
+
else
|
|
220
|
+
"#{optional}#{key.to_s.inspect} =>"
|
|
221
|
+
end
|
|
208
222
|
end
|
|
209
223
|
|
|
210
224
|
def hash_erasure
|
|
@@ -7,23 +7,19 @@ require_relative "plain_lattice"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Type
|
|
10
|
-
# A bounded integer range carrier. Each bound is either an `Integer`
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# `positive-int` (
|
|
14
|
-
#
|
|
15
|
-
# carrier and are recovered in `describe` for human-friendly output.
|
|
10
|
+
# A bounded integer range carrier. Each bound is either an `Integer` or one of the symbolic
|
|
11
|
+
# infinities `:neg_infinity` / `:pos_infinity`. Inspired by PHPStan's `int<min, max>` family — the
|
|
12
|
+
# named aliases `positive-int` (1..), `non-negative-int` (0..), `negative-int` (..-1),
|
|
13
|
+
# `non-positive-int` (..0) all surface through this single carrier and are recovered in `describe`
|
|
14
|
+
# for human-friendly output.
|
|
16
15
|
#
|
|
17
16
|
# Constraints on construction:
|
|
18
|
-
# - both bounds must be either `Integer` or one of the two infinity
|
|
19
|
-
# sentinels;
|
|
17
|
+
# - both bounds must be either `Integer` or one of the two infinity sentinels;
|
|
20
18
|
# - if both bounds are concrete, `min <= max` must hold;
|
|
21
|
-
# - the universal case `(-∞, +∞)` is structurally distinct from
|
|
22
|
-
#
|
|
23
|
-
# keeps the carrier closed under range narrowing.
|
|
19
|
+
# - the universal case `(-∞, +∞)` is structurally distinct from `Nominal[Integer]` — it carries no
|
|
20
|
+
# extra information today but keeps the carrier closed under range narrowing.
|
|
24
21
|
#
|
|
25
|
-
# Erasure to RBS is always "Integer": RBS itself does not natively
|
|
26
|
-
# express bounded integer ranges.
|
|
22
|
+
# Erasure to RBS is always "Integer": RBS itself does not natively express bounded integer ranges.
|
|
27
23
|
class IntegerRange
|
|
28
24
|
NEG_INFINITY = :neg_infinity
|
|
29
25
|
POS_INFINITY = :pos_infinity
|
|
@@ -64,9 +60,8 @@ module Rigor
|
|
|
64
60
|
int.between?(lower, upper)
|
|
65
61
|
end
|
|
66
62
|
|
|
67
|
-
# Returns the lower bound as a numeric (with `-Float::INFINITY` for
|
|
68
|
-
#
|
|
69
|
-
# `:neg_infinity` directly with an `Integer`.
|
|
63
|
+
# Returns the lower bound as a numeric (with `-Float::INFINITY` for `:neg_infinity`). Use this in
|
|
64
|
+
# arithmetic comparisons; never compare `:neg_infinity` directly with an `Integer`.
|
|
70
65
|
def lower
|
|
71
66
|
m = min
|
|
72
67
|
return m if m.is_a?(Integer)
|
|
@@ -7,36 +7,28 @@ require_relative "plain_lattice"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Type
|
|
10
|
-
# `Intersection[M1, M2, …]` — value set is the meet of every
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# `
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# [`imported-built-in-types.md`](docs/type-specification/imported-built-in-types.md).
|
|
17
|
-
# See [ADR-3](docs/adr/3-type-representation.md) for the
|
|
18
|
-
# OQ3 working decision and the rationale for keeping
|
|
19
|
-
# Intersection a thin wrapper rather than per-shape carriers.
|
|
10
|
+
# `Intersection[M1, M2, …]` — value set is the meet of every member's value set. The carrier composes
|
|
11
|
+
# refinements that share a base, in particular the catalogued `non-empty-lowercase-string` (=
|
|
12
|
+
# `Difference[String, ""] & Refined[String, :lowercase]`) and `non-empty-uppercase-string` shapes
|
|
13
|
+
# from [`imported-built-in-types.md`](docs/type-specification/imported-built-in-types.md). See
|
|
14
|
+
# [ADR-3](docs/adr/3-type-representation.md) for the OQ3 working decision and the rationale for
|
|
15
|
+
# keeping Intersection a thin wrapper rather than per-shape carriers.
|
|
20
16
|
#
|
|
21
|
-
# Construction MUST go through `Type::Combinator.intersection`
|
|
22
|
-
#
|
|
23
|
-
# `Combinator.non_empty_lowercase_string` /
|
|
24
|
-
# `Combinator.non_empty_uppercase_string`). The factory:
|
|
17
|
+
# Construction MUST go through `Type::Combinator.intersection` (or the per-name factories
|
|
18
|
+
# `Combinator.non_empty_lowercase_string` / `Combinator.non_empty_uppercase_string`). The factory:
|
|
25
19
|
#
|
|
26
20
|
# - flattens nested intersections,
|
|
27
21
|
# - drops `Top` members (Top is the identity of intersection),
|
|
28
22
|
# - collapses to `Bot` if any member is `Bot` (Bot is absorbing),
|
|
29
23
|
# - deduplicates structurally-equal members,
|
|
30
|
-
# - sorts the surviving members by `describe(:short)` so two
|
|
31
|
-
#
|
|
32
|
-
# compare equal,
|
|
24
|
+
# - sorts the surviving members by `describe(:short)` so two structurally-equal intersections built
|
|
25
|
+
# in different orders compare equal,
|
|
33
26
|
# - returns `Top` for the empty intersection,
|
|
34
|
-
# - returns the lone member for a 1-element intersection (so
|
|
35
|
-
#
|
|
36
|
-
# shape).
|
|
27
|
+
# - returns the lone member for a 1-element intersection (so the carrier is never inhabited by a
|
|
28
|
+
# degenerate single-member shape).
|
|
37
29
|
#
|
|
38
|
-
# Direct `.new` callers MUST pass an already-normalised member
|
|
39
|
-
#
|
|
30
|
+
# Direct `.new` callers MUST pass an already-normalised member list and are expected to be tests or
|
|
31
|
+
# the combinator itself.
|
|
40
32
|
class Intersection
|
|
41
33
|
attr_reader :members
|
|
42
34
|
|
|
@@ -52,13 +44,10 @@ module Rigor
|
|
|
52
44
|
members.map { |m| m.describe(verbosity) }.join(" & ")
|
|
53
45
|
end
|
|
54
46
|
|
|
55
|
-
# An intersection of refinements over the same base type
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
# cross-base intersections will need a stricter erasure
|
|
60
|
-
# rule (likely "lowest common ancestor" via the inference
|
|
61
|
-
# engine's class hierarchy).
|
|
47
|
+
# An intersection of refinements over the same base type erases to that base. We use the first
|
|
48
|
+
# member's erasure because the v0.0.4 catalogue (`non-empty-lowercase-string` etc.) is restricted
|
|
49
|
+
# to same-base composition; richer cross-base intersections will need a stricter erasure rule
|
|
50
|
+
# (likely "lowest common ancestor" via the inference engine's class hierarchy).
|
|
62
51
|
def erase_to_rbs
|
|
63
52
|
members.first.erase_to_rbs
|
|
64
53
|
end
|
|
@@ -77,15 +66,13 @@ module Rigor
|
|
|
77
66
|
|
|
78
67
|
private
|
|
79
68
|
|
|
80
|
-
# Maps a structurally-recognised composite shape to its
|
|
81
|
-
#
|
|
82
|
-
# sync with the imported-built-in catalogue
|
|
69
|
+
# Maps a structurally-recognised composite shape to its kebab-case canonical name. The recognised
|
|
70
|
+
# set is kept in sync with the imported-built-in catalogue
|
|
83
71
|
# ([`imported-built-in-types.md`](docs/type-specification/imported-built-in-types.md)).
|
|
84
72
|
#
|
|
85
|
-
# Detection is order-independent — `Combinator.intersection`
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
# in any order) MUST still print in its canonical spelling.
|
|
73
|
+
# Detection is order-independent — `Combinator.intersection` sorts the canonical member list, but
|
|
74
|
+
# reading the registry the other way around (a user-authored Intersection built in any order) MUST
|
|
75
|
+
# still print in its canonical spelling.
|
|
89
76
|
def canonical_name
|
|
90
77
|
return nil unless members.size == 2
|
|
91
78
|
|
|
@@ -99,12 +86,10 @@ module Rigor
|
|
|
99
86
|
end
|
|
100
87
|
end
|
|
101
88
|
|
|
102
|
-
# Returns a stable role tag for the recognised composite
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
#
|
|
106
|
-
# any nil contribution disqualifies the canonical-name path
|
|
107
|
-
# and the operator-form fallback kicks in.
|
|
89
|
+
# Returns a stable role tag for the recognised composite members so `canonical_name` can
|
|
90
|
+
# pattern-match on a sorted role pair regardless of construction order. Returns nil when the
|
|
91
|
+
# member is not part of any catalogued composite — any nil contribution disqualifies the
|
|
92
|
+
# canonical-name path and the operator-form fallback kicks in.
|
|
108
93
|
def canonical_role(member)
|
|
109
94
|
case member
|
|
110
95
|
when Difference
|
data/lib/rigor/type/nominal.rb
CHANGED
|
@@ -7,23 +7,18 @@ require_relative "plain_lattice"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Type
|
|
10
|
-
# An instance type for a Ruby class or module. The class is identified by
|
|
11
|
-
#
|
|
12
|
-
# environment owns the class lookup.
|
|
10
|
+
# An instance type for a Ruby class or module. The class is identified by its fully-qualified Ruby
|
|
11
|
+
# name; the registry attached to the environment owns the class lookup.
|
|
13
12
|
#
|
|
14
|
-
# Slice 4 phase 2d adds `type_args`: an ordered, frozen array of
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# match, so the raw form and any applied form are intentionally
|
|
21
|
-
# distinct values. Acceptance routes treat the raw form leniently
|
|
22
|
-
# for backward compatibility with phase 2b call sites that have not
|
|
23
|
-
# yet learned to carry generics.
|
|
13
|
+
# Slice 4 phase 2d adds `type_args`: an ordered, frozen array of `Rigor::Type` values that carry the
|
|
14
|
+
# receiver's generic instantiation. The empty array is the canonical "raw" form (`Nominal[Array]`); a
|
|
15
|
+
# non-empty array represents an applied generic (`Nominal[Array, [Integer]]`). Two Nominals are
|
|
16
|
+
# structurally equal only when their `class_name` AND `type_args` match, so the raw form and any
|
|
17
|
+
# applied form are intentionally distinct values. Acceptance routes treat the raw form leniently for
|
|
18
|
+
# backward compatibility with phase 2b call sites that have not yet learned to carry generics.
|
|
24
19
|
#
|
|
25
|
-
# Type arguments MUST be `Rigor::Type` instances. The constructor
|
|
26
|
-
#
|
|
20
|
+
# Type arguments MUST be `Rigor::Type` instances. The constructor freezes the array; callers MUST NOT
|
|
21
|
+
# mutate it after construction.
|
|
27
22
|
#
|
|
28
23
|
# See docs/type-specification/rbs-compatible-types.md.
|
|
29
24
|
class Nominal
|
|
@@ -4,22 +4,18 @@ require_relative "../trinary"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Type
|
|
7
|
-
# Supplies the lattice-membership trio for the "plain" carriers — the
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# inner type.
|
|
7
|
+
# Supplies the lattice-membership trio for the "plain" carriers — the concrete value types that are
|
|
8
|
+
# neither a lattice extreme (`Top` / `Bot` / `Dynamic`) nor a wrapper that computes membership from
|
|
9
|
+
# an inner type.
|
|
11
10
|
#
|
|
12
|
-
# Every such carrier answers `top` / `bot` / `dynamic` with the same
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# `Dynamic#dynamic` answer `Trinary.yes`) and the delegators (`App`,
|
|
17
|
-
# `Difference`, `Refined`, `Union`) compute `dynamic` from their inner
|
|
11
|
+
# Every such carrier answers `top` / `bot` / `dynamic` with the same `Trinary.no` ("this value is not
|
|
12
|
+
# that lattice point"), so the trio lived as a byte-identical copy in a dozen carriers. The extremes
|
|
13
|
+
# override the relevant member (`Top#top` / `Bot#bot` / `Dynamic#dynamic` answer `Trinary.yes`) and
|
|
14
|
+
# the delegators (`App`, `Difference`, `Refined`, `Union`) compute `dynamic` from their inner
|
|
18
15
|
# type(s); none of those include this module.
|
|
19
16
|
#
|
|
20
|
-
# Mirrors the existing {AcceptanceRouter} / `ValueSemantics` mixins —
|
|
21
|
-
#
|
|
22
|
-
# contract forbids).
|
|
17
|
+
# Mirrors the existing {AcceptanceRouter} / `ValueSemantics` mixins — narrow trait sharing, never
|
|
18
|
+
# carrier inheritance (which the type-object contract forbids).
|
|
23
19
|
module PlainLattice
|
|
24
20
|
def top
|
|
25
21
|
Trinary.no
|