rigortype 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/15-type-protection-coverage.md +6 -4
- data/lib/rigor/analysis/baseline.rb +56 -96
- data/lib/rigor/analysis/buffer_binding.rb +13 -20
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
- data/lib/rigor/analysis/check_rules.rb +174 -274
- data/lib/rigor/analysis/dependency_recorder.rb +26 -38
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
- data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
- data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
- data/lib/rigor/analysis/diagnostic.rb +48 -75
- data/lib/rigor/analysis/erb_template_detector.rb +13 -18
- data/lib/rigor/analysis/fact_store.rb +12 -22
- data/lib/rigor/analysis/incremental.rb +47 -63
- data/lib/rigor/analysis/incremental_session.rb +74 -100
- data/lib/rigor/analysis/project_scan.rb +12 -23
- data/lib/rigor/analysis/result.rb +3 -5
- data/lib/rigor/analysis/rule_catalog.rb +67 -95
- data/lib/rigor/analysis/run_stats.rb +38 -61
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
- data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
- data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
- data/lib/rigor/analysis/runner.rb +220 -333
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
- data/lib/rigor/analysis/worker_session.rb +64 -102
- data/lib/rigor/ast/type_node.rb +6 -8
- data/lib/rigor/ast.rb +6 -10
- data/lib/rigor/bleeding_edge.rb +27 -35
- data/lib/rigor/builtins/hkt_builtins.rb +7 -14
- data/lib/rigor/builtins/imported_refinements.rb +106 -149
- data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
- data/lib/rigor/builtins/regex_refinement.rb +32 -43
- data/lib/rigor/builtins/static_return_refinements.rb +57 -81
- data/lib/rigor/cache/descriptor.rb +58 -94
- data/lib/rigor/cache/incremental_snapshot.rb +32 -48
- data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
- data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
- data/lib/rigor/cache/rbs_constant_table.rb +8 -13
- data/lib/rigor/cache/rbs_descriptor.rb +8 -13
- data/lib/rigor/cache/rbs_environment.rb +11 -19
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
- data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
- data/lib/rigor/cache/store.rb +96 -151
- data/lib/rigor/cli/annotate_command.rb +51 -88
- data/lib/rigor/cli/baseline_command.rb +10 -17
- data/lib/rigor/cli/check_command.rb +121 -199
- data/lib/rigor/cli/check_runner_factory.rb +8 -14
- data/lib/rigor/cli/ci_detector.rb +9 -14
- data/lib/rigor/cli/command.rb +8 -14
- data/lib/rigor/cli/coverage_command.rb +19 -26
- data/lib/rigor/cli/coverage_mutation.rb +14 -19
- data/lib/rigor/cli/coverage_report.rb +0 -2
- data/lib/rigor/cli/coverage_scan.rb +7 -11
- data/lib/rigor/cli/diagnostic_formats.rb +43 -62
- data/lib/rigor/cli/diff_command.rb +10 -20
- data/lib/rigor/cli/docs_command.rb +26 -40
- data/lib/rigor/cli/doctor_command.rb +8 -9
- data/lib/rigor/cli/explain_command.rb +4 -7
- data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
- data/lib/rigor/cli/fused_protection_report.rb +6 -8
- data/lib/rigor/cli/lsp_command.rb +11 -19
- data/lib/rigor/cli/mcp_command.rb +4 -6
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
- data/lib/rigor/cli/mutation_protection_report.rb +6 -9
- data/lib/rigor/cli/options.rb +11 -19
- data/lib/rigor/cli/plugin_command.rb +18 -30
- data/lib/rigor/cli/plugins_command.rb +29 -51
- data/lib/rigor/cli/plugins_renderer.rb +12 -20
- data/lib/rigor/cli/prism_colorizer.rb +13 -19
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +27 -17
- data/lib/rigor/cli/renderable.rb +4 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
- data/lib/rigor/cli/sig_gen_command.rb +14 -26
- data/lib/rigor/cli/skill_command.rb +30 -47
- data/lib/rigor/cli/skill_describe.rb +40 -64
- data/lib/rigor/cli/trace_command.rb +9 -16
- data/lib/rigor/cli/trace_renderer.rb +35 -51
- data/lib/rigor/cli/triage_command.rb +6 -10
- data/lib/rigor/cli/triage_renderer.rb +1 -2
- data/lib/rigor/cli/type_of_command.rb +14 -23
- data/lib/rigor/cli/type_of_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_command.rb +6 -10
- data/lib/rigor/cli/type_scan_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_report.rb +2 -3
- data/lib/rigor/cli/upgrade_command.rb +2 -3
- data/lib/rigor/cli.rb +16 -28
- data/lib/rigor/config_audit.rb +35 -44
- data/lib/rigor/configuration/dependencies.rb +41 -70
- data/lib/rigor/configuration/severity_profile.rb +28 -42
- data/lib/rigor/configuration.rb +150 -241
- data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
- data/lib/rigor/environment/class_registry.rb +19 -26
- data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
- data/lib/rigor/environment/lockfile_resolver.rb +31 -47
- data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
- data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
- data/lib/rigor/environment/rbs_loader.rb +420 -518
- data/lib/rigor/environment/reflection.rb +28 -53
- data/lib/rigor/environment/reporters.rb +13 -24
- data/lib/rigor/environment.rb +176 -291
- data/lib/rigor/flow_contribution/conflict.rb +16 -27
- data/lib/rigor/flow_contribution/element.rb +7 -12
- data/lib/rigor/flow_contribution/fact.rb +33 -57
- data/lib/rigor/flow_contribution/merge_result.rb +6 -9
- data/lib/rigor/flow_contribution/merger.rb +32 -47
- data/lib/rigor/flow_contribution.rb +37 -55
- data/lib/rigor/inference/acceptance.rb +133 -219
- data/lib/rigor/inference/block_parameter_binder.rb +52 -82
- data/lib/rigor/inference/body_fixpoint.rb +22 -30
- data/lib/rigor/inference/budget_trace.rb +43 -63
- data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
- data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
- data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
- data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
- data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
- data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
- data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
- data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
- data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
- data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
- data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
- data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
- data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
- data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
- data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
- data/lib/rigor/inference/coverage_scanner.rb +13 -18
- data/lib/rigor/inference/def_return_typer.rb +8 -14
- data/lib/rigor/inference/dynamic_origin.rb +23 -20
- data/lib/rigor/inference/expression_typer.rb +774 -1152
- data/lib/rigor/inference/fallback.rb +8 -12
- data/lib/rigor/inference/fallback_tracer.rb +4 -10
- data/lib/rigor/inference/flow_tracer.rb +25 -36
- data/lib/rigor/inference/hkt_body.rb +45 -68
- data/lib/rigor/inference/hkt_body_parser.rb +33 -52
- data/lib/rigor/inference/hkt_reducer.rb +38 -59
- data/lib/rigor/inference/hkt_registry.rb +50 -76
- data/lib/rigor/inference/indexed_narrowing.rb +55 -81
- data/lib/rigor/inference/macro_block_self_type.rb +21 -34
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
- data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
- data/lib/rigor/inference/method_dispatcher.rb +378 -524
- data/lib/rigor/inference/method_parameter_binder.rb +81 -114
- data/lib/rigor/inference/multi_target_binder.rb +51 -68
- data/lib/rigor/inference/mutation_widening.rb +115 -158
- data/lib/rigor/inference/narrowing.rb +509 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
- data/lib/rigor/inference/precision_scanner.rb +26 -35
- data/lib/rigor/inference/project_patched_methods.rb +20 -32
- data/lib/rigor/inference/project_patched_scanner.rb +23 -37
- data/lib/rigor/inference/protection_scanner.rb +16 -18
- data/lib/rigor/inference/rbs_type_translator.rb +49 -66
- data/lib/rigor/inference/scope_indexer.rb +473 -817
- data/lib/rigor/inference/statement_evaluator.rb +706 -1111
- data/lib/rigor/inference/struct_fold_safety.rb +34 -48
- data/lib/rigor/inference/synthetic_method.rb +9 -16
- data/lib/rigor/inference/synthetic_method_index.rb +20 -35
- data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
- data/lib/rigor/language_server/buffer_resolution.rb +6 -9
- data/lib/rigor/language_server/buffer_table.rb +11 -18
- data/lib/rigor/language_server/completion_provider.rb +69 -116
- data/lib/rigor/language_server/debouncer.rb +16 -25
- data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
- data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
- data/lib/rigor/language_server/folding_range_provider.rb +11 -19
- data/lib/rigor/language_server/hover_provider.rb +8 -11
- data/lib/rigor/language_server/hover_renderer.rb +56 -93
- data/lib/rigor/language_server/loop.rb +14 -19
- data/lib/rigor/language_server/project_context.rb +46 -74
- data/lib/rigor/language_server/selection_range_provider.rb +9 -12
- data/lib/rigor/language_server/server.rb +55 -83
- data/lib/rigor/language_server/signature_help_provider.rb +29 -46
- data/lib/rigor/language_server/synchronized_writer.rb +4 -7
- data/lib/rigor/language_server/uri.rb +8 -13
- data/lib/rigor/language_server.rb +4 -6
- data/lib/rigor/mcp/loop.rb +2 -3
- data/lib/rigor/mcp/server.rb +4 -7
- data/lib/rigor/mcp.rb +3 -6
- data/lib/rigor/plugin/access_denied_error.rb +5 -8
- data/lib/rigor/plugin/additional_initializer.rb +21 -31
- data/lib/rigor/plugin/base.rb +335 -518
- data/lib/rigor/plugin/blueprint.rb +14 -23
- data/lib/rigor/plugin/box.rb +18 -29
- data/lib/rigor/plugin/fact_store.rb +16 -26
- data/lib/rigor/plugin/inflector.rb +37 -53
- data/lib/rigor/plugin/io_boundary.rb +33 -56
- data/lib/rigor/plugin/isolation.rb +42 -55
- data/lib/rigor/plugin/load_error.rb +10 -15
- data/lib/rigor/plugin/loader.rb +30 -49
- data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
- data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
- data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
- data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
- data/lib/rigor/plugin/macro.rb +10 -15
- data/lib/rigor/plugin/manifest.rb +85 -144
- data/lib/rigor/plugin/node_context.rb +14 -22
- data/lib/rigor/plugin/node_rule_walk.rb +49 -74
- data/lib/rigor/plugin/protocol_contract.rb +25 -39
- data/lib/rigor/plugin/registry.rb +132 -205
- data/lib/rigor/plugin/services.rb +21 -33
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
- data/lib/rigor/plugin/trust_policy.rb +24 -38
- data/lib/rigor/plugin/type_node_resolver.rb +15 -24
- data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
- data/lib/rigor/protection/mutation_scanner.rb +27 -35
- data/lib/rigor/protection/mutator.rb +50 -70
- data/lib/rigor/protection/test_suite_oracle.rb +20 -27
- data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
- data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
- data/lib/rigor/rbs_extended/reporter.rb +24 -40
- data/lib/rigor/rbs_extended.rb +107 -197
- data/lib/rigor/reflection.rb +68 -86
- data/lib/rigor/scope/discovery_index.rb +14 -19
- data/lib/rigor/scope.rb +255 -310
- data/lib/rigor/sig_gen/classification.rb +6 -10
- data/lib/rigor/sig_gen/generator.rb +197 -323
- data/lib/rigor/sig_gen/layout_index.rb +12 -20
- data/lib/rigor/sig_gen/method_candidate.rb +12 -17
- data/lib/rigor/sig_gen/observation_collector.rb +38 -70
- data/lib/rigor/sig_gen/observed_call.rb +13 -23
- data/lib/rigor/sig_gen/path_mapper.rb +17 -29
- data/lib/rigor/sig_gen/renderer.rb +7 -13
- data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
- data/lib/rigor/sig_gen/write_result.rb +8 -16
- data/lib/rigor/sig_gen/writer.rb +95 -174
- data/lib/rigor/sig_gen.rb +3 -6
- data/lib/rigor/signature_path_audit.rb +24 -30
- data/lib/rigor/source/constant_path.rb +10 -14
- data/lib/rigor/source/literals.rb +31 -45
- data/lib/rigor/source/node_locator.rb +9 -11
- data/lib/rigor/source/node_walker.rb +9 -13
- data/lib/rigor/source.rb +3 -4
- data/lib/rigor/testing.rb +16 -20
- data/lib/rigor/triage/catalogue.rb +38 -62
- data/lib/rigor/triage.rb +31 -52
- data/lib/rigor/trinary.rb +9 -13
- data/lib/rigor/type/acceptance_router.rb +4 -6
- data/lib/rigor/type/accepts_result.rb +10 -14
- data/lib/rigor/type/app.rb +19 -27
- data/lib/rigor/type/bot.rb +4 -6
- data/lib/rigor/type/bound_method.rb +10 -15
- data/lib/rigor/type/combinator.rb +165 -257
- data/lib/rigor/type/constant.rb +23 -34
- data/lib/rigor/type/data_class.rb +10 -15
- data/lib/rigor/type/data_instance.rb +14 -20
- data/lib/rigor/type/difference.rb +21 -32
- data/lib/rigor/type/dynamic.rb +3 -5
- data/lib/rigor/type/hash_shape.rb +32 -18
- data/lib/rigor/type/integer_range.rb +11 -16
- data/lib/rigor/type/intersection.rb +27 -42
- data/lib/rigor/type/nominal.rb +10 -15
- data/lib/rigor/type/plain_lattice.rb +9 -13
- data/lib/rigor/type/refined.rb +67 -114
- data/lib/rigor/type/singleton.rb +4 -6
- data/lib/rigor/type/struct_class.rb +11 -16
- data/lib/rigor/type/struct_instance.rb +15 -21
- data/lib/rigor/type/tuple.rb +14 -19
- data/lib/rigor/type/union.rb +30 -42
- data/lib/rigor/type_node/generic.rb +14 -26
- data/lib/rigor/type_node/identifier.rb +12 -19
- data/lib/rigor/type_node.rb +3 -12
- data/lib/rigor/value_semantics.rb +16 -21
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
- data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
- data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
- data/sig/rigor/scope.rbs +6 -0
- metadata +2 -1
|
@@ -5,48 +5,37 @@ require_relative "../inference/rbs_type_translator"
|
|
|
5
5
|
|
|
6
6
|
module Rigor
|
|
7
7
|
module RbsExtended
|
|
8
|
-
# Verifies every `rigor:v1:conforms-to <Interface>` class- /
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# interface as a *checked design assertion* — independent of
|
|
14
|
-
# whether any current call site exercises that requirement.
|
|
15
|
-
# Multiple directives on one class combine as an intersection:
|
|
16
|
-
# each interface is checked independently.
|
|
8
|
+
# Verifies every `rigor:v1:conforms-to <Interface>` class- / module-level directive in the loaded RBS
|
|
9
|
+
# environment (spec: `docs/type-specification/rbs-extended.md` § "Explicit conformance directive"). For each
|
|
10
|
+
# annotated class, the directive asserts the class satisfies the named structural interface as a *checked
|
|
11
|
+
# design assertion* — independent of whether any current call site exercises that requirement. Multiple
|
|
12
|
+
# directives on one class combine as an intersection: each interface is checked independently.
|
|
17
13
|
#
|
|
18
14
|
# ## Two checked tiers
|
|
19
15
|
#
|
|
20
|
-
# 1. **Presence** (FP-free): an interface method the class provably does
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
# `def.override-*` rules — not the inferred-signature comparison whose
|
|
31
|
-
# FP risk justified deferring it. Conservative: single-method-type
|
|
32
|
-
# (non-overloaded) signatures only, `Dynamic[Top]` positions skipped,
|
|
33
|
-
# fires only on a proven `accepts(...).no?` violation.
|
|
16
|
+
# 1. **Presence** (FP-free): an interface method the class provably does NOT provide anywhere in its
|
|
17
|
+
# RBS-resolved method set (own, inherited, included) is a definitive non-conformance.
|
|
18
|
+
# 2. **Signature compatibility** (covariant return / contravariant params): for a method the class DOES
|
|
19
|
+
# provide, the provided RBS signature must be a behavioural subtype of the interface's required one. Both
|
|
20
|
+
# sides are *authored* RBS (the class in `signature_paths:` RBS, the interface in a loaded `sig`/library),
|
|
21
|
+
# so this is the same FP-safe both-sides-authored construction as the
|
|
22
|
+
# [ADR-35](../../../docs/adr/35-override-signature-compatibility.md) `def.override-*` rules — not the
|
|
23
|
+
# inferred-signature comparison whose FP risk justified deferring it. Conservative: single-method-type
|
|
24
|
+
# (non-overloaded) signatures only, `Dynamic[Top]` positions skipped, fires only on a proven
|
|
25
|
+
# `accepts(...).no?` violation.
|
|
34
26
|
#
|
|
35
27
|
# ## Output records (all drained by {Rigor::Analysis::Runner})
|
|
36
28
|
#
|
|
37
|
-
# - `Unsatisfied` — the class is missing one or more required interface
|
|
38
|
-
#
|
|
39
|
-
# - `IncompatibleSignature` — a provided method's signature violates the
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
# the
|
|
44
|
-
# Surfaces as `dynamic.rbs-extended.unresolved` `:info`, the fail-soft
|
|
45
|
-
# channel the other directive parsers use, so a bad name never silently
|
|
46
|
-
# disables the author's assertion.
|
|
29
|
+
# - `Unsatisfied` — the class is missing one or more required interface methods. Surfaces as
|
|
30
|
+
# `rbs_extended.unsatisfied-conformance`.
|
|
31
|
+
# - `IncompatibleSignature` — a provided method's signature violates the interface contract (return widened,
|
|
32
|
+
# or a parameter narrowed). Same rule, signature-specific message.
|
|
33
|
+
# - `UnresolvedInterface` — the named interface is not loaded (a typo, or the defining library / `sig` set is
|
|
34
|
+
# not on the RBS load path). Surfaces as `dynamic.rbs-extended.unresolved` `:info`, the fail-soft channel
|
|
35
|
+
# the other directive parsers use, so a bad name never silently disables the author's assertion.
|
|
47
36
|
#
|
|
48
|
-
# Fail-soft throughout: a class whose own definition cannot be built (RBS
|
|
49
|
-
#
|
|
37
|
+
# Fail-soft throughout: a class whose own definition cannot be built (RBS error) is skipped rather than
|
|
38
|
+
# reported.
|
|
50
39
|
module ConformanceChecker
|
|
51
40
|
Unsatisfied = Data.define(:class_name, :interface_name, :missing_methods, :location)
|
|
52
41
|
IncompatibleSignature = Data.define(:class_name, :interface_name, :method_name, :detail, :location)
|
|
@@ -113,14 +102,11 @@ module Rigor
|
|
|
113
102
|
end
|
|
114
103
|
end
|
|
115
104
|
|
|
116
|
-
# Returns a human-readable mismatch detail when `provided` is NOT a
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
# Also checks arity divergence and keyword-requiredness divergence
|
|
122
|
-
# (positional-type comparison only was the initial scope; these
|
|
123
|
-
# extend it to the cases that cause runtime ArgumentError).
|
|
105
|
+
# Returns a human-readable mismatch detail when `provided` is NOT a behavioural subtype of the `required`
|
|
106
|
+
# (interface) signature, else nil. Mirrors the ADR-35 override checks: covariant return, contravariant
|
|
107
|
+
# params, single method type only, `Dynamic[Top]` positions skipped (fires only on a proven
|
|
108
|
+
# `accepts(...).no?`). Also checks arity divergence and keyword-requiredness divergence (positional-type
|
|
109
|
+
# comparison only was the initial scope; these extend it to the cases that cause runtime ArgumentError).
|
|
124
110
|
def signature_mismatch(required_method, provided_method)
|
|
125
111
|
return nil unless required_method.method_types.size == 1
|
|
126
112
|
return nil unless provided_method.method_types.size == 1
|
|
@@ -158,14 +144,13 @@ module Rigor
|
|
|
158
144
|
nil
|
|
159
145
|
end
|
|
160
146
|
|
|
161
|
-
# Checks positional-count divergence — cases that would cause a
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
#
|
|
168
|
-
# (caller passes ≥ interface required → provided raises).
|
|
147
|
+
# Checks positional-count divergence — cases that would cause a runtime `ArgumentError` even when every
|
|
148
|
+
# declared type matches. Skipped when either side has a rest parameter (`*args`) since that makes the
|
|
149
|
+
# arity range unbounded. Two violation shapes:
|
|
150
|
+
# (a) provided requires MORE positionals than the interface allows (caller passes ≤ interface total →
|
|
151
|
+
# provided raises);
|
|
152
|
+
# (b) provided accepts FEWER positionals than the interface requires (caller passes ≥ interface required →
|
|
153
|
+
# provided raises).
|
|
169
154
|
def arity_detail(required_method, provided_method)
|
|
170
155
|
req_func = required_method.method_types.first.type
|
|
171
156
|
prov_func = provided_method.method_types.first.type
|
|
@@ -193,11 +178,10 @@ module Rigor
|
|
|
193
178
|
end
|
|
194
179
|
|
|
195
180
|
# Checks keyword-requiredness divergence.
|
|
196
|
-
# (a) A keyword the interface requires that the provided method does
|
|
197
|
-
#
|
|
198
|
-
# (b) A keyword the provided method requires that the interface does
|
|
199
|
-
#
|
|
200
|
-
# provided will raise.
|
|
181
|
+
# (a) A keyword the interface requires that the provided method does not accept at all → callers will pass
|
|
182
|
+
# it, provided will raise.
|
|
183
|
+
# (b) A keyword the provided method requires that the interface does not mention → callers following the
|
|
184
|
+
# interface won't pass it, provided will raise.
|
|
201
185
|
# Skipped when either side has a keyword rest (`**kwargs`).
|
|
202
186
|
def keyword_detail(required_method, provided_method)
|
|
203
187
|
req_func, prov_func = keyword_funcs(required_method, provided_method)
|
|
@@ -245,13 +229,11 @@ module Rigor
|
|
|
245
229
|
(func.required_positionals + func.optional_positionals).map { |param| translate(param.type) }
|
|
246
230
|
end
|
|
247
231
|
|
|
248
|
-
# Resolves the (possibly namespace-relative) `interface_name` against
|
|
249
|
-
#
|
|
250
|
-
#
|
|
251
|
-
#
|
|
252
|
-
#
|
|
253
|
-
# `::` is already stripped by the parser, so an intended-absolute name
|
|
254
|
-
# still resolves via the trailing top-level candidate.)
|
|
232
|
+
# Resolves the (possibly namespace-relative) `interface_name` against the declaring class's namespace
|
|
233
|
+
# chain, mirroring Ruby constant lookup: `conforms-to _Foo` inside `Bar::Baz` tries `Bar::Baz::_Foo`,
|
|
234
|
+
# `Bar::_Foo`, then top-level `_Foo` (longest prefix first). Returns the first interface definition that
|
|
235
|
+
# resolves, or nil. (A leading `::` is already stripped by the parser, so an intended-absolute name still
|
|
236
|
+
# resolves via the trailing top-level candidate.)
|
|
255
237
|
def resolve_interface(rbs_loader, class_name, interface_name)
|
|
256
238
|
candidate_interface_names(class_name, interface_name).each do |candidate|
|
|
257
239
|
defn = rbs_loader.interface_definition(candidate)
|
|
@@ -265,11 +247,9 @@ module Rigor
|
|
|
265
247
|
prefixes.map { |prefix| "#{prefix}::#{interface_name}" } + [interface_name]
|
|
266
248
|
end
|
|
267
249
|
|
|
268
|
-
# Namespace prefixes of a qualified name, longest first:
|
|
269
|
-
# `
|
|
270
|
-
#
|
|
271
|
-
# (a superset of `Module.nesting`, which the directive's resolved
|
|
272
|
-
# class name does not record).
|
|
250
|
+
# Namespace prefixes of a qualified name, longest first: `"Bar::Baz"` → `["Bar::Baz", "Bar"]`. Covers both
|
|
251
|
+
# the `class Bar::Baz` and the `module Bar; class Baz` nesting shapes (a superset of `Module.nesting`,
|
|
252
|
+
# which the directive's resolved class name does not record).
|
|
273
253
|
def namespace_prefixes(class_name)
|
|
274
254
|
parts = normalize(class_name).split("::")
|
|
275
255
|
(1..parts.size).to_a.reverse.map { |count| parts.first(count).join("::") }
|
|
@@ -5,35 +5,25 @@ require_relative "../inference/hkt_body_parser"
|
|
|
5
5
|
|
|
6
6
|
module Rigor
|
|
7
7
|
module RbsExtended
|
|
8
|
-
# ADR-20 § "Decision D6" parser for the two new HKT
|
|
9
|
-
# directives that live in `.rbs` files at module / class
|
|
8
|
+
# ADR-20 § "Decision D6" parser for the two new HKT directives that live in `.rbs` files at module / class
|
|
10
9
|
# scope:
|
|
11
10
|
#
|
|
12
|
-
# - `%a{rigor:v1:hkt_register: uri=<uri> arity=<int>
|
|
13
|
-
# variance
|
|
14
|
-
# registers a defunctionalised type-constructor URI
|
|
15
|
-
# together with its arity, per-position variance, and
|
|
11
|
+
# - `%a{rigor:v1:hkt_register: uri=<uri> arity=<int> variance=<v1>,<v2>,... bound=<class_name_or_untyped>}` —
|
|
12
|
+
# registers a defunctionalised type-constructor URI together with its arity, per-position variance, and
|
|
16
13
|
# erasure bound.
|
|
17
|
-
# - `%a{rigor:v1:hkt_define: uri=<uri> params=<P1>,<P2>,...
|
|
18
|
-
# body
|
|
19
|
-
# body that {HktBodyParser} parses into an
|
|
20
|
-
# {HktBody::Union} tree.
|
|
14
|
+
# - `%a{rigor:v1:hkt_define: uri=<uri> params=<P1>,<P2>,... body=<body_text>}` — binds the URI to a
|
|
15
|
+
# type-function body that {HktBodyParser} parses into an {HktBody::Union} tree.
|
|
21
16
|
#
|
|
22
17
|
# ## Payload format
|
|
23
18
|
#
|
|
24
|
-
# **Space-separated `key=value` pairs.** The format is
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# parsing). Each value is a bare token: no quoting, no
|
|
29
|
-
# escaping. Values that contain spaces or `=` signs MUST
|
|
30
|
-
# be encoded via the `body=` key, which is special-cased
|
|
31
|
-
# to gobble everything from `body=` to the end of the
|
|
19
|
+
# **Space-separated `key=value` pairs.** The format is constrained by RBS's `%a{...}` annotation grammar,
|
|
20
|
+
# which does NOT accept arbitrary nested punctuation (a JSON payload with quotes / nested braces will fail RBS
|
|
21
|
+
# parsing). Each value is a bare token: no quoting, no escaping. Values that contain spaces or `=` signs MUST
|
|
22
|
+
# be encoded via the `body=` key, which is special-cased to gobble everything from `body=` to the end of the
|
|
32
23
|
# payload — see `parse_define`.
|
|
33
24
|
#
|
|
34
|
-
# Example annotations (write inside a class / module
|
|
35
|
-
#
|
|
36
|
-
# RBS parses):
|
|
25
|
+
# Example annotations (write inside a class / module declaration so the annotation attaches to the decl RBS
|
|
26
|
+
# parses):
|
|
37
27
|
#
|
|
38
28
|
# %a{rigor:v1:hkt_register: uri=json::value arity=1
|
|
39
29
|
# variance=out bound=untyped}
|
|
@@ -46,18 +36,13 @@ module Rigor
|
|
|
46
36
|
#
|
|
47
37
|
# ## Bound vocabulary
|
|
48
38
|
#
|
|
49
|
-
# - `untyped` resolves to `Rigor::Type::Combinator.untyped`
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
# supplied, falling back to a raw `Rigor::Type::Nominal`
|
|
54
|
-
# otherwise.
|
|
55
|
-
# - Anything else falls back to `untyped` and emits an
|
|
56
|
-
# `:info` diagnostic via the supplied reporter (fail-soft
|
|
39
|
+
# - `untyped` resolves to `Rigor::Type::Combinator.untyped` (i.e. `Dynamic[Top]`, the ADR-20 WD2 default).
|
|
40
|
+
# - A bare class name (`String`, `Integer`, …) resolves through `name_scope.nominal_for_name(...)` when
|
|
41
|
+
# supplied, falling back to a raw `Rigor::Type::Nominal` otherwise.
|
|
42
|
+
# - Anything else falls back to `untyped` and emits an `:info` diagnostic via the supplied reporter (fail-soft
|
|
57
43
|
# so an unrecognised bound never crashes the loader).
|
|
58
44
|
#
|
|
59
|
-
# Richer bound forms (parameterised generics, unions,
|
|
60
|
-
# refinements) wait for a follow-up slice's expression
|
|
45
|
+
# Richer bound forms (parameterised generics, unions, refinements) wait for a follow-up slice's expression
|
|
61
46
|
# parser.
|
|
62
47
|
module HktDirectives
|
|
63
48
|
module_function
|
|
@@ -68,10 +53,8 @@ module Rigor
|
|
|
68
53
|
DEFAULT_VARIANCE = :inv
|
|
69
54
|
DEFAULT_BOUND_LITERAL = "untyped"
|
|
70
55
|
|
|
71
|
-
# Parses one `%a{rigor:v1:hkt_register: ...}` payload
|
|
72
|
-
# string
|
|
73
|
-
# string is not an hkt_register directive (so callers can
|
|
74
|
-
# walk a list of annotations without each having to
|
|
56
|
+
# Parses one `%a{rigor:v1:hkt_register: ...}` payload string and returns a `Registration`, or `nil` when the
|
|
57
|
+
# string is not an hkt_register directive (so callers can walk a list of annotations without each having to
|
|
75
58
|
# pre-filter).
|
|
76
59
|
def parse_register(string, name_scope: nil, reporter: nil, source_location: nil)
|
|
77
60
|
payload = extract_payload(string, REGISTER_DIRECTIVE)
|
|
@@ -106,8 +89,7 @@ module Rigor
|
|
|
106
89
|
nil
|
|
107
90
|
end
|
|
108
91
|
|
|
109
|
-
# Parses one `%a{rigor:v1:hkt_define: ...}` payload
|
|
110
|
-
# string and returns a `Definition`, or `nil` when the
|
|
92
|
+
# Parses one `%a{rigor:v1:hkt_define: ...}` payload string and returns a `Definition`, or `nil` when the
|
|
111
93
|
# string is not an hkt_define directive.
|
|
112
94
|
def parse_define(string, reporter: nil, source_location: nil)
|
|
113
95
|
payload = extract_payload(string, DEFINE_DIRECTIVE)
|
|
@@ -149,8 +131,7 @@ module Rigor
|
|
|
149
131
|
return nil if idx.nil?
|
|
150
132
|
|
|
151
133
|
payload = string[(idx + directive.size)..].to_s.strip
|
|
152
|
-
# Strip trailing `}` of the wrapping `%a{...}` form if
|
|
153
|
-
# the caller passed the raw annotation string. The
|
|
134
|
+
# Strip trailing `}` of the wrapping `%a{...}` form if the caller passed the raw annotation string. The
|
|
154
135
|
# parser also accepts a pre-extracted payload.
|
|
155
136
|
payload = payload.sub(/\}\z/, "") if payload.end_with?("}") && !balanced_braces?(payload)
|
|
156
137
|
payload.empty? ? nil : payload
|
|
@@ -169,19 +150,15 @@ module Rigor
|
|
|
169
150
|
depth.zero?
|
|
170
151
|
end
|
|
171
152
|
|
|
172
|
-
# Parses a space-separated `key=value [key=value ...]`
|
|
173
|
-
#
|
|
174
|
-
#
|
|
175
|
-
# the end of the payload becomes the value (body
|
|
176
|
-
# contents typically include spaces, `|`, `[]` etc.
|
|
177
|
-
# that the simple tokenizer cannot otherwise carry).
|
|
153
|
+
# Parses a space-separated `key=value [key=value ...]` payload into a Hash. When `body_key` is supplied AND
|
|
154
|
+
# that key appears, everything from `<body_key>=` to the end of the payload becomes the value (body
|
|
155
|
+
# contents typically include spaces, `|`, `[]` etc. that the simple tokenizer cannot otherwise carry).
|
|
178
156
|
KV_KEY_PATTERN = /(?<![\w.])([a-z_]\w*)=/
|
|
179
157
|
private_constant :KV_KEY_PATTERN
|
|
180
158
|
|
|
181
159
|
def parse_kv_payload(payload, body_key:)
|
|
182
160
|
result = {}
|
|
183
|
-
# Find every `<key>=` boundary; each value runs to
|
|
184
|
-
# the next boundary or end of string.
|
|
161
|
+
# Find every `<key>=` boundary; each value runs to the next boundary or end of string.
|
|
185
162
|
markers = []
|
|
186
163
|
payload.scan(KV_KEY_PATTERN) { markers << [::Regexp.last_match[1], ::Regexp.last_match.end(0)] }
|
|
187
164
|
markers.each_with_index do |(key, value_start), i|
|
|
@@ -196,13 +173,10 @@ module Rigor
|
|
|
196
173
|
result
|
|
197
174
|
end
|
|
198
175
|
|
|
199
|
-
# ADR-20 slice 2b — parse the body String into an
|
|
200
|
-
# `
|
|
201
|
-
#
|
|
202
|
-
#
|
|
203
|
-
# keeps its `body` String slot but `body_tree` stays
|
|
204
|
-
# absent (the reducer falls back to `app.bound` at call
|
|
205
|
-
# time per ADR-20 D5).
|
|
176
|
+
# ADR-20 slice 2b — parse the body String into an `HktBody::*` tree via {Inference::HktBodyParser.parse}. On
|
|
177
|
+
# parse failure: emit a fail-soft `:info` reporter entry and return `nil` so the resulting Definition keeps
|
|
178
|
+
# its `body` String slot but `body_tree` stays absent (the reducer falls back to `app.bound` at call time
|
|
179
|
+
# per ADR-20 D5).
|
|
206
180
|
def parse_body_tree(body, params, reporter:, source_location:)
|
|
207
181
|
return nil if body.nil? || body.empty?
|
|
208
182
|
|
|
@@ -2,35 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module RbsExtended
|
|
5
|
-
# ADR-13 slice 3b — per-run accumulator for `RBS::Extended`
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# `nil` so call sites fall back to the RBS-declared type).
|
|
5
|
+
# ADR-13 slice 3b — per-run accumulator for `RBS::Extended` diagnostic events that the parser / resolver
|
|
6
|
+
# cannot surface at the point of failure (the parsers are fail-soft, returning `nil` so call sites fall back
|
|
7
|
+
# to the RBS-declared type).
|
|
9
8
|
#
|
|
10
9
|
# Owns two event streams:
|
|
11
10
|
#
|
|
12
|
-
# - `#unresolved_payloads` — `rigor:v1:*` directive payloads
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# shape information (anything other than `Type::HashShape`
|
|
19
|
-
# / `Type::Tuple`). Surface as
|
|
20
|
-
# `dynamic.shape.lossy-projection` `:info` diagnostics.
|
|
11
|
+
# - `#unresolved_payloads` — `rigor:v1:*` directive payloads the resolver could not turn into a
|
|
12
|
+
# {Rigor::Type}. Surface as `dynamic.rbs-extended.unresolved` `:info` diagnostics.
|
|
13
|
+
# - `#lossy_projections` — shape-projection type functions (`pick_of` / `omit_of` / `partial_of` /
|
|
14
|
+
# `required_of` / `readonly_of`) applied to a carrier that does not preserve shape information (anything
|
|
15
|
+
# other than `Type::HashShape` / `Type::Tuple`). Surface as `dynamic.shape.lossy-projection` `:info`
|
|
16
|
+
# diagnostics.
|
|
21
17
|
#
|
|
22
|
-
# Mutable through the run; consumed once by
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# and `(head, source_location)` for lossy-projection so a
|
|
26
|
-
# single annotation read from many call sites yields one
|
|
27
|
-
# diagnostic.
|
|
18
|
+
# Mutable through the run; consumed once by {Rigor::Analysis::Runner} at end-of-run. Each event is
|
|
19
|
+
# deduplicated by `(payload, source_location)` for unresolved and `(head, source_location)` for
|
|
20
|
+
# lossy-projection so a single annotation read from many call sites yields one diagnostic.
|
|
28
21
|
#
|
|
29
|
-
# The reporter is intentionally thread-safe via a coarse
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
# critical sections are short (Array#include? + Array#<<) so
|
|
33
|
-
# the lock contention is negligible.
|
|
22
|
+
# The reporter is intentionally thread-safe via a coarse `Mutex` because the inference engine may read the
|
|
23
|
+
# same method definition from multiple files in parallel; the critical sections are short (Array#include? +
|
|
24
|
+
# Array#<<) so the lock contention is negligible.
|
|
34
25
|
class Reporter
|
|
35
26
|
UnresolvedEntry = Data.define(:payload, :source_location)
|
|
36
27
|
LossyProjectionEntry = Data.define(:head, :source_location)
|
|
@@ -41,23 +32,19 @@ module Rigor
|
|
|
41
32
|
@mutex = Mutex.new
|
|
42
33
|
end
|
|
43
34
|
|
|
44
|
-
# @return [Array<UnresolvedEntry>] frozen snapshot of the
|
|
45
|
-
# accumulated unresolved-payload events.
|
|
35
|
+
# @return [Array<UnresolvedEntry>] frozen snapshot of the accumulated unresolved-payload events.
|
|
46
36
|
def unresolved_payloads
|
|
47
37
|
@mutex.synchronize { @unresolved_payloads.dup.freeze }
|
|
48
38
|
end
|
|
49
39
|
|
|
50
|
-
# @return [Array<LossyProjectionEntry>] frozen snapshot of
|
|
51
|
-
# the accumulated lossy-projection events.
|
|
40
|
+
# @return [Array<LossyProjectionEntry>] frozen snapshot of the accumulated lossy-projection events.
|
|
52
41
|
def lossy_projections
|
|
53
42
|
@mutex.synchronize { @lossy_projections.dup.freeze }
|
|
54
43
|
end
|
|
55
44
|
|
|
56
|
-
# Records a `dynamic.rbs-extended.unresolved` event. The
|
|
57
|
-
# `
|
|
58
|
-
# to
|
|
59
|
-
# have one — the diagnostic falls back to a generic
|
|
60
|
-
# location in that case).
|
|
45
|
+
# Records a `dynamic.rbs-extended.unresolved` event. The `source_location` argument is the {RBS::Location}
|
|
46
|
+
# attached to the source annotation (or `nil` when the caller doesn't have one — the diagnostic falls back
|
|
47
|
+
# to a generic location in that case).
|
|
61
48
|
def record_unresolved(payload:, source_location: nil)
|
|
62
49
|
entry = UnresolvedEntry.new(payload: payload.to_s, source_location: source_location)
|
|
63
50
|
@mutex.synchronize do
|
|
@@ -67,10 +54,8 @@ module Rigor
|
|
|
67
54
|
end
|
|
68
55
|
end
|
|
69
56
|
|
|
70
|
-
# Records a `dynamic.shape.lossy-projection` event for one
|
|
71
|
-
#
|
|
72
|
-
# String (`"pick_of"`, `"omit_of"`, …); the diagnostic
|
|
73
|
-
# message identifies which projection degraded.
|
|
57
|
+
# Records a `dynamic.shape.lossy-projection` event for one of the five shape-projection heads. `head` MUST
|
|
58
|
+
# be a String (`"pick_of"`, `"omit_of"`, …); the diagnostic message identifies which projection degraded.
|
|
74
59
|
def record_lossy_projection(head:, source_location: nil)
|
|
75
60
|
entry = LossyProjectionEntry.new(head: head.to_s, source_location: source_location)
|
|
76
61
|
@mutex.synchronize do
|
|
@@ -80,9 +65,8 @@ module Rigor
|
|
|
80
65
|
end
|
|
81
66
|
end
|
|
82
67
|
|
|
83
|
-
# True when no events have accumulated. Used by callers
|
|
84
|
-
#
|
|
85
|
-
# on the common no-event path.
|
|
68
|
+
# True when no events have accumulated. Used by callers that want to skip the diagnostic-emission pass
|
|
69
|
+
# entirely on the common no-event path.
|
|
86
70
|
def empty?
|
|
87
71
|
@mutex.synchronize { @unresolved_payloads.empty? && @lossy_projections.empty? }
|
|
88
72
|
end
|