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,60 +7,44 @@ module Rigor
|
|
|
7
7
|
module Builtins
|
|
8
8
|
# `Time` catalog. Singleton — load once, consult during dispatch.
|
|
9
9
|
#
|
|
10
|
-
# Time is a pure-C built-in: the Init block in
|
|
11
|
-
# `references/ruby/
|
|
12
|
-
#
|
|
13
|
-
# contributes the class-side constructors (`Time.now`,
|
|
14
|
-
# `Time.at`, `Time.new`) through Primitive cexpr stubs.
|
|
10
|
+
# Time is a pure-C built-in: the Init block in `references/ruby/time.c` registers the bulk of the
|
|
11
|
+
# surface, and the Ruby-side prelude `references/ruby/timev.rb` contributes the class-side
|
|
12
|
+
# constructors (`Time.now`, `Time.at`, `Time.new`) through Primitive cexpr stubs.
|
|
15
13
|
#
|
|
16
|
-
# Time receivers are not lifted to a `Constant` carrier today
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# The catalog wiring therefore mostly governs:
|
|
14
|
+
# Time receivers are not lifted to a `Constant` carrier today (there is no `Time` literal node — the
|
|
15
|
+
# closest is `Time.now` / `Time.new(...)`, which produce `Nominal[Time]`). The catalog wiring
|
|
16
|
+
# therefore mostly governs:
|
|
20
17
|
#
|
|
21
|
-
# 1. The size-projection-equivalent reader surface (`#year`,
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# `:leaf` from ever folding through a hypothetical future
|
|
27
|
-
# `Constant<Time>` carrier.
|
|
18
|
+
# 1. The size-projection-equivalent reader surface (`#year`, `#month`, `#hour`, `#sec`, `#wday`, …)
|
|
19
|
+
# — RBS-declared `Integer` is preserved through dispatch.
|
|
20
|
+
# 2. The blocklist below, which keeps the indirect-mutator methods that the C-body classifier
|
|
21
|
+
# mis-flagged as `:leaf` from ever folding through a hypothetical future `Constant<Time>`
|
|
22
|
+
# carrier.
|
|
28
23
|
#
|
|
29
|
-
# The blocklist captures the false-positive `:leaf` entries
|
|
30
|
-
#
|
|
31
|
-
# recognise as mutators.
|
|
24
|
+
# The blocklist captures the false-positive `:leaf` entries whose helper functions the regex
|
|
25
|
+
# classifier did not recognise as mutators.
|
|
32
26
|
TIME_CATALOG = MethodCatalog.for_topic(
|
|
33
27
|
"time",
|
|
34
28
|
mutating_selectors: {
|
|
35
29
|
"Time" => Set[
|
|
36
|
-
# `time_init_copy` writes the `timew` and `vtm` slots on
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
# mutator regex's helper list. Blocked for symmetry with
|
|
40
|
-
# String / Array / Range / Set initialize_copy entries.
|
|
30
|
+
# `time_init_copy` writes the `timew` and `vtm` slots on the receiver via `time_set_timew` /
|
|
31
|
+
# `time_set_vtm`. Classed `:leaf` because those setters are not in the mutator regex's helper
|
|
32
|
+
# list. Blocked for symmetry with String / Array / Range / Set initialize_copy entries.
|
|
41
33
|
:initialize_copy,
|
|
42
|
-
# `time_localtime_m` -> `time_localtime` calls
|
|
43
|
-
# `
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
# in place"). The C-body classifier mis-flagged it as
|
|
47
|
-
# `:leaf` because `time_modify` is not in its mutator
|
|
48
|
-
# regex.
|
|
34
|
+
# `time_localtime_m` -> `time_localtime` calls `time_modify(time)` to mark the receiver
|
|
35
|
+
# mutable before rewriting its `vtm` cache and `tzmode`. The docstring is explicit ("converts
|
|
36
|
+
# time to local time in place"). The C-body classifier mis-flagged it as `:leaf` because
|
|
37
|
+
# `time_modify` is not in its mutator regex.
|
|
49
38
|
:localtime,
|
|
50
|
-
# `time_gmtime` (registered as both `gmtime` and `utc`
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
# `time_set_vtm` write and `TZMODE_SET_UTC`. Both
|
|
54
|
-
# selectors share the cfunc, so both must be blocked.
|
|
39
|
+
# `time_gmtime` (registered as both `gmtime` and `utc` against `rb_cTime`) follows the same
|
|
40
|
+
# in-place pattern as `time_localtime`: `time_modify(time)` then a `time_set_vtm` write and
|
|
41
|
+
# `TZMODE_SET_UTC`. Both selectors share the cfunc, so both must be blocked.
|
|
55
42
|
:gmtime, :utc,
|
|
56
|
-
# `getlocal` is not a mutator — it returns a fresh Time —
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
# into the inferred type. Blocked so the fold stays
|
|
62
|
-
# machine-independent; the RBS tier answers `Nominal[Time]`.
|
|
63
|
-
# `getutc` / `getgm` stay foldable — their result is UTC.
|
|
43
|
+
# `getlocal` is not a mutator — it returns a fresh Time — but the fresh Time is pinned to the
|
|
44
|
+
# *analysis machine's* timezone. Folding it through a `Constant[Time]` carrier (which only
|
|
45
|
+
# ever holds a UTC literal from `Time.utc`) would bake a host-dependent wall clock /
|
|
46
|
+
# `utc_offset` into the inferred type. Blocked so the fold stays machine-independent; the RBS
|
|
47
|
+
# tier answers `Nominal[Time]`. `getutc` / `getgm` stay foldable — their result is UTC.
|
|
64
48
|
:getlocal
|
|
65
49
|
]
|
|
66
50
|
}
|
|
@@ -6,73 +6,55 @@ module Rigor
|
|
|
6
6
|
module Inference
|
|
7
7
|
# Slice 6 phase C sub-phase 3a — closure-escape classification.
|
|
8
8
|
#
|
|
9
|
-
# Given a `(receiver_type, method_name)` pair representing a
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# synchronously**, without retaining the block past the call?
|
|
9
|
+
# Given a `(receiver_type, method_name)` pair representing a block-accepting call, this analyzer answers
|
|
10
|
+
# one question: does the receiver's method invoke its block **immediately and synchronously**, without
|
|
11
|
+
# retaining the block past the call?
|
|
13
12
|
#
|
|
14
13
|
# The answer is one of three outcomes:
|
|
15
14
|
#
|
|
16
|
-
# - `:non_escaping` — the block is proven to be invoked
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# the block
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# - `:unknown` — the analyzer cannot prove either edge. Callers
|
|
27
|
-
# MUST treat `:unknown` as conservatively as `:escaping` for
|
|
28
|
-
# the purposes of fact retention; the distinction exists so
|
|
29
|
-
# diagnostics and later RBS-Extended effect plumbing can
|
|
30
|
-
# tell "deliberately conservative" apart from "declared
|
|
31
|
-
# escape".
|
|
15
|
+
# - `:non_escaping` — the block is proven to be invoked immediately, zero or more times, and is NOT
|
|
16
|
+
# retained past the call. The receiver does not store the block in an instance variable, return it as a
|
|
17
|
+
# value, or schedule it for later invocation. Outer-local narrowing facts that survive the block body
|
|
18
|
+
# MAY safely survive the call.
|
|
19
|
+
# - `:escaping` — the block is proven to be retained past the call (stored, returned, or invoked
|
|
20
|
+
# asynchronously). Outer narrowing facts on locals the block can rebind MUST be dropped at the call
|
|
21
|
+
# boundary.
|
|
22
|
+
# - `:unknown` — the analyzer cannot prove either edge. Callers MUST treat `:unknown` as conservatively as
|
|
23
|
+
# `:escaping` for the purposes of fact retention; the distinction exists so diagnostics and later
|
|
24
|
+
# RBS-Extended effect plumbing can tell "deliberately conservative" apart from "declared escape".
|
|
32
25
|
#
|
|
33
26
|
# ## Catalogue
|
|
34
27
|
#
|
|
35
|
-
# Sub-phase 3a is RBS-blind: it ships a hardcoded catalogue
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
# core-and-stdlib surface where immediate invocation is part of
|
|
40
|
-
# the documented contract:
|
|
28
|
+
# Sub-phase 3a is RBS-blind: it ships a hardcoded catalogue keyed by Ruby class name. A future sub-phase
|
|
29
|
+
# will replace this with an `RBS::Extended` call-timing effect read from method signatures. The catalogue
|
|
30
|
+
# therefore covers ONLY the core-and-stdlib surface where immediate invocation is part of the documented
|
|
31
|
+
# contract:
|
|
41
32
|
#
|
|
42
|
-
# - `Array`, `Hash`, `Range`, `Integer`, `Enumerator::Lazy`
|
|
43
|
-
#
|
|
44
|
-
# `
|
|
45
|
-
# `
|
|
46
|
-
# `
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
# `collect`, `collect_concat`, `filter`, `filter_map`).
|
|
50
|
-
# - `Hash`-only iteration: `each_pair`, `each_key`, `each_value`,
|
|
51
|
-
# `transform_keys`, `transform_values`.
|
|
52
|
-
# - `Integer#times`, `Integer#upto`, `Integer#downto`,
|
|
53
|
-
# `Range#each`, `Range#step`.
|
|
33
|
+
# - `Array`, `Hash`, `Range`, `Integer`, `Enumerator::Lazy` iteration methods (`each`, `map`, `select`,
|
|
34
|
+
# `reject`, `flat_map`, `find`/`detect`, `any?`, `all?`, `none?`, `one?`, `count`, `inject`/`reduce`,
|
|
35
|
+
# `each_with_index`, `each_with_object`, `min_by`, `max_by`, `sort_by`, `partition`, `group_by`,
|
|
36
|
+
# `tally`, `sum`, `take_while`, `drop_while`, `chunk_while`, `slice_when`, `zip`, `collect`,
|
|
37
|
+
# `collect_concat`, `filter`, `filter_map`).
|
|
38
|
+
# - `Hash`-only iteration: `each_pair`, `each_key`, `each_value`, `transform_keys`, `transform_values`.
|
|
39
|
+
# - `Integer#times`, `Integer#upto`, `Integer#downto`, `Range#each`, `Range#step`.
|
|
54
40
|
# - `Object#tap`, `Object#then`, `Object#yield_self`.
|
|
55
|
-
# - Tuple/HashShape carriers map to Array/Hash for catalogue
|
|
56
|
-
#
|
|
41
|
+
# - Tuple/HashShape carriers map to Array/Hash for catalogue lookup so a literal `[1, 2, 3].each { ... }`
|
|
42
|
+
# is recognised.
|
|
57
43
|
#
|
|
58
|
-
# Anything outside the catalogue resolves to `:unknown`. The
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
# catalogue would silently weaken the soundness of fact
|
|
63
|
-
# retention in later sub-phases.
|
|
44
|
+
# Anything outside the catalogue resolves to `:unknown`. The catalogue is intentionally narrow: adding
|
|
45
|
+
# entries requires confirming, by reading the method's stdlib documentation, that the block is not
|
|
46
|
+
# retained. False positives in this catalogue would silently weaken the soundness of fact retention in
|
|
47
|
+
# later sub-phases.
|
|
64
48
|
#
|
|
65
|
-
# The analyzer is a pure query. It MUST NOT mutate the
|
|
66
|
-
#
|
|
67
|
-
# inputs, and MUST be deterministic for a given input.
|
|
49
|
+
# The analyzer is a pure query. It MUST NOT mutate the receiver type or scope, MUST NOT raise on
|
|
50
|
+
# unrecognised inputs, and MUST be deterministic for a given input.
|
|
68
51
|
module ClosureEscapeAnalyzer
|
|
69
52
|
module_function
|
|
70
53
|
|
|
71
54
|
# @param receiver_type [Rigor::Type, nil]
|
|
72
55
|
# @param method_name [Symbol]
|
|
73
|
-
# @param environment [Rigor::Environment, nil] reserved for the
|
|
74
|
-
#
|
|
75
|
-
# effects; sub-phase 3a ignores it.
|
|
56
|
+
# @param environment [Rigor::Environment, nil] reserved for the future sub-phase that consults
|
|
57
|
+
# `RBS::Extended` call-timing effects; sub-phase 3a ignores it.
|
|
76
58
|
# @return [Symbol] one of `:non_escaping`, `:escaping`, `:unknown`.
|
|
77
59
|
def classify(receiver_type:, method_name:, environment: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
78
60
|
return :unknown if receiver_type.nil?
|
|
@@ -90,14 +72,11 @@ module Rigor
|
|
|
90
72
|
class << self
|
|
91
73
|
private
|
|
92
74
|
|
|
93
|
-
# Resolve a single concrete class name for catalogue lookup.
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
# a singleton call, but the catalogue today only lists
|
|
99
|
-
# instance-side methods on `Integer`, so a hit there would
|
|
100
|
-
# be unsurprising — kept for forward consistency).
|
|
75
|
+
# Resolve a single concrete class name for catalogue lookup. Returns `nil` when the receiver carrier
|
|
76
|
+
# does not name a single class (e.g. `Top`, `Dynamic[Top]`, `Union[...]`, `Bot`). `Tuple` projects to
|
|
77
|
+
# `Array`; `HashShape` to `Hash`; `Singleton[C]` to `C` (so `Integer.times` would resolve as a
|
|
78
|
+
# singleton call, but the catalogue today only lists instance-side methods on `Integer`, so a hit
|
|
79
|
+
# there would be unsurprising — kept for forward consistency).
|
|
101
80
|
def receiver_class_name(receiver_type)
|
|
102
81
|
case receiver_type
|
|
103
82
|
when Type::Nominal, Type::Singleton then receiver_type.class_name
|
|
@@ -107,10 +86,9 @@ module Rigor
|
|
|
107
86
|
end
|
|
108
87
|
end
|
|
109
88
|
|
|
110
|
-
# `Rigor::Type::Constant` only carries scalar literals
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
# values, so we only project from those scalar shapes here.
|
|
89
|
+
# `Rigor::Type::Constant` only carries scalar literals (`Integer`, `Float`, `String`, `Symbol`,
|
|
90
|
+
# `Range`, booleans, `nil`); the carrier explicitly rejects mutable container values, so we only
|
|
91
|
+
# project from those scalar shapes here.
|
|
114
92
|
CONSTANT_CLASS_NAMES = {
|
|
115
93
|
Integer => "Integer",
|
|
116
94
|
String => "String",
|
|
@@ -176,9 +154,8 @@ module Rigor
|
|
|
176
154
|
"Enumerator::Lazy" => ENUMERABLE_NON_ESCAPING
|
|
177
155
|
}.freeze
|
|
178
156
|
|
|
179
|
-
# Methods that are documented to **retain** the block past the
|
|
180
|
-
#
|
|
181
|
-
# facts on writeable captured locals cannot survive.
|
|
157
|
+
# Methods that are documented to **retain** the block past the call. The block is stored or scheduled,
|
|
158
|
+
# so outer narrowing facts on writeable captured locals cannot survive.
|
|
182
159
|
ESCAPING = {
|
|
183
160
|
"Module" => %i[define_method].freeze,
|
|
184
161
|
"Class" => %i[define_method].freeze,
|
|
@@ -9,20 +9,17 @@ module Rigor
|
|
|
9
9
|
module Inference
|
|
10
10
|
# Walks an AST and reports per-node-class coverage of `Rigor::Scope#type_of`.
|
|
11
11
|
#
|
|
12
|
-
# For every visited node the scanner runs `type_of` with a fresh
|
|
13
|
-
#
|
|
12
|
+
# For every visited node the scanner runs `type_of` with a fresh `FallbackTracer` and inspects the first
|
|
13
|
+
# recorded event:
|
|
14
14
|
#
|
|
15
|
-
# * If the first event's `node_class` matches the visited node's class,
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# that itself was unrecognized; the visited node is counted as
|
|
20
|
-
# recognized so pass-through wrappers (`ProgramNode`, `StatementsNode`,
|
|
15
|
+
# * If the first event's `node_class` matches the visited node's class, the engine entered the fallback
|
|
16
|
+
# (else) branch *for this very node* — the node is counted as **directly unrecognized**.
|
|
17
|
+
# * Otherwise the typer either succeeded outright or recursed into a child that itself was unrecognized;
|
|
18
|
+
# the visited node is counted as recognized so pass-through wrappers (`ProgramNode`, `StatementsNode`,
|
|
21
19
|
# `ParenthesesNode`, ...) are not double-counted along with their leaves.
|
|
22
20
|
#
|
|
23
|
-
# This class is intended for tooling probes and CI gates rather than the
|
|
24
|
-
#
|
|
25
|
-
# the inferred type values.
|
|
21
|
+
# This class is intended for tooling probes and CI gates rather than the hot inference path: it allocates
|
|
22
|
+
# a tracer per visited node and discards the inferred type values.
|
|
26
23
|
class CoverageScanner
|
|
27
24
|
class Result < Data.define(:visits, :unrecognized, :events)
|
|
28
25
|
# @return [Integer] sum of all visits across node classes.
|
|
@@ -56,13 +53,11 @@ module Rigor
|
|
|
56
53
|
unrecognized = Hash.new(0)
|
|
57
54
|
events = []
|
|
58
55
|
|
|
59
|
-
# Build the per-node scope index once per scan so locals bound
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
# second pass below re-types each node with its own tracer so
|
|
65
|
-
# the per-class fallback statistics stay attributable.
|
|
56
|
+
# Build the per-node scope index once per scan so locals bound earlier in the program flow into the
|
|
57
|
+
# scope used to type every later node. The indexer walks the program with a tracer-less
|
|
58
|
+
# StatementEvaluator and propagates the recorded scope down to expression-interior nodes the evaluator
|
|
59
|
+
# does not visit. The second pass below re-types each node with its own tracer so the per-class
|
|
60
|
+
# fallback statistics stay attributable.
|
|
66
61
|
scope_index = ScopeIndexer.index(root, default_scope: @scope)
|
|
67
62
|
|
|
68
63
|
Source::NodeWalker.each(root) do |node|
|
|
@@ -6,22 +6,17 @@ require_relative "../type"
|
|
|
6
6
|
|
|
7
7
|
module Rigor
|
|
8
8
|
module Inference
|
|
9
|
-
# Returns the inferred return type of a `Prism::DefNode`, or nil
|
|
10
|
-
#
|
|
11
|
-
# or any failure during inference — caller surfaces "no
|
|
12
|
-
# annotation" on a nil).
|
|
9
|
+
# Returns the inferred return type of a `Prism::DefNode`, or nil when no type can be derived (empty body,
|
|
10
|
+
# scope-lookup miss, or any failure during inference — caller surfaces "no annotation" on a nil).
|
|
13
11
|
#
|
|
14
12
|
# The inferred type is the union of:
|
|
15
13
|
#
|
|
16
14
|
# - the body's last-statement type, and
|
|
17
|
-
# - the type of every explicit `return value` reachable in the
|
|
18
|
-
#
|
|
19
|
-
# barriers — their `return`s do not bubble up to the enclosing
|
|
20
|
-
# method.
|
|
15
|
+
# - the type of every explicit `return value` reachable in the body. Nested `def` / lambda / block bodies
|
|
16
|
+
# are return barriers — their `return`s do not bubble up to the enclosing method.
|
|
21
17
|
#
|
|
22
|
-
# Extracted from `Rigor::SigGen::Generator#infer_return_type` so
|
|
23
|
-
#
|
|
24
|
-
# and the sig-generator share one source of truth.
|
|
18
|
+
# Extracted from `Rigor::SigGen::Generator#infer_return_type` so `LineTypeCollector` (`rigor annotate`'s
|
|
19
|
+
# def-line annotator) and the sig-generator share one source of truth.
|
|
25
20
|
module DefReturnTyper
|
|
26
21
|
RETURN_BARRIER_NODES = [Prism::DefNode, Prism::LambdaNode, Prism::BlockNode].freeze
|
|
27
22
|
private_constant :RETURN_BARRIER_NODES
|
|
@@ -79,9 +74,8 @@ module Rigor
|
|
|
79
74
|
|
|
80
75
|
scope = scope_index[return_node] || scope_index[args.first]
|
|
81
76
|
return if scope.nil?
|
|
82
|
-
# `return a, b` packs into a Tuple at runtime; the MVP only
|
|
83
|
-
#
|
|
84
|
-
# contribute no type to keep the implementation focused.
|
|
77
|
+
# `return a, b` packs into a Tuple at runtime; the MVP only handles the single-value form. Multi-arg
|
|
78
|
+
# returns contribute no type to keep the implementation focused.
|
|
85
79
|
return unless args.size == 1
|
|
86
80
|
|
|
87
81
|
type = safe_type_of(scope, args.first)
|
|
@@ -2,16 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Inference
|
|
5
|
-
# ADR-75 v1 cause set — precision-additive provenance for Dynamic[T]
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# holes (e.g. an explicit `untyped` RBS signature) from intractable
|
|
10
|
-
# ones (e.g. unsupported syntax).
|
|
5
|
+
# ADR-75 v1 cause set — precision-additive provenance for Dynamic[T] introduction sites. Each symbol
|
|
6
|
+
# identifies a distinct family of reason that an expression widened to Dynamic, surfaced by
|
|
7
|
+
# `rigor coverage --protection` so users can distinguish tractable holes (e.g. an explicit `untyped` RBS
|
|
8
|
+
# signature) from intractable ones (e.g. unsupported syntax).
|
|
11
9
|
#
|
|
12
|
-
# Provenance is a side-channel: it never participates in subtyping,
|
|
13
|
-
#
|
|
14
|
-
# from it.
|
|
10
|
+
# Provenance is a side-channel: it never participates in subtyping, consistency, normalization, or
|
|
11
|
+
# erasure, and no diagnostic fires from it.
|
|
15
12
|
module DynamicOrigin
|
|
16
13
|
# A gem with no resolvable RBS.
|
|
17
14
|
EXTERNAL_GEM_WITHOUT_RBS = :external_gem_without_rbs
|
|
@@ -21,6 +18,13 @@ module Rigor
|
|
|
21
18
|
ANALYZER_BUDGET_CUTOFF = :analyzer_budget_cutoff
|
|
22
19
|
# Authored `untyped` contract.
|
|
23
20
|
EXPLICIT_UNTYPED = :explicit_untyped
|
|
21
|
+
# The engine cannot yet infer a value's type although it is not unmodeled syntax and no RBS declared
|
|
22
|
+
# it `untyped`: a resolved user/ancestor method whose return body it cannot fold, or an undeclared
|
|
23
|
+
# method *parameter* with no call-site type flowing in (`def f(x); x.foo`). The lever is inference —
|
|
24
|
+
# parameter inference (ADR-67) or ivar-field typing (ADR-58) — not a hand-written type, so it is an
|
|
25
|
+
# engine gap that routes to that roadmap rather than to "add RBS". (The `_return_` in the name is
|
|
26
|
+
# historical; it now covers the parameter case too.)
|
|
27
|
+
INFERRED_RETURN_UNTYPED = :inferred_return_untyped
|
|
24
28
|
# Inference fallback on unmodeled construct.
|
|
25
29
|
UNSUPPORTED_SYNTAX = :unsupported_syntax
|
|
26
30
|
|
|
@@ -29,20 +33,18 @@ module Rigor
|
|
|
29
33
|
FRAMEWORK_DSL_BOUNDARY,
|
|
30
34
|
ANALYZER_BUDGET_CUTOFF,
|
|
31
35
|
EXPLICIT_UNTYPED,
|
|
36
|
+
INFERRED_RETURN_UNTYPED,
|
|
32
37
|
UNSUPPORTED_SYNTAX
|
|
33
38
|
].freeze
|
|
34
39
|
|
|
35
|
-
# ADR-73 P6 / ADR-75 WD2 — tractability: given the cause, can a user
|
|
36
|
-
#
|
|
37
|
-
# surfaces it so a user does not chase a hole a hand-written type
|
|
40
|
+
# ADR-73 P6 / ADR-75 WD2 — tractability: given the cause, can a user close this `Dynamic` hole, and on
|
|
41
|
+
# which axis. `coverage --protection` surfaces it so a user does not chase a hole a hand-written type
|
|
38
42
|
# cannot fix. Three coarse, action-oriented categories:
|
|
39
43
|
#
|
|
40
|
-
# - `:add_rbs` — write or install RBS (a missing gem signature,
|
|
41
|
-
#
|
|
42
|
-
# - `:enable_plugin`— a framework / DSL boundary; needs a plugin or
|
|
43
|
-
#
|
|
44
|
-
# - `:engine_gap` — not user-closable (a budget cutoff or unmodeled
|
|
45
|
-
# syntax); report it.
|
|
44
|
+
# - `:add_rbs` — write or install RBS (a missing gem signature, or an authored `untyped` to
|
|
45
|
+
# tighten).
|
|
46
|
+
# - `:enable_plugin`— a framework / DSL boundary; needs a plugin or `pre_eval:`, not a hand-written type.
|
|
47
|
+
# - `:engine_gap` — not user-closable (a budget cutoff or unmodeled syntax); report it.
|
|
46
48
|
ADD_RBS = :add_rbs
|
|
47
49
|
ENABLE_PLUGIN = :enable_plugin
|
|
48
50
|
ENGINE_GAP = :engine_gap
|
|
@@ -52,13 +54,14 @@ module Rigor
|
|
|
52
54
|
EXPLICIT_UNTYPED => ADD_RBS,
|
|
53
55
|
FRAMEWORK_DSL_BOUNDARY => ENABLE_PLUGIN,
|
|
54
56
|
ANALYZER_BUDGET_CUTOFF => ENGINE_GAP,
|
|
57
|
+
INFERRED_RETURN_UNTYPED => ENGINE_GAP,
|
|
55
58
|
UNSUPPORTED_SYNTAX => ENGINE_GAP
|
|
56
59
|
}.freeze
|
|
57
60
|
|
|
58
61
|
module_function
|
|
59
62
|
|
|
60
|
-
# @return [Symbol, nil] the tractability category for a cause, or nil
|
|
61
|
-
#
|
|
63
|
+
# @return [Symbol, nil] the tractability category for a cause, or nil when the cause is unknown /
|
|
64
|
+
# absent.
|
|
62
65
|
def tractability(cause)
|
|
63
66
|
TRACTABILITY[cause]
|
|
64
67
|
end
|