rigortype 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/15-type-protection-coverage.md +6 -4
- data/lib/rigor/analysis/baseline.rb +56 -96
- data/lib/rigor/analysis/buffer_binding.rb +13 -20
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
- data/lib/rigor/analysis/check_rules.rb +174 -274
- data/lib/rigor/analysis/dependency_recorder.rb +26 -38
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
- data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
- data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
- data/lib/rigor/analysis/diagnostic.rb +48 -75
- data/lib/rigor/analysis/erb_template_detector.rb +13 -18
- data/lib/rigor/analysis/fact_store.rb +12 -22
- data/lib/rigor/analysis/incremental.rb +47 -63
- data/lib/rigor/analysis/incremental_session.rb +74 -100
- data/lib/rigor/analysis/project_scan.rb +12 -23
- data/lib/rigor/analysis/result.rb +3 -5
- data/lib/rigor/analysis/rule_catalog.rb +67 -95
- data/lib/rigor/analysis/run_stats.rb +38 -61
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
- data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
- data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
- data/lib/rigor/analysis/runner.rb +220 -333
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
- data/lib/rigor/analysis/worker_session.rb +64 -102
- data/lib/rigor/ast/type_node.rb +6 -8
- data/lib/rigor/ast.rb +6 -10
- data/lib/rigor/bleeding_edge.rb +27 -35
- data/lib/rigor/builtins/hkt_builtins.rb +7 -14
- data/lib/rigor/builtins/imported_refinements.rb +106 -149
- data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
- data/lib/rigor/builtins/regex_refinement.rb +32 -43
- data/lib/rigor/builtins/static_return_refinements.rb +57 -81
- data/lib/rigor/cache/descriptor.rb +58 -94
- data/lib/rigor/cache/incremental_snapshot.rb +32 -48
- data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
- data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
- data/lib/rigor/cache/rbs_constant_table.rb +8 -13
- data/lib/rigor/cache/rbs_descriptor.rb +8 -13
- data/lib/rigor/cache/rbs_environment.rb +11 -19
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
- data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
- data/lib/rigor/cache/store.rb +96 -151
- data/lib/rigor/cli/annotate_command.rb +51 -88
- data/lib/rigor/cli/baseline_command.rb +10 -17
- data/lib/rigor/cli/check_command.rb +121 -199
- data/lib/rigor/cli/check_runner_factory.rb +8 -14
- data/lib/rigor/cli/ci_detector.rb +9 -14
- data/lib/rigor/cli/command.rb +8 -14
- data/lib/rigor/cli/coverage_command.rb +19 -26
- data/lib/rigor/cli/coverage_mutation.rb +14 -19
- data/lib/rigor/cli/coverage_report.rb +0 -2
- data/lib/rigor/cli/coverage_scan.rb +7 -11
- data/lib/rigor/cli/diagnostic_formats.rb +43 -62
- data/lib/rigor/cli/diff_command.rb +10 -20
- data/lib/rigor/cli/docs_command.rb +26 -40
- data/lib/rigor/cli/doctor_command.rb +8 -9
- data/lib/rigor/cli/explain_command.rb +4 -7
- data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
- data/lib/rigor/cli/fused_protection_report.rb +6 -8
- data/lib/rigor/cli/lsp_command.rb +11 -19
- data/lib/rigor/cli/mcp_command.rb +4 -6
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
- data/lib/rigor/cli/mutation_protection_report.rb +6 -9
- data/lib/rigor/cli/options.rb +11 -19
- data/lib/rigor/cli/plugin_command.rb +18 -30
- data/lib/rigor/cli/plugins_command.rb +29 -51
- data/lib/rigor/cli/plugins_renderer.rb +12 -20
- data/lib/rigor/cli/prism_colorizer.rb +13 -19
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +27 -17
- data/lib/rigor/cli/renderable.rb +4 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
- data/lib/rigor/cli/sig_gen_command.rb +14 -26
- data/lib/rigor/cli/skill_command.rb +30 -47
- data/lib/rigor/cli/skill_describe.rb +40 -64
- data/lib/rigor/cli/trace_command.rb +9 -16
- data/lib/rigor/cli/trace_renderer.rb +35 -51
- data/lib/rigor/cli/triage_command.rb +6 -10
- data/lib/rigor/cli/triage_renderer.rb +1 -2
- data/lib/rigor/cli/type_of_command.rb +14 -23
- data/lib/rigor/cli/type_of_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_command.rb +6 -10
- data/lib/rigor/cli/type_scan_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_report.rb +2 -3
- data/lib/rigor/cli/upgrade_command.rb +2 -3
- data/lib/rigor/cli.rb +16 -28
- data/lib/rigor/config_audit.rb +35 -44
- data/lib/rigor/configuration/dependencies.rb +41 -70
- data/lib/rigor/configuration/severity_profile.rb +28 -42
- data/lib/rigor/configuration.rb +150 -241
- data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
- data/lib/rigor/environment/class_registry.rb +19 -26
- data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
- data/lib/rigor/environment/lockfile_resolver.rb +31 -47
- data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
- data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
- data/lib/rigor/environment/rbs_loader.rb +420 -518
- data/lib/rigor/environment/reflection.rb +28 -53
- data/lib/rigor/environment/reporters.rb +13 -24
- data/lib/rigor/environment.rb +176 -291
- data/lib/rigor/flow_contribution/conflict.rb +16 -27
- data/lib/rigor/flow_contribution/element.rb +7 -12
- data/lib/rigor/flow_contribution/fact.rb +33 -57
- data/lib/rigor/flow_contribution/merge_result.rb +6 -9
- data/lib/rigor/flow_contribution/merger.rb +32 -47
- data/lib/rigor/flow_contribution.rb +37 -55
- data/lib/rigor/inference/acceptance.rb +133 -219
- data/lib/rigor/inference/block_parameter_binder.rb +52 -82
- data/lib/rigor/inference/body_fixpoint.rb +22 -30
- data/lib/rigor/inference/budget_trace.rb +43 -63
- data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
- data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
- data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
- data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
- data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
- data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
- data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
- data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
- data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
- data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
- data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
- data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
- data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
- data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
- data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
- data/lib/rigor/inference/coverage_scanner.rb +13 -18
- data/lib/rigor/inference/def_return_typer.rb +8 -14
- data/lib/rigor/inference/dynamic_origin.rb +23 -20
- data/lib/rigor/inference/expression_typer.rb +774 -1152
- data/lib/rigor/inference/fallback.rb +8 -12
- data/lib/rigor/inference/fallback_tracer.rb +4 -10
- data/lib/rigor/inference/flow_tracer.rb +25 -36
- data/lib/rigor/inference/hkt_body.rb +45 -68
- data/lib/rigor/inference/hkt_body_parser.rb +33 -52
- data/lib/rigor/inference/hkt_reducer.rb +38 -59
- data/lib/rigor/inference/hkt_registry.rb +50 -76
- data/lib/rigor/inference/indexed_narrowing.rb +55 -81
- data/lib/rigor/inference/macro_block_self_type.rb +21 -34
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
- data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
- data/lib/rigor/inference/method_dispatcher.rb +378 -524
- data/lib/rigor/inference/method_parameter_binder.rb +81 -114
- data/lib/rigor/inference/multi_target_binder.rb +51 -68
- data/lib/rigor/inference/mutation_widening.rb +115 -158
- data/lib/rigor/inference/narrowing.rb +509 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
- data/lib/rigor/inference/precision_scanner.rb +26 -35
- data/lib/rigor/inference/project_patched_methods.rb +20 -32
- data/lib/rigor/inference/project_patched_scanner.rb +23 -37
- data/lib/rigor/inference/protection_scanner.rb +16 -18
- data/lib/rigor/inference/rbs_type_translator.rb +49 -66
- data/lib/rigor/inference/scope_indexer.rb +473 -817
- data/lib/rigor/inference/statement_evaluator.rb +706 -1111
- data/lib/rigor/inference/struct_fold_safety.rb +34 -48
- data/lib/rigor/inference/synthetic_method.rb +9 -16
- data/lib/rigor/inference/synthetic_method_index.rb +20 -35
- data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
- data/lib/rigor/language_server/buffer_resolution.rb +6 -9
- data/lib/rigor/language_server/buffer_table.rb +11 -18
- data/lib/rigor/language_server/completion_provider.rb +69 -116
- data/lib/rigor/language_server/debouncer.rb +16 -25
- data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
- data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
- data/lib/rigor/language_server/folding_range_provider.rb +11 -19
- data/lib/rigor/language_server/hover_provider.rb +8 -11
- data/lib/rigor/language_server/hover_renderer.rb +56 -93
- data/lib/rigor/language_server/loop.rb +14 -19
- data/lib/rigor/language_server/project_context.rb +46 -74
- data/lib/rigor/language_server/selection_range_provider.rb +9 -12
- data/lib/rigor/language_server/server.rb +55 -83
- data/lib/rigor/language_server/signature_help_provider.rb +29 -46
- data/lib/rigor/language_server/synchronized_writer.rb +4 -7
- data/lib/rigor/language_server/uri.rb +8 -13
- data/lib/rigor/language_server.rb +4 -6
- data/lib/rigor/mcp/loop.rb +2 -3
- data/lib/rigor/mcp/server.rb +4 -7
- data/lib/rigor/mcp.rb +3 -6
- data/lib/rigor/plugin/access_denied_error.rb +5 -8
- data/lib/rigor/plugin/additional_initializer.rb +21 -31
- data/lib/rigor/plugin/base.rb +335 -518
- data/lib/rigor/plugin/blueprint.rb +14 -23
- data/lib/rigor/plugin/box.rb +18 -29
- data/lib/rigor/plugin/fact_store.rb +16 -26
- data/lib/rigor/plugin/inflector.rb +37 -53
- data/lib/rigor/plugin/io_boundary.rb +33 -56
- data/lib/rigor/plugin/isolation.rb +42 -55
- data/lib/rigor/plugin/load_error.rb +10 -15
- data/lib/rigor/plugin/loader.rb +30 -49
- data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
- data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
- data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
- data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
- data/lib/rigor/plugin/macro.rb +10 -15
- data/lib/rigor/plugin/manifest.rb +85 -144
- data/lib/rigor/plugin/node_context.rb +14 -22
- data/lib/rigor/plugin/node_rule_walk.rb +49 -74
- data/lib/rigor/plugin/protocol_contract.rb +25 -39
- data/lib/rigor/plugin/registry.rb +132 -205
- data/lib/rigor/plugin/services.rb +21 -33
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
- data/lib/rigor/plugin/trust_policy.rb +24 -38
- data/lib/rigor/plugin/type_node_resolver.rb +15 -24
- data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
- data/lib/rigor/protection/mutation_scanner.rb +27 -35
- data/lib/rigor/protection/mutator.rb +50 -70
- data/lib/rigor/protection/test_suite_oracle.rb +20 -27
- data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
- data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
- data/lib/rigor/rbs_extended/reporter.rb +24 -40
- data/lib/rigor/rbs_extended.rb +107 -197
- data/lib/rigor/reflection.rb +68 -86
- data/lib/rigor/scope/discovery_index.rb +14 -19
- data/lib/rigor/scope.rb +255 -310
- data/lib/rigor/sig_gen/classification.rb +6 -10
- data/lib/rigor/sig_gen/generator.rb +197 -323
- data/lib/rigor/sig_gen/layout_index.rb +12 -20
- data/lib/rigor/sig_gen/method_candidate.rb +12 -17
- data/lib/rigor/sig_gen/observation_collector.rb +38 -70
- data/lib/rigor/sig_gen/observed_call.rb +13 -23
- data/lib/rigor/sig_gen/path_mapper.rb +17 -29
- data/lib/rigor/sig_gen/renderer.rb +7 -13
- data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
- data/lib/rigor/sig_gen/write_result.rb +8 -16
- data/lib/rigor/sig_gen/writer.rb +95 -174
- data/lib/rigor/sig_gen.rb +3 -6
- data/lib/rigor/signature_path_audit.rb +24 -30
- data/lib/rigor/source/constant_path.rb +10 -14
- data/lib/rigor/source/literals.rb +31 -45
- data/lib/rigor/source/node_locator.rb +9 -11
- data/lib/rigor/source/node_walker.rb +9 -13
- data/lib/rigor/source.rb +3 -4
- data/lib/rigor/testing.rb +16 -20
- data/lib/rigor/triage/catalogue.rb +38 -62
- data/lib/rigor/triage.rb +31 -52
- data/lib/rigor/trinary.rb +9 -13
- data/lib/rigor/type/acceptance_router.rb +4 -6
- data/lib/rigor/type/accepts_result.rb +10 -14
- data/lib/rigor/type/app.rb +19 -27
- data/lib/rigor/type/bot.rb +4 -6
- data/lib/rigor/type/bound_method.rb +10 -15
- data/lib/rigor/type/combinator.rb +165 -257
- data/lib/rigor/type/constant.rb +23 -34
- data/lib/rigor/type/data_class.rb +10 -15
- data/lib/rigor/type/data_instance.rb +14 -20
- data/lib/rigor/type/difference.rb +21 -32
- data/lib/rigor/type/dynamic.rb +3 -5
- data/lib/rigor/type/hash_shape.rb +32 -18
- data/lib/rigor/type/integer_range.rb +11 -16
- data/lib/rigor/type/intersection.rb +27 -42
- data/lib/rigor/type/nominal.rb +10 -15
- data/lib/rigor/type/plain_lattice.rb +9 -13
- data/lib/rigor/type/refined.rb +67 -114
- data/lib/rigor/type/singleton.rb +4 -6
- data/lib/rigor/type/struct_class.rb +11 -16
- data/lib/rigor/type/struct_instance.rb +15 -21
- data/lib/rigor/type/tuple.rb +14 -19
- data/lib/rigor/type/union.rb +30 -42
- data/lib/rigor/type_node/generic.rb +14 -26
- data/lib/rigor/type_node/identifier.rb +12 -19
- data/lib/rigor/type_node.rb +3 -12
- data/lib/rigor/value_semantics.rb +16 -21
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
- data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
- data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
- data/sig/rigor/scope.rbs +6 -0
- metadata +2 -1
|
@@ -7,42 +7,33 @@ require_relative "../type_node"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Builtins
|
|
10
|
-
# Canonical-name registry for the imported-built-in
|
|
11
|
-
#
|
|
12
|
-
# in `docs/type-specification/` for the full catalogue
|
|
10
|
+
# Canonical-name registry for the imported-built-in refinement catalogue. See
|
|
11
|
+
# `imported-built-in-types.md` in `docs/type-specification/` for the full catalogue
|
|
13
12
|
# rationale and the kebab-case naming rule.
|
|
14
13
|
#
|
|
15
|
-
# Maps kebab-case names (`non-empty-string`, `positive-int`,
|
|
16
|
-
#
|
|
17
|
-
# The registry is the single integration point for:
|
|
14
|
+
# Maps kebab-case names (`non-empty-string`, `positive-int`, `non-empty-array`, …) to the
|
|
15
|
+
# Rigor type each name denotes. The registry is the single integration point for:
|
|
18
16
|
#
|
|
19
17
|
# - The `rigor:v1:return:` RBS::Extended directive
|
|
20
|
-
# ([`Rigor::RbsExtended.read_return_type_override`](../rbs_extended.rb)),
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# - The display side: `Type::Difference#describe` already
|
|
27
|
-
# recognises the same shapes and prints the kebab-case
|
|
28
|
-
# spelling without consulting the registry.
|
|
18
|
+
# ([`Rigor::RbsExtended.read_return_type_override`](../rbs_extended.rb)), which overrides
|
|
19
|
+
# a method's RBS-declared return type with a refinement carrier.
|
|
20
|
+
# - Future `RBS::Extended` directives that accept a refinement name in any type position
|
|
21
|
+
# (`param:`, `assert: x is non-empty-string`, …).
|
|
22
|
+
# - The display side: `Type::Difference#describe` already recognises the same shapes and
|
|
23
|
+
# prints the kebab-case spelling without consulting the registry.
|
|
29
24
|
#
|
|
30
|
-
# Names not in the registry resolve to `nil`; callers
|
|
31
|
-
#
|
|
32
|
-
# raise a parse error.
|
|
25
|
+
# Names not in the registry resolve to `nil`; callers decide whether to fall back to the
|
|
26
|
+
# RBS-declared type or raise a parse error.
|
|
33
27
|
#
|
|
34
28
|
# The registry covers two surfaces:
|
|
35
29
|
#
|
|
36
|
-
# - **No-argument refinement names** (`non-empty-string`,
|
|
37
|
-
# `
|
|
38
|
-
# and resolve through `lookup(name)`.
|
|
30
|
+
# - **No-argument refinement names** (`non-empty-string`, `non-zero-int`,
|
|
31
|
+
# `lowercase-string`, …) live in `REGISTRY` and resolve through `lookup(name)`.
|
|
39
32
|
# - **Parameterised refinement payloads** (`non-empty-array[Integer]`,
|
|
40
|
-
# `non-empty-hash[Symbol, Integer]`, `int<5, 10>`) are
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
# `PARAMETERISED_TYPE_BUILDERS` (square-bracket form, type
|
|
45
|
-
# args) and `PARAMETERISED_INT_BUILDERS` (angle-bracket form,
|
|
33
|
+
# `non-empty-hash[Symbol, Integer]`, `int<5, 10>`) are accepted by `parse(payload)`. The
|
|
34
|
+
# full grammar is documented on `Parser`. The two surfaces share `REGISTRY` for the
|
|
35
|
+
# no-arg head names; the parameterised head names live in `PARAMETERISED_TYPE_BUILDERS`
|
|
36
|
+
# (square-bracket form, type args) and `PARAMETERISED_INT_BUILDERS` (angle-bracket form,
|
|
46
37
|
# integer bounds).
|
|
47
38
|
module ImportedRefinements
|
|
48
39
|
REGISTRY = {
|
|
@@ -70,10 +61,9 @@ module Rigor
|
|
|
70
61
|
}.freeze
|
|
71
62
|
private_constant :REGISTRY
|
|
72
63
|
|
|
73
|
-
# `name[T]` / `name[K, V]` — type-arg parameterised
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
# mismatch so the caller surfaces a parse failure).
|
|
64
|
+
# `name[T]` / `name[K, V]` — type-arg parameterised refinements. Each builder takes an
|
|
65
|
+
# `Array<Rigor::Type>` and returns a `Rigor::Type` (or `nil` on arity / shape mismatch
|
|
66
|
+
# so the caller surfaces a parse failure).
|
|
77
67
|
PARAMETERISED_TYPE_BUILDERS = {
|
|
78
68
|
"non-empty-array" => lambda { |args|
|
|
79
69
|
return nil unless args.size == 1
|
|
@@ -85,12 +75,10 @@ module Rigor
|
|
|
85
75
|
|
|
86
76
|
Type::Combinator.non_empty_hash(args[0], args[1])
|
|
87
77
|
},
|
|
88
|
-
# v0.0.7 — `key_of[T]` and `value_of[T]` type functions.
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
# rules. Use `lower_snake` per the
|
|
93
|
-
# imported-built-in-types.md type-function naming rule.
|
|
78
|
+
# v0.0.7 — `key_of[T]` and `value_of[T]` type functions. Each takes a single type
|
|
79
|
+
# argument and projects the known-keys (resp. known-values) union out of `T`. See
|
|
80
|
+
# `Type::Combinator.key_of` for the per-shape projection rules. Use `lower_snake` per
|
|
81
|
+
# the imported-built-in-types.md type-function naming rule.
|
|
94
82
|
"key_of" => lambda { |args|
|
|
95
83
|
return nil unless args.size == 1
|
|
96
84
|
|
|
@@ -101,32 +89,27 @@ module Rigor
|
|
|
101
89
|
|
|
102
90
|
Type::Combinator.value_of(args.first)
|
|
103
91
|
},
|
|
104
|
-
# `int_mask[1, 2, 4]` — every integer representable by
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
# for this purpose. Builder declines on any non-integer
|
|
108
|
-
# arg.
|
|
92
|
+
# `int_mask[1, 2, 4]` — every integer representable by a bitwise OR over the listed
|
|
93
|
+
# flags. Each arg must be a `Constant<Integer>`; the parser wraps integer literals for
|
|
94
|
+
# this purpose. Builder declines on any non-integer arg.
|
|
109
95
|
"int_mask" => lambda { |args|
|
|
110
96
|
flags = args.map { |arg| arg.is_a?(Type::Constant) && arg.value.is_a?(Integer) ? arg.value : nil }
|
|
111
97
|
return nil if flags.any?(&:nil?)
|
|
112
98
|
|
|
113
99
|
Type::Combinator.int_mask(flags)
|
|
114
100
|
},
|
|
115
|
-
# `int_mask_of[T]` — derives the closure from a finite
|
|
116
|
-
#
|
|
117
|
-
# Union of them).
|
|
101
|
+
# `int_mask_of[T]` — derives the closure from a finite integer literal type (single
|
|
102
|
+
# Constant<Integer> or a Union of them).
|
|
118
103
|
"int_mask_of" => lambda { |args|
|
|
119
104
|
return nil unless args.size == 1
|
|
120
105
|
|
|
121
106
|
Type::Combinator.int_mask_of(args.first)
|
|
122
107
|
},
|
|
123
|
-
# ADR-13 § "Canonical type-function additions" — five
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
# inputs return the input unchanged (the lossy-projection
|
|
129
|
-
# diagnostic lands in slice 5).
|
|
108
|
+
# ADR-13 § "Canonical type-function additions" — five shape-projection type functions
|
|
109
|
+
# that the `rigor-typescript-utility-types` plugin (and any other plugin that ships a
|
|
110
|
+
# shape-projection vocabulary) maps onto. Phase A handles `HashShape` carriers;
|
|
111
|
+
# non-shape inputs return the input unchanged (the lossy-projection diagnostic lands
|
|
112
|
+
# in slice 5).
|
|
130
113
|
"pick_of" => lambda { |args|
|
|
131
114
|
return nil unless args.size == 2
|
|
132
115
|
|
|
@@ -155,12 +138,10 @@ module Rigor
|
|
|
155
138
|
}.freeze
|
|
156
139
|
private_constant :PARAMETERISED_TYPE_BUILDERS
|
|
157
140
|
|
|
158
|
-
# `name<min, max>` — integer-bound parameterised
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
# to construct successfully (`Type::IntegerRange` enforces
|
|
163
|
-
# the invariant).
|
|
141
|
+
# `name<min, max>` — integer-bound parameterised refinements. Each builder takes an
|
|
142
|
+
# `Array<Integer>` and returns a `Rigor::Type` (or `nil`). Bounds are signed integer
|
|
143
|
+
# literals; `min` MUST be ≤ `max` for the carrier to construct successfully
|
|
144
|
+
# (`Type::IntegerRange` enforces the invariant).
|
|
164
145
|
PARAMETERISED_INT_BUILDERS = {
|
|
165
146
|
"int" => lambda { |bounds|
|
|
166
147
|
return nil unless bounds.size == 2
|
|
@@ -173,39 +154,32 @@ module Rigor
|
|
|
173
154
|
module_function
|
|
174
155
|
|
|
175
156
|
# @param name [String] kebab-case refinement name.
|
|
176
|
-
# @return [Rigor::Type, nil] the matching refinement
|
|
177
|
-
#
|
|
157
|
+
# @return [Rigor::Type, nil] the matching refinement carrier, or `nil` if the name is
|
|
158
|
+
# not registered.
|
|
178
159
|
def lookup(name)
|
|
179
160
|
builder = REGISTRY[name.to_s]
|
|
180
161
|
builder&.call
|
|
181
162
|
end
|
|
182
163
|
|
|
183
|
-
# @param payload [String] the trailing payload of a
|
|
184
|
-
# `
|
|
185
|
-
# the bare-name forms `lookup` already handles plus the
|
|
164
|
+
# @param payload [String] the trailing payload of a `rigor:v1:return:` (or sibling)
|
|
165
|
+
# directive. Accepts the bare-name forms `lookup` already handles plus the
|
|
186
166
|
# parameterised forms documented on {Parser}.
|
|
187
167
|
# @param name_scope [Rigor::TypeNode::NameScope, nil]
|
|
188
|
-
# ADR-13 slice 3 — when provided, the parser consults the
|
|
189
|
-
#
|
|
190
|
-
#
|
|
191
|
-
#
|
|
192
|
-
# behaviour of consulting only built-ins + RBS.
|
|
168
|
+
# ADR-13 slice 3 — when provided, the parser consults the scope's `#resolver` chain
|
|
169
|
+
# after the built-in registry and built-in parametric forms but before the RBS
|
|
170
|
+
# Nominal fallback. `nil` (default) preserves the slice-1 / slice-2 behaviour of
|
|
171
|
+
# consulting only built-ins + RBS.
|
|
193
172
|
# @param reporter [Rigor::RbsExtended::Reporter, nil]
|
|
194
|
-
# ADR-13 slice 3b — collector that the Resolver feeds
|
|
195
|
-
#
|
|
196
|
-
#
|
|
197
|
-
#
|
|
198
|
-
#
|
|
199
|
-
#
|
|
200
|
-
#
|
|
201
|
-
# pre-slice-3b silent fall-through.
|
|
202
|
-
# @param source_location [RBS::Location, nil] location
|
|
203
|
-
# attribution for the events the Resolver records. Carries
|
|
204
|
-
# the annotation's filename / line / column so the runner
|
|
173
|
+
# ADR-13 slice 3b — collector that the Resolver feeds `dynamic.shape.lossy-projection`
|
|
174
|
+
# events into when a shape-projection head (`pick_of`, `omit_of`, `partial_of`,
|
|
175
|
+
# `required_of`, `readonly_of`) is applied to a carrier that does not preserve shape
|
|
176
|
+
# information. `nil` (default) suppresses event accumulation; legacy call sites that
|
|
177
|
+
# have no reporter to thread keep the pre-slice-3b silent fall-through.
|
|
178
|
+
# @param source_location [RBS::Location, nil] location attribution for the events the
|
|
179
|
+
# Resolver records. Carries the annotation's filename / line / column so the runner
|
|
205
180
|
# can stamp diagnostics with the user-visible source site.
|
|
206
|
-
# @return [Rigor::Type, nil] the resolved refinement
|
|
207
|
-
#
|
|
208
|
-
# names a refinement / class no registered source resolved.
|
|
181
|
+
# @return [Rigor::Type, nil] the resolved refinement carrier, or `nil` when the payload
|
|
182
|
+
# is unparseable or names a refinement / class no registered source resolved.
|
|
209
183
|
def parse(payload, name_scope: nil, reporter: nil, source_location: nil)
|
|
210
184
|
Parser.new(
|
|
211
185
|
payload.to_s,
|
|
@@ -251,16 +225,14 @@ module Rigor
|
|
|
251
225
|
#
|
|
252
226
|
# Whitespace between tokens is ignored. The parser fails
|
|
253
227
|
# soft (returns `nil` from `parse`) on any deviation so the
|
|
254
|
-
# `RBS::Extended` directive site can fall back to the
|
|
255
|
-
#
|
|
228
|
+
# `RBS::Extended` directive site can fall back to the RBS-declared type rather than
|
|
229
|
+
# crash on a typo.
|
|
256
230
|
#
|
|
257
|
-
# ADR-13 slice 3 split the original "scan + resolve" loop
|
|
258
|
-
#
|
|
259
|
-
#
|
|
260
|
-
# {Rigor::
|
|
261
|
-
#
|
|
262
|
-
# the RBS Nominal fallback in that order. Plugin resolvers
|
|
263
|
-
# never see partial parses.
|
|
231
|
+
# ADR-13 slice 3 split the original "scan + resolve" loop into two passes: the parser
|
|
232
|
+
# emits a {Rigor::TypeNode} AST, and a sibling {Resolver} walks the AST to produce a
|
|
233
|
+
# {Rigor::Type} carrier — consulting the built-in registry, the plugin
|
|
234
|
+
# {Rigor::TypeNode::ResolverChain}, and finally the RBS Nominal fallback in that order.
|
|
235
|
+
# Plugin resolvers never see partial parses.
|
|
264
236
|
class Parser
|
|
265
237
|
def initialize(input, name_scope: nil, reporter: nil, source_location: nil)
|
|
266
238
|
@scanner = StringScanner.new(input.strip)
|
|
@@ -275,11 +247,10 @@ module Rigor
|
|
|
275
247
|
ast = parse_type_ast
|
|
276
248
|
return nil if ast.nil?
|
|
277
249
|
|
|
278
|
-
# v0.0.7 — trailing `[K]` indexed-access projects into
|
|
279
|
-
#
|
|
280
|
-
#
|
|
281
|
-
#
|
|
282
|
-
# composes cleanly through the resolver pass.
|
|
250
|
+
# v0.0.7 — trailing `[K]` indexed-access projects into the parsed type. Multiple
|
|
251
|
+
# `[K]` segments chain (`Tuple[A, B, C][1][0]`). Each segment wraps the previous AST
|
|
252
|
+
# in an {IndexedAccess} node so the chain composes cleanly through the resolver
|
|
253
|
+
# pass.
|
|
283
254
|
ast = parse_indexed_access_chain_ast(ast)
|
|
284
255
|
return nil if ast.nil?
|
|
285
256
|
return nil unless @scanner.eos?
|
|
@@ -289,21 +260,17 @@ module Rigor
|
|
|
289
260
|
|
|
290
261
|
private
|
|
291
262
|
|
|
292
|
-
# Refinement names use kebab-case (`non-empty-string`),
|
|
293
|
-
#
|
|
294
|
-
#
|
|
295
|
-
# the registry lookup decides which family the name
|
|
296
|
-
# belongs to.
|
|
263
|
+
# Refinement names use kebab-case (`non-empty-string`), type-function names use
|
|
264
|
+
# lower_snake (`key_of`, `value_of`, `int_mask`). The regex accepts both shapes; the
|
|
265
|
+
# registry lookup decides which family the name belongs to.
|
|
297
266
|
SIMPLE_NAME = /[a-z][a-z0-9_-]*/
|
|
298
267
|
CLASS_NAME = /[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*/
|
|
299
268
|
SIGNED_INT = /-?\d+/
|
|
300
|
-
# ADR-13 follow-up — literal-key tokens at type-arg
|
|
301
|
-
#
|
|
302
|
-
#
|
|
303
|
-
#
|
|
304
|
-
#
|
|
305
|
-
# capture lets the parser pull the inner text without
|
|
306
|
-
# post-stripping the delimiter.
|
|
269
|
+
# ADR-13 follow-up — literal-key tokens at type-arg position. Symbol literals match
|
|
270
|
+
# Ruby's bare-symbol identifier shape (`:name`); string literals are double-quoted
|
|
271
|
+
# without escape sequences (the most common TS-style key-union shape). The
|
|
272
|
+
# `?<value>` capture lets the parser pull the inner text without post-stripping the
|
|
273
|
+
# delimiter.
|
|
307
274
|
SYMBOL_LITERAL = /:(?<value>[a-zA-Z_][a-zA-Z0-9_]*[?!=]?)/
|
|
308
275
|
STRING_LITERAL = /"(?<value>[^"\\]*)"/
|
|
309
276
|
private_constant :SIMPLE_NAME, :CLASS_NAME, :SIGNED_INT, :SYMBOL_LITERAL, :STRING_LITERAL
|
|
@@ -431,10 +398,9 @@ module Rigor
|
|
|
431
398
|
end
|
|
432
399
|
end
|
|
433
400
|
|
|
434
|
-
# Class-name-headed type argument with optional `[T_1,
|
|
435
|
-
#
|
|
436
|
-
#
|
|
437
|
-
# nominal carrier rather than rejecting the inner brackets.
|
|
401
|
+
# Class-name-headed type argument with optional `[T_1, …]` type-args tail. Used so
|
|
402
|
+
# `key_of[Hash[Symbol, Integer]]` parses as the projection of a parameterised nominal
|
|
403
|
+
# carrier rather than rejecting the inner brackets.
|
|
438
404
|
def parse_class_arg_tail_ast(class_name)
|
|
439
405
|
return TypeNode::Identifier.new(name: class_name) unless @scanner.peek(1) == "["
|
|
440
406
|
|
|
@@ -460,8 +426,8 @@ module Rigor
|
|
|
460
426
|
end
|
|
461
427
|
private_constant :Parser
|
|
462
428
|
|
|
463
|
-
# AST → {Rigor::Type} resolver. ADR-13's resolution order
|
|
464
|
-
#
|
|
429
|
+
# AST → {Rigor::Type} resolver. ADR-13's resolution order for every named-type
|
|
430
|
+
# production:
|
|
465
431
|
#
|
|
466
432
|
# 1. Built-in `ImportedRefinements.lookup` (no-arg
|
|
467
433
|
# refinements like `non-empty-string`).
|
|
@@ -473,16 +439,14 @@ module Rigor
|
|
|
473
439
|
# 4. RBS Nominal fallback for class-shaped names
|
|
474
440
|
# (PascalCase head, with or without type args).
|
|
475
441
|
#
|
|
476
|
-
# Returns `nil` when every step declined — preserves the
|
|
477
|
-
#
|
|
478
|
-
# RBS-declared type instead of raising.
|
|
442
|
+
# Returns `nil` when every step declined — preserves the parser's fail-soft contract so
|
|
443
|
+
# callers fall back to the RBS-declared type instead of raising.
|
|
479
444
|
class Resolver
|
|
480
|
-
# ADR-13 slice 3b — heads that consume a shape-bearing
|
|
481
|
-
#
|
|
482
|
-
#
|
|
483
|
-
#
|
|
484
|
-
#
|
|
485
|
-
# event on the reporter (if any).
|
|
445
|
+
# ADR-13 slice 3b — heads that consume a shape-bearing first argument. When the first
|
|
446
|
+
# arg is not a `HashShape` / `Tuple` (per
|
|
447
|
+
# {Rigor::Type::Combinator.shape_projection_lossy?}), the projection degrades to
|
|
448
|
+
# "input unchanged" and the Resolver records a `dynamic.shape.lossy-projection` event
|
|
449
|
+
# on the reporter (if any).
|
|
486
450
|
SHAPE_PROJECTION_HEADS = %w[pick_of omit_of partial_of required_of readonly_of].freeze
|
|
487
451
|
private_constant :SHAPE_PROJECTION_HEADS
|
|
488
452
|
|
|
@@ -494,10 +458,9 @@ module Rigor
|
|
|
494
458
|
@source_location = source_location
|
|
495
459
|
end
|
|
496
460
|
|
|
497
|
-
# ADR-13 follow-up — every leaf-literal AST node
|
|
498
|
-
#
|
|
499
|
-
#
|
|
500
|
-
# `Constant<value>` carrier through the same helper.
|
|
461
|
+
# ADR-13 follow-up — every leaf-literal AST node (`IntegerLiteral` / `SymbolLiteral` /
|
|
462
|
+
# `StringLiteral`) carries a Ruby value that lifts directly to a `Constant<value>`
|
|
463
|
+
# carrier through the same helper.
|
|
501
464
|
LITERAL_AST_NODES = [
|
|
502
465
|
TypeNode::IntegerLiteral, TypeNode::SymbolLiteral, TypeNode::StringLiteral
|
|
503
466
|
].freeze
|
|
@@ -513,13 +476,11 @@ module Rigor
|
|
|
513
476
|
end
|
|
514
477
|
end
|
|
515
478
|
|
|
516
|
-
# ADR-13 follow-up — resolves each node recursively and
|
|
517
|
-
#
|
|
518
|
-
#
|
|
519
|
-
#
|
|
520
|
-
#
|
|
521
|
-
# RBS-declared type rather than a half-resolved Union
|
|
522
|
-
# carrier.
|
|
479
|
+
# ADR-13 follow-up — resolves each node recursively and folds into a
|
|
480
|
+
# `Type::Combinator.union(...)`. When any node resolves to `nil` (unknown name,
|
|
481
|
+
# plugin decline, RBS Nominal fallback miss), the whole union collapses to `nil` so
|
|
482
|
+
# the caller falls back to the underlying RBS-declared type rather than a
|
|
483
|
+
# half-resolved Union carrier.
|
|
523
484
|
def resolve_union(node)
|
|
524
485
|
resolved = node.nodes.map { |child| resolve_ast(child) }
|
|
525
486
|
return nil if resolved.any?(&:nil?)
|
|
@@ -527,14 +488,12 @@ module Rigor
|
|
|
527
488
|
Type::Combinator.union(*resolved)
|
|
528
489
|
end
|
|
529
490
|
|
|
530
|
-
# Public {Rigor::Plugin::TypeNodeResolver}-shaped interface
|
|
531
|
-
#
|
|
532
|
-
#
|
|
533
|
-
#
|
|
534
|
-
#
|
|
535
|
-
#
|
|
536
|
-
# just back through the chain. The `_scope` argument is
|
|
537
|
-
# ignored — the Resolver owns the scope state internally.
|
|
491
|
+
# Public {Rigor::Plugin::TypeNodeResolver}-shaped interface so a
|
|
492
|
+
# {Rigor::TypeNode::NameScope} can point its `#resolver` at the Resolver itself.
|
|
493
|
+
# Plugin resolvers call `scope.resolver.resolve(arg, scope)` to recursively resolve a
|
|
494
|
+
# nested argument through the FULL pass (built-in registry → plugin chain → RBS
|
|
495
|
+
# fallback), not just back through the chain. The `_scope` argument is ignored — the
|
|
496
|
+
# Resolver owns the scope state internally.
|
|
538
497
|
def resolve(node, _scope)
|
|
539
498
|
resolve_ast(node)
|
|
540
499
|
end
|
|
@@ -599,13 +558,11 @@ module Rigor
|
|
|
599
558
|
result
|
|
600
559
|
end
|
|
601
560
|
|
|
602
|
-
# ADR-13 slice 3b — record one `dynamic.shape.lossy-projection`
|
|
603
|
-
#
|
|
604
|
-
#
|
|
605
|
-
#
|
|
606
|
-
# `
|
|
607
|
-
# HashShape-only `partial_of` / `required_of` /
|
|
608
|
-
# `readonly_of`), so detection is "first arg was lossy".
|
|
561
|
+
# ADR-13 slice 3b — record one `dynamic.shape.lossy-projection` event per (head,
|
|
562
|
+
# source_location) pair when the projection actually degraded. The builders return
|
|
563
|
+
# the source carrier unchanged on non-HashShape / non-Tuple receivers (see
|
|
564
|
+
# `Type::Combinator.pick_of` / `omit_of` and the HashShape-only `partial_of` /
|
|
565
|
+
# `required_of` / `readonly_of`), so detection is "first arg was lossy".
|
|
609
566
|
def record_lossy_projection_if_applicable(node, args, result)
|
|
610
567
|
return if @reporter.nil?
|
|
611
568
|
return if result.nil?
|
|
@@ -4,37 +4,31 @@ require_relative "../type"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Builtins
|
|
7
|
-
# Refined types for predefined Ruby / stdlib constants whose upstream
|
|
8
|
-
#
|
|
9
|
-
# invariants.
|
|
7
|
+
# Refined types for predefined Ruby / stdlib constants whose upstream RBS signatures are
|
|
8
|
+
# broader than the constants' documented runtime invariants.
|
|
10
9
|
#
|
|
11
10
|
# Resolution is two-tiered:
|
|
12
11
|
#
|
|
13
12
|
# **Tier 1 — exact-value whitelist** (`FOLDED_CONSTANTS`):
|
|
14
|
-
# Constants whose value is bit-for-bit identical across every Ruby
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# (`Float::DIG` / `MANT_DIG` / `MAX_EXP` / …) are intentionally NOT
|
|
27
|
-
# folded: upstream RBS hedges them as "Usually defaults to …", and
|
|
28
|
-
# as plain `Integer`s they fall through Tier 2 to the RBS type
|
|
29
|
-
# harmlessly. `Complex::I` is deferred (no complex-fold consumer).
|
|
13
|
+
# Constants whose value is bit-for-bit identical across every Ruby version and platform
|
|
14
|
+
# are folded to `Constant[T]`: the `Math::PI` / `Math::E` math constants (C's `M_PI` /
|
|
15
|
+
# `M_E`) and the four IEEE 754 binary64 magnitude constants `Float::INFINITY` / `::MAX` /
|
|
16
|
+
# `::MIN` / `::EPSILON` (each a single format-mandated bit pattern). Add new entries only
|
|
17
|
+
# when the value is truly cross-implementation invariant AND compares reflexively under
|
|
18
|
+
# `==` — the latter is why `Float::NAN` is deliberately EXCLUDED: `NaN == NaN` is `false`,
|
|
19
|
+
# so a `Constant[NAN]` would violate the `Type::Constant` `==` / `eql?` / `hash` contract
|
|
20
|
+
# (it would hash equal to itself yet compare unequal), corrupting type-equality and union
|
|
21
|
+
# dedup. The binary64 *integer* shape parameters (`Float::DIG` / `MANT_DIG` / `MAX_EXP` /
|
|
22
|
+
# …) are intentionally NOT folded: upstream RBS hedges them as "Usually defaults to …",
|
|
23
|
+
# and as plain `Integer`s they fall through Tier 2 to the RBS type harmlessly.
|
|
24
|
+
# `Complex::I` is deferred (no complex-fold consumer).
|
|
30
25
|
#
|
|
31
26
|
# **Tier 2 — runtime String inspection**:
|
|
32
|
-
# For any other constant, the module resolves it via `const_get`
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
# falls through to the RBS type tier.
|
|
27
|
+
# For any other constant, the module resolves it via `const_get` against the analyzer's
|
|
28
|
+
# own Ruby runtime. Core / stdlib constants (e.g. `RUBY_VERSION`, `RUBY_PLATFORM`) are
|
|
29
|
+
# always loaded into the analyzer process; project-defined constants are not (they live
|
|
30
|
+
# only in ASTs), so their `const_get` raises `NameError` and the lookup falls through to
|
|
31
|
+
# the RBS type tier.
|
|
38
32
|
#
|
|
39
33
|
# For a successfully resolved `String` value:
|
|
40
34
|
# - empty string → no refinement (fall through to RBS `String`)
|
|
@@ -42,34 +36,29 @@ module Rigor
|
|
|
42
36
|
# - non-empty otherwise → `non-empty-string`
|
|
43
37
|
#
|
|
44
38
|
# **Exclusion set** (`RUNTIME_INSPECTION_EXCLUDED`):
|
|
45
|
-
# String constants that appear non-empty in the current runtime but
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
# "platform-specific default". None are known today; the set
|
|
51
|
-
# exists as a safety net.
|
|
39
|
+
# String constants that appear non-empty in the current runtime but are documented to be
|
|
40
|
+
# potentially empty in some build configuration or alternative implementation. Exclusions
|
|
41
|
+
# are populated by scanning Ruby's C source (version.c, etc.) and RBS comments for any
|
|
42
|
+
# constant whose documentation says "may be empty" or "platform-specific default". None
|
|
43
|
+
# are known today; the set exists as a safety net.
|
|
52
44
|
#
|
|
53
|
-
# This module is consulted by `Environment#constant_for_name` BEFORE
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
# via the lexical-candidate walk in `ExpressionTyper`).
|
|
45
|
+
# This module is consulted by `Environment#constant_for_name` BEFORE the RBS
|
|
46
|
+
# constant-type table (widest types) but AFTER in-source constant writes (the user's own
|
|
47
|
+
# `Math::PI = 0.0` takes precedence via the lexical-candidate walk in `ExpressionTyper`).
|
|
57
48
|
module PredefinedConstantRefinements
|
|
58
49
|
# --- tier 1 -------------------------------------------------------
|
|
59
50
|
|
|
60
|
-
# Exact-value fold whitelist. Keys are unqualified constant paths
|
|
61
|
-
#
|
|
62
|
-
# receives.
|
|
51
|
+
# Exact-value fold whitelist. Keys are unqualified constant paths (no leading "::")
|
|
52
|
+
# matching what `Environment#constant_for_name` receives.
|
|
63
53
|
FOLDED_CONSTANTS = {
|
|
64
|
-
# Math module — IEEE 754 bit-identical across all MRI / JRuby /
|
|
65
|
-
#
|
|
54
|
+
# Math module — IEEE 754 bit-identical across all MRI / JRuby / TruffleRuby builds;
|
|
55
|
+
# folding enables precise constant arithmetic.
|
|
66
56
|
"Math::PI" => Type::Combinator.constant_of(::Math::PI).freeze,
|
|
67
57
|
"Math::E" => Type::Combinator.constant_of(::Math::E).freeze,
|
|
68
58
|
|
|
69
|
-
# Float magnitude limits — each a single format-mandated IEEE 754
|
|
70
|
-
#
|
|
71
|
-
# `
|
|
72
|
-
# (non-reflexive `==` — see the module-level note).
|
|
59
|
+
# Float magnitude limits — each a single format-mandated IEEE 754 binary64 bit
|
|
60
|
+
# pattern (`+Inf`, `DBL_MAX`, `DBL_MIN`, `DBL_EPSILON`), reflexive under `==`.
|
|
61
|
+
# `Float::NAN` is excluded (non-reflexive `==` — see the module-level note).
|
|
73
62
|
"Float::INFINITY" => Type::Combinator.constant_of(::Float::INFINITY).freeze,
|
|
74
63
|
"Float::MAX" => Type::Combinator.constant_of(::Float::MAX).freeze,
|
|
75
64
|
"Float::MIN" => Type::Combinator.constant_of(::Float::MIN).freeze,
|
|
@@ -79,14 +68,13 @@ module Rigor
|
|
|
79
68
|
|
|
80
69
|
# --- tier 2 -------------------------------------------------------
|
|
81
70
|
|
|
82
|
-
# String constants whose runtime value is non-empty in the current
|
|
83
|
-
#
|
|
84
|
-
#
|
|
71
|
+
# String constants whose runtime value is non-empty in the current Ruby but that should
|
|
72
|
+
# NOT be narrowed because they are documented to be potentially empty in some build or
|
|
73
|
+
# implementation.
|
|
85
74
|
#
|
|
86
|
-
# Methodology: grep Ruby's version.c and similar C sources, and the
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
# (without leading "::") when a genuine risk is found.
|
|
75
|
+
# Methodology: grep Ruby's version.c and similar C sources, and the RBS comment corpus,
|
|
76
|
+
# for any constant annotated with "may be empty" or "platform-specific default". Add
|
|
77
|
+
# the full qualified path (without leading "::") when a genuine risk is found.
|
|
90
78
|
RUNTIME_INSPECTION_EXCLUDED = Set[].freeze
|
|
91
79
|
private_constant :RUNTIME_INSPECTION_EXCLUDED
|
|
92
80
|
|
|
@@ -105,24 +93,22 @@ module Rigor
|
|
|
105
93
|
|
|
106
94
|
# --- private ------------------------------------------------------
|
|
107
95
|
|
|
108
|
-
# Resolves `name` via `const_get` in the analyzer's runtime and
|
|
109
|
-
#
|
|
96
|
+
# Resolves `name` via `const_get` in the analyzer's runtime and returns a refined
|
|
97
|
+
# String carrier, or nil.
|
|
110
98
|
def self.inspect_runtime_string(name)
|
|
111
99
|
return nil if RUNTIME_INSPECTION_EXCLUDED.include?(name)
|
|
112
100
|
|
|
113
101
|
mod = ::Object
|
|
114
102
|
name.split("::").each do |part|
|
|
115
|
-
# Resolve only constants already present — never let analysing a
|
|
116
|
-
#
|
|
117
|
-
# `
|
|
118
|
-
#
|
|
119
|
-
# `
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
# effect — a project-defined constant (the common case) is simply
|
|
125
|
-
# absent and returns nil, no exception raised.
|
|
103
|
+
# Resolve only constants already present — never let analysing a reference drive
|
|
104
|
+
# the analyzer's own runtime to autoload or run a `const_missing` hook. A
|
|
105
|
+
# `Digest::UUID` reference in project code otherwise makes `const_get` trigger
|
|
106
|
+
# `Digest.const_missing` → `require "digest/uuid"`, and a missing optional library
|
|
107
|
+
# raises `LoadError` (a `ScriptError`, not the `NameError` the const_get walk
|
|
108
|
+
# expects), which would abort the whole run rather than fall through to the RBS
|
|
109
|
+
# tier. `const_defined?(part, false)` answers the same "is this resolvable here"
|
|
110
|
+
# question without the side effect — a project-defined constant (the common case)
|
|
111
|
+
# is simply absent and returns nil, no exception raised.
|
|
126
112
|
return nil unless mod.is_a?(::Module) && mod.const_defined?(part, false)
|
|
127
113
|
|
|
128
114
|
mod = mod.const_get(part, false)
|