rigortype 0.3.8 → 0.3.9
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/data/capability_roles/capability_roles.rbs +36 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +109 -13
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +37 -4
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +14 -1
- data/docs/handbook/11-sig-gen.md +72 -1
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +32 -4
- data/docs/manual/03-configuration.md +11 -0
- data/docs/manual/04-diagnostics.md +11 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +6 -1
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/plugins/rigor-actionpack.md +18 -0
- data/docs/manual/plugins/rigor-activerecord.md +28 -0
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +32 -2
- data/docs/manual/plugins/rigor-rbs-inline.md +42 -1
- data/lib/rigor/analysis/baseline.rb +2 -2
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +39 -4
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +200 -32
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +6 -1
- data/lib/rigor/analysis/incremental.rb +16 -0
- data/lib/rigor/analysis/incremental_session.rb +81 -22
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +2 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +4 -1
- data/lib/rigor/analysis/run_cache_key.rb +1 -1
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +177 -26
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -10
- data/lib/rigor/analysis/runner/pool_coordinator.rb +256 -88
- data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +133 -35
- data/lib/rigor/analysis/worker_session.rb +9 -10
- data/lib/rigor/bleeding_edge.rb +12 -24
- data/lib/rigor/builtins/hkt_builtins.rb +2 -2
- data/lib/rigor/builtins/imported_refinements.rb +155 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +4 -4
- data/lib/rigor/builtins/static_return_refinements.rb +5 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +58 -20
- data/lib/rigor/cache/engine_source.rb +4 -4
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +40 -6
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +79 -11
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +77 -32
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +3 -3
- data/lib/rigor/cli/docs_command.rb +2 -2
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +1 -1
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +2 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +2 -2
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +36 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +10 -6
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +68 -6
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +6 -6
- data/lib/rigor/configuration.rb +43 -4
- data/lib/rigor/effects/attribution.rb +1 -3
- data/lib/rigor/effects/config_envelopes.rb +6 -8
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +0 -1
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +8 -8
- data/lib/rigor/effects/envelope_index.rb +5 -8
- data/lib/rigor/effects/framework_units.rb +4 -6
- data/lib/rigor/effects/identity.rb +4 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/method_key.rb +1 -1
- data/lib/rigor/effects/plugin_facts.rb +4 -6
- data/lib/rigor/effects/propagator.rb +2 -3
- data/lib/rigor/effects/scanner.rb +1 -1
- data/lib/rigor/effects/signature_sources.rb +3 -5
- data/lib/rigor/effects/snapshot.rb +10 -10
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/unit_scan.rb +10 -10
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +51 -4
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +388 -59
- data/lib/rigor/environment.rb +105 -20
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/inference/acceptance.rb +153 -8
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/body_fixpoint.rb +5 -5
- data/lib/rigor/inference/budget_trace.rb +1 -5
- data/lib/rigor/inference/captured_locals.rb +2 -3
- data/lib/rigor/inference/closure_escape_analyzer.rb +2 -4
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +168 -0
- data/lib/rigor/inference/expression_typer.rb +763 -143
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +1 -5
- data/lib/rigor/inference/macro_block_self_type.rb +1 -4
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +2 -9
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +61 -47
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +165 -31
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +4 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +12 -13
- data/lib/rigor/inference/method_parameter_binder.rb +4 -6
- data/lib/rigor/inference/multi_target_binder.rb +1 -3
- data/lib/rigor/inference/mutation_rejoin.rb +168 -0
- data/lib/rigor/inference/mutation_widening.rb +100 -51
- data/lib/rigor/inference/narrowing.rb +299 -46
- data/lib/rigor/inference/optimistic_origin.rb +1 -7
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_patched_methods.rb +2 -2
- data/lib/rigor/inference/project_patched_scanner.rb +3 -3
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +3 -3
- data/lib/rigor/inference/refinement_mutation.rb +72 -0
- data/lib/rigor/inference/scope_indexer.rb +688 -151
- data/lib/rigor/inference/statement_evaluator.rb +221 -50
- data/lib/rigor/inference/string_mutation.rb +60 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +1 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +2 -2
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +2 -5
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/plugin/base.rb +90 -21
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +7 -7
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +31 -12
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +23 -1
- data/lib/rigor/plugin/registry.rb +42 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +12 -1
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +11 -11
- data/lib/rigor/protection/kill_signature.rb +2 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +6 -9
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +61 -21
- data/lib/rigor/reflection/constant_path.rb +126 -0
- data/lib/rigor/reflection.rb +26 -10
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +30 -0
- data/lib/rigor/scope.rb +203 -4
- data/lib/rigor/sig_gen/generator.rb +115 -22
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/observation_collector.rb +17 -15
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +4 -5
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +111 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/writer.rb +23 -6
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +2 -5
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +68 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +5 -5
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +3 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +1 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +33 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +28 -2
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +1 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +3 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +42 -7
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +119 -14
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +1 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +6 -3
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +0 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +1 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +1 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +3 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -0
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +128 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +1 -0
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +5 -5
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/environment.rbs +5 -0
- data/sig/rigor/inference.rbs +3 -10
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/manifest.rbs +2 -1
- data/sig/rigor/reflection.rbs +3 -1
- data/sig/rigor/scope.rbs +24 -3
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -0
- data/sig/rigor/type.rbs +27 -1
- data/sig/rigor.rbs +1 -0
- data/skills/rigor-ask/SKILL.md +8 -6
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +13 -2
- data/skills/rigor-project-init/SKILL.md +6 -3
- data/skills/rigor-project-init/references/02-configure.md +10 -6
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-type-oracle/SKILL.md +228 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +261 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +128 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +8 -5
- metadata +26 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
data/lib/rigor/environment.rb
CHANGED
|
@@ -13,6 +13,7 @@ require_relative "environment/constant_type_cache_holder"
|
|
|
13
13
|
require_relative "environment/missing_gem_constant_index"
|
|
14
14
|
require_relative "environment/bundle_sig_discovery"
|
|
15
15
|
require_relative "environment/lockfile_resolver"
|
|
16
|
+
require_relative "environment/installed_gem_set"
|
|
16
17
|
require_relative "environment/rbs_collection_discovery"
|
|
17
18
|
require_relative "plugin/isolation"
|
|
18
19
|
require_relative "environment/rbs_coverage_report"
|
|
@@ -48,16 +49,15 @@ module Rigor
|
|
|
48
49
|
:reporters, :name_scope,
|
|
49
50
|
:synthetic_method_index, :project_patched_methods
|
|
50
51
|
|
|
51
|
-
# @param
|
|
52
|
-
# @param rbs_loader [Rigor::Environment::RbsLoader, nil] when nil the environment is "RBS-blind"; useful
|
|
52
|
+
# @param rbs_loader — when nil the environment is "RBS-blind"; useful
|
|
53
53
|
# in tests that want to assert how the engine behaves without RBS data. The default Environment wires
|
|
54
54
|
# the shared core loader, which is itself lazy: requesting an environment instance does NOT load RBS
|
|
55
55
|
# until a method or class query actually consults the loader.
|
|
56
|
-
# @param plugin_registry
|
|
56
|
+
# @param plugin_registry — v0.1.1 Track 2 slice 7. The per-run plugin
|
|
57
57
|
# registry the inference engine consults at call sites for plugin `dynamic_return` rules. When nil
|
|
58
58
|
# (the default), no plugin-level return-type contribution participates — useful for tests, the
|
|
59
59
|
# `Environment.default` facade, and analyses that don't load plugins.
|
|
60
|
-
# @param dependency_source_index
|
|
60
|
+
# @param dependency_source_index — ADR-10 slice
|
|
61
61
|
# 2b-ii. The per-run index of opt-in gem sources the dispatcher consults BELOW RBS dispatch. When nil
|
|
62
62
|
# (the default), no dep-source contribution participates and the dispatcher tier is a no-op.
|
|
63
63
|
def initialize(class_registry: ClassRegistry.default, rbs_loader: nil, # rubocop:disable Metrics/ParameterLists
|
|
@@ -151,7 +151,7 @@ module Rigor
|
|
|
151
151
|
# defect. First-write-wins on the slot means a run whose overlay AND scan both raise reports the
|
|
152
152
|
# overlay — the actionable one, since the plugin is what a user can remove.
|
|
153
153
|
#
|
|
154
|
-
# @return
|
|
154
|
+
# @return the registry the RBS scan is layered on top of.
|
|
155
155
|
def pre_scan_hkt_registry
|
|
156
156
|
return @hkt_registry_base unless @plugin_registry.respond_to?(:hkt_overlay_registry)
|
|
157
157
|
|
|
@@ -171,8 +171,6 @@ module Rigor
|
|
|
171
171
|
# worker (the coordinator never analyses a file under the pool, so the drain is how its snapshot learns
|
|
172
172
|
# the outcome: the #696 lesson), and from a resolved environment when the analyze set is empty — so the
|
|
173
173
|
# row never depends on which files happened to be analysed.
|
|
174
|
-
#
|
|
175
|
-
# @return [Array(String, String, String, Symbol), Array(String, String, nil, Symbol), nil]
|
|
176
174
|
def hkt_scan_failure
|
|
177
175
|
@hkt_scan_failure.value
|
|
178
176
|
end
|
|
@@ -255,18 +253,17 @@ module Rigor
|
|
|
255
253
|
# Builds an Environment that consults the project's local signatures and any opt-in stdlib libraries on
|
|
256
254
|
# top of RBS core.
|
|
257
255
|
#
|
|
258
|
-
# @param root
|
|
256
|
+
# @param root — project root used to auto-detect the default signature path. Defaults
|
|
259
257
|
# to the current working directory.
|
|
260
|
-
# @param libraries
|
|
258
|
+
# @param libraries — additional stdlib libraries to load on top of
|
|
261
259
|
# {DEFAULT_LIBRARIES}. The final list is the union of the two, de-duplicated while preserving order.
|
|
262
260
|
# Pass an empty array (the default) to load only the defaults.
|
|
263
|
-
# @param signature_paths
|
|
261
|
+
# @param signature_paths — explicit list of `sig/`-style directories. When
|
|
264
262
|
# `nil` (the default), the canonical project layout `<root>/sig` is used if it exists, otherwise no
|
|
265
263
|
# signature path is loaded.
|
|
266
|
-
# @param cache_store
|
|
264
|
+
# @param cache_store — persistent cache threaded into the underlying
|
|
267
265
|
# {Environment::RbsLoader} so constant lookups (and, in later v0.0.9 slices, other reflection
|
|
268
266
|
# artefacts) consult the cache. Pass `nil` (the default) to skip caching for this environment.
|
|
269
|
-
# @return [Rigor::Environment]
|
|
270
267
|
# rubocop:disable-next Metrics/MethodLength, Metrics/ParameterLists
|
|
271
268
|
def for_project(root: Dir.pwd, libraries: [], signature_paths: nil, cache_store: nil,
|
|
272
269
|
plugin_registry: nil, dependency_source_index: nil,
|
|
@@ -336,7 +333,7 @@ module Rigor
|
|
|
336
333
|
missing_gems, overlay_paths = missing_gems_and_overlay_paths(
|
|
337
334
|
locked: locked, default_libraries: merged_libraries, bundle_sig_paths: gem_sig_paths,
|
|
338
335
|
rbs_collection_paths: collection_paths, plugin_registry: plugin_registry,
|
|
339
|
-
signature_paths: resolved_paths
|
|
336
|
+
signature_paths: resolved_paths, bundle_root: bundle_root
|
|
340
337
|
)
|
|
341
338
|
loader_signature_paths = resolved_paths + plugin_sig_paths + gem_sig_paths +
|
|
342
339
|
collection_paths + overlay_paths
|
|
@@ -361,6 +358,13 @@ module Rigor
|
|
|
361
358
|
# the bundle walk and `rbs collection install` all stay authoritative.
|
|
362
359
|
deferred_signature_paths: plugin_sig_paths
|
|
363
360
|
)
|
|
361
|
+
# Issue #824 / ADR-32 WD13 — one `:info` per inline member the loader stood down against the
|
|
362
|
+
# project's own `sig/`. Recorded HERE because this is where the reporter is: the run's
|
|
363
|
+
# `source_rbs_synthesis` stream already carries WD12's "parsed but not honoured" rows, drains out of
|
|
364
|
+
# pool workers, and is regenerated (never cached) on every run, so the member-level stand-down needs
|
|
365
|
+
# no plumbing of its own. Costs nothing for a project with no inline RBS: the loader's reader
|
|
366
|
+
# short-circuits on an empty `virtual_rbs`.
|
|
367
|
+
record_inline_member_standdowns(loader, source_rbs_synthesis_reporter, root)
|
|
364
368
|
# ADR-20 slice 2c + 2e — seed hkt_registry with the bundled builtins. The Environment's
|
|
365
369
|
# `#hkt_registry` getter then LAZILY merges in the RBS env scan on first call so fast paths that
|
|
366
370
|
# don't consult HKT (e.g. `rigor check --cache-stats --no-stats`) don't pay the eager env-build cost
|
|
@@ -412,13 +416,13 @@ module Rigor
|
|
|
412
416
|
# and consumed twice: as `[gem_name, version]` pairs for the ADR-82 WD9 constant-ownership index, and
|
|
413
417
|
# as the eligible-gem set for the ADR-72 overlay resolution. Returns `[pairs, overlay_paths]`.
|
|
414
418
|
def missing_gems_and_overlay_paths(locked:, default_libraries:, bundle_sig_paths:,
|
|
415
|
-
rbs_collection_paths:, plugin_registry:, signature_paths: []
|
|
416
|
-
|
|
419
|
+
rbs_collection_paths:, plugin_registry:, signature_paths: [],
|
|
420
|
+
bundle_root: nil)
|
|
421
|
+
if locked.empty?
|
|
422
|
+
return unlocked_missing_gems(default_libraries, bundle_sig_paths, rbs_collection_paths, bundle_root)
|
|
423
|
+
end
|
|
417
424
|
|
|
418
|
-
rows =
|
|
419
|
-
locked_gems: locked, default_libraries: default_libraries,
|
|
420
|
-
bundle_sig_paths: bundle_sig_paths, rbs_collection_paths: rbs_collection_paths
|
|
421
|
-
).select { |row| row.source == :missing }
|
|
425
|
+
rows = missing_rows(locked, default_libraries, bundle_sig_paths, rbs_collection_paths)
|
|
422
426
|
overlays = gem_overlay_paths(
|
|
423
427
|
missing_gem_names: rows.map(&:gem_name), plugin_registry: plugin_registry,
|
|
424
428
|
signature_paths: signature_paths
|
|
@@ -426,6 +430,27 @@ module Rigor
|
|
|
426
430
|
[rows.map { |row| [row.gem_name, row.version] }, overlays]
|
|
427
431
|
end
|
|
428
432
|
|
|
433
|
+
# Issue #530 — a project with no `Gemfile.lock` still has gems on disk, and before this it handed the
|
|
434
|
+
# ADR-82 WD9 index nothing, so every constant reaching into an RBS-less gem kept the generic cause and
|
|
435
|
+
# the whole boundary reported as `engine_gap` rather than `add_rbs`. The installed set stands in for
|
|
436
|
+
# the locked one ({InstalledGemSet} says why that stays honest), and only for the provenance index:
|
|
437
|
+
# the second element is always empty because the ADR-72 overlays change what type-checks and so remain
|
|
438
|
+
# gated on the project's own declaration.
|
|
439
|
+
def unlocked_missing_gems(default_libraries, bundle_sig_paths, rbs_collection_paths, bundle_root)
|
|
440
|
+
installed = InstalledGemSet.gems(bundle_path: bundle_root)
|
|
441
|
+
return [[], []] if installed.empty?
|
|
442
|
+
|
|
443
|
+
rows = missing_rows(installed, default_libraries, bundle_sig_paths, rbs_collection_paths)
|
|
444
|
+
[rows.map { |row| [row.gem_name, row.version] }, []]
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
def missing_rows(gems, default_libraries, bundle_sig_paths, rbs_collection_paths)
|
|
448
|
+
RbsCoverageReport.classify(
|
|
449
|
+
locked_gems: gems, default_libraries: default_libraries,
|
|
450
|
+
bundle_sig_paths: bundle_sig_paths, rbs_collection_paths: rbs_collection_paths
|
|
451
|
+
).select { |row| row.source == :missing }
|
|
452
|
+
end
|
|
453
|
+
|
|
429
454
|
# ADR-72 — resolve the bundled RBS overlay directories to load for this project. A gem is eligible when
|
|
430
455
|
# it is classified `:missing` (see {missing_rbs_gem_rows}) and its conflicting opt-in plugin twin (if
|
|
431
456
|
# any) is NOT already reachable. Returns `[Pathname]`, deterministically ordered, or `[]` when no
|
|
@@ -540,6 +565,54 @@ module Rigor
|
|
|
540
565
|
reporter&.record(plugin_id: plugin.manifest.id, path: path, message: message.to_s, kind: kind)
|
|
541
566
|
end
|
|
542
567
|
|
|
568
|
+
# ADR-32 WD13 — turn each {Environment::RbsLoader#inline_member_standdowns} record into a WD12
|
|
569
|
+
# `:not_honoured` entry, so the run's `plugin.rbs-inline.source-rbs-annotation-not-honoured` row names
|
|
570
|
+
# BOTH sources and which one won. WD12's rule is what makes this necessary rather than optional: an
|
|
571
|
+
# annotation Rigor parses and does not honour is reported, never swallowed — and a silent per-member
|
|
572
|
+
# strip is exactly the shape that rule forbids.
|
|
573
|
+
#
|
|
574
|
+
# The row is positioned at the annotated `.rb` (line 1, as every entry on this stream is): the member's
|
|
575
|
+
# own position lives in the synthesized RBS buffer, which describes a document nobody has, and the
|
|
576
|
+
# ADR-54 environment cache drops positions anyway, so a line read off it would differ warm and cold.
|
|
577
|
+
def record_inline_member_standdowns(loader, reporter, root)
|
|
578
|
+
return if reporter.nil?
|
|
579
|
+
|
|
580
|
+
loader.inline_member_standdowns.each do |class_name, method_name, kind, signature_path, virtual_name|
|
|
581
|
+
plugin_id, path = split_virtual_source_name(virtual_name)
|
|
582
|
+
next if path.nil?
|
|
583
|
+
|
|
584
|
+
reporter.record(
|
|
585
|
+
plugin_id: plugin_id, path: path, kind: :not_honoured,
|
|
586
|
+
message: inline_member_standdown_message(class_name, method_name, kind, signature_path, root)
|
|
587
|
+
)
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
# Splits a virtual buffer name back into the pair {.collect_virtual_rbs} composed it from
|
|
592
|
+
# (`virtual:<plugin id>:<source path>`). Limited to three fields so a path carrying a colon survives.
|
|
593
|
+
# Returns `[nil, nil]` for a name in any other shape — a synthesizer channel this method does not own.
|
|
594
|
+
def split_virtual_source_name(virtual_name)
|
|
595
|
+
prefix, plugin_id, path = virtual_name.to_s.split(":", 3)
|
|
596
|
+
return [nil, nil] unless prefix == "virtual" && plugin_id && !plugin_id.empty? && path && !path.empty?
|
|
597
|
+
|
|
598
|
+
[plugin_id, path]
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
def inline_member_standdown_message(class_name, method_name, kind, signature_path, root)
|
|
602
|
+
separator = kind == :singleton ? "." : "#"
|
|
603
|
+
"`#{class_name}#{separator}#{method_name}` is also declared in " \
|
|
604
|
+
"`#{path_relative_to(signature_path, root)}`, and an explicit `.rbs` declaration wins over an " \
|
|
605
|
+
"inline annotation for the same member, so the inline signature was dropped. Left to collide the " \
|
|
606
|
+
"two would fail the class's definition build, and every call on it — real methods and typos " \
|
|
607
|
+
"alike — would read `Dynamic[top]`. Remove one of the two declarations to make the inline " \
|
|
608
|
+
"annotation bind."
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
def path_relative_to(path, root)
|
|
612
|
+
prefix = "#{root}#{File::SEPARATOR}"
|
|
613
|
+
path.to_s.start_with?(prefix) ? path.to_s.delete_prefix(prefix) : path.to_s
|
|
614
|
+
end
|
|
615
|
+
|
|
543
616
|
SYNTHESIZER_CACHE_PRODUCER_ID = "plugin.source_rbs_synthesizer"
|
|
544
617
|
private_constant :SYNTHESIZER_CACHE_PRODUCER_ID
|
|
545
618
|
|
|
@@ -653,6 +726,15 @@ module Rigor
|
|
|
653
726
|
rbs_loader.rbs_module?(name)
|
|
654
727
|
end
|
|
655
728
|
|
|
729
|
+
# Issue #915 — the module names RBS puts in `name`'s SINGLETON ancestry, the declaration-side twin of
|
|
730
|
+
# `Scope#singleton_extends_of`. `Inference::Narrowing` reads it the same one-directional way: presence
|
|
731
|
+
# withholds a `Bot`, absence asserts nothing (a class the environment does not know answers `[]`).
|
|
732
|
+
def singleton_extended_modules(name)
|
|
733
|
+
return [] unless rbs_loader
|
|
734
|
+
|
|
735
|
+
rbs_loader.singleton_extended_module_names(normalize_class_name(name))
|
|
736
|
+
end
|
|
737
|
+
|
|
656
738
|
# Compares two class/module names using analyzer-owned class data. Returns `:equal`, `:subclass`,
|
|
657
739
|
# `:superclass`, `:disjoint`, or `:unknown`. The static registry handles built-ins cheaply; the RBS
|
|
658
740
|
# loader handles project/stdlib classes without relying on host Ruby constants being loaded.
|
|
@@ -677,8 +759,11 @@ module Rigor
|
|
|
677
759
|
rbs_loader.class_known?(name)
|
|
678
760
|
end
|
|
679
761
|
|
|
762
|
+
# Allocates only when there is a prefix to strip: `String#delete_prefix` copies unconditionally, and
|
|
763
|
+
# this runs once per class-registry / hierarchy probe (~320k times on the lib self-check).
|
|
680
764
|
def normalize_class_name(name)
|
|
681
|
-
name.to_s
|
|
765
|
+
name = name.to_s
|
|
766
|
+
name.start_with?("::") ? name.delete_prefix("::") : name
|
|
682
767
|
end
|
|
683
768
|
|
|
684
769
|
# ADR-13 slice 3b — composes the per-run plugin-supplied {Rigor::TypeNode::ResolverChain} into a single
|
|
@@ -49,24 +49,24 @@ module Rigor
|
|
|
49
49
|
|
|
50
50
|
attr_reader(*SLOT_NAMES, :provenance)
|
|
51
51
|
|
|
52
|
-
# @param return_type
|
|
52
|
+
# @param return_type — normal-edge return type. Use `nil` when the contribution does not
|
|
53
53
|
# refine the return type selected from the RBS contract.
|
|
54
|
-
# @param truthy_facts
|
|
54
|
+
# @param truthy_facts — facts that hold only on the truthy control-flow edge. Edge-local: a
|
|
55
55
|
# truthy-edge fact does NOT imply its falsey-edge complement (ADR-2 § "Plugin Contribution Merging").
|
|
56
|
-
# @param falsey_facts
|
|
57
|
-
# @param post_return_facts
|
|
56
|
+
# @param falsey_facts — dual of `truthy_facts`.
|
|
57
|
+
# @param post_return_facts — facts that hold after the call returns normally on every edge —
|
|
58
58
|
# the carrier for assertion-style contributions.
|
|
59
|
-
# @param mutations
|
|
60
|
-
# @param invalidations
|
|
59
|
+
# @param mutations — receiver and argument mutation effects.
|
|
60
|
+
# @param invalidations — targeted fact invalidations beyond what mutation effects already
|
|
61
61
|
# imply.
|
|
62
|
-
# @param exceptional
|
|
63
|
-
# @param role_conformance
|
|
64
|
-
# @param effects
|
|
62
|
+
# @param exceptional — non-returning, raising, or unreachable effect.
|
|
63
|
+
# @param role_conformance — capability-role conformance facts the contribution provides.
|
|
64
|
+
# @param effects — ADR-103 WD5 — the effect labels this call edge
|
|
65
65
|
# attributes to its callee, as an upper bound. `nil` means "says nothing about effects", which is
|
|
66
66
|
# NOT the same as the empty set (which asserts the call performs none). Merged by union, the
|
|
67
67
|
# conservative direction: two sources that each name part of a call's footprint together name
|
|
68
68
|
# more of it, and neither can shrink the other's claim.
|
|
69
|
-
# @param provenance
|
|
69
|
+
# @param provenance — source-family, plugin-id, node, and cache-descriptor metadata. Defaults
|
|
70
70
|
# to `Provenance.builtin`.
|
|
71
71
|
# rubocop:disable Metrics/ParameterLists
|
|
72
72
|
def initialize(return_type: nil, truthy_facts: nil, falsey_facts: nil,
|
|
@@ -87,7 +87,7 @@ module Rigor
|
|
|
87
87
|
freeze
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
# @return
|
|
90
|
+
# @return true when every content slot is unset (nil or an empty collection). Provenance does
|
|
91
91
|
# not count toward emptiness — an empty bundle still carries source attribution.
|
|
92
92
|
def empty?
|
|
93
93
|
SLOT_NAMES.all? { |slot| slot_empty?(slot, public_send(slot)) }
|
|
@@ -116,8 +116,6 @@ module Rigor
|
|
|
116
116
|
# | exceptional | exceptional | exception | :raise |
|
|
117
117
|
# | role_conformance | normal | role | (per-role target) |
|
|
118
118
|
# | effects | normal | effects | :effects |
|
|
119
|
-
#
|
|
120
|
-
# @return [Array<Element>]
|
|
121
119
|
def to_element_list # rubocop:disable Metrics/AbcSize
|
|
122
120
|
elements = []
|
|
123
121
|
elements << element_for(:return, :normal, :return_type, return_type) unless return_type.nil?
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "../type"
|
|
4
|
+
require_relative "range_constant"
|
|
4
5
|
|
|
5
6
|
module Rigor
|
|
6
7
|
module Inference
|
|
@@ -27,10 +28,7 @@ module Rigor
|
|
|
27
28
|
module Acceptance
|
|
28
29
|
module_function
|
|
29
30
|
|
|
30
|
-
# @param
|
|
31
|
-
# @param other_type [Rigor::Type]
|
|
32
|
-
# @param mode [Symbol] `:gradual` (default) or `:strict`.
|
|
33
|
-
# @return [Rigor::Type::AcceptsResult]
|
|
31
|
+
# @param mode — `:gradual` (default) or `:strict`.
|
|
34
32
|
def accepts(self_type, other_type, mode: :gradual)
|
|
35
33
|
raise ArgumentError, "Acceptance mode #{mode.inspect} is not implemented yet" unless mode == :gradual
|
|
36
34
|
|
|
@@ -63,6 +61,7 @@ module Rigor
|
|
|
63
61
|
Type::Nominal => :accepts_nominal,
|
|
64
62
|
Type::Constant => :accepts_constant,
|
|
65
63
|
Type::IntegerRange => :accepts_integer_range,
|
|
64
|
+
Type::FloatRange => :accepts_float_range,
|
|
66
65
|
Type::Difference => :accepts_difference,
|
|
67
66
|
Type::Refined => :accepts_refined,
|
|
68
67
|
Type::Intersection => :accepts_intersection,
|
|
@@ -201,7 +200,8 @@ module Rigor
|
|
|
201
200
|
# {#accepts_nominal_args});
|
|
202
201
|
# - Constant[v] when v.is_a?(klass(C)). The type_args of self are ignored here because a Constant
|
|
203
202
|
# carries a concrete value, not a generic instantiation, and the analyzer has no way to refute the
|
|
204
|
-
# args from a literal alone.
|
|
203
|
+
# args from a literal alone. A Range value is the one exception — see
|
|
204
|
+
# {#accepts_range_constant_type_arg}.
|
|
205
205
|
# - Tuple[*] when self is the Array (or a supertype) family. The Tuple is projected to
|
|
206
206
|
# `Nominal[Array, [union(elements)]]` so the existing generic-arg machinery handles it.
|
|
207
207
|
# - HashShape{*} when self is the Hash (or a supertype) family, projected to
|
|
@@ -215,6 +215,7 @@ module Rigor
|
|
|
215
215
|
when Type::Singleton then accepts_nominal_from_singleton(self_type, other_type, mode)
|
|
216
216
|
when Type::StructClass, Type::DataClass then accepts_nominal_from_class_factory(self_type, other_type, mode)
|
|
217
217
|
when Type::IntegerRange then accepts_nominal_from_integer_range(self_type, other_type, mode)
|
|
218
|
+
when Type::FloatRange then accepts_nominal_from_float_range(self_type, other_type, mode)
|
|
218
219
|
else accepts_nominal_from_shape(self_type, other_type, mode)
|
|
219
220
|
end
|
|
220
221
|
end
|
|
@@ -311,6 +312,32 @@ module Rigor
|
|
|
311
312
|
end
|
|
312
313
|
end
|
|
313
314
|
|
|
315
|
+
# ADR-109 WD4 — the Float twin of the IntegerRange rule: `Nominal[Float]` and everything Float
|
|
316
|
+
# is-a accept any `FloatRange`; nothing else does.
|
|
317
|
+
FLOAT_NOMINAL_ANCESTORS = %w[Float Numeric Comparable Object BasicObject].freeze
|
|
318
|
+
private_constant :FLOAT_NOMINAL_ANCESTORS
|
|
319
|
+
|
|
320
|
+
def accepts_nominal_from_float_range(self_type, _other_type, mode)
|
|
321
|
+
unless self_type.type_args.empty?
|
|
322
|
+
return Type::AcceptsResult.no(
|
|
323
|
+
mode: mode,
|
|
324
|
+
reasons: "Nominal[#{self_type.class_name}] with type args rejects FloatRange"
|
|
325
|
+
)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
if FLOAT_NOMINAL_ANCESTORS.include?(self_type.class_name)
|
|
329
|
+
Type::AcceptsResult.yes(
|
|
330
|
+
mode: mode,
|
|
331
|
+
reasons: "FloatRange is-a #{self_type.class_name}"
|
|
332
|
+
)
|
|
333
|
+
else
|
|
334
|
+
Type::AcceptsResult.no(
|
|
335
|
+
mode: mode,
|
|
336
|
+
reasons: "Nominal[#{self_type.class_name}] rejects FloatRange"
|
|
337
|
+
)
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
314
341
|
# v0.0.2 — meta-type rule. A `Singleton[T]` is the class object for `T`, so it is an instance of
|
|
315
342
|
# `Class` (when `T` is a class) and always an instance of `Module`. Without this rule a method whose
|
|
316
343
|
# parameter is typed `Class | Module` would reject every `is_a?(SomeClass)` call and similar
|
|
@@ -492,7 +519,7 @@ module Rigor
|
|
|
492
519
|
|
|
493
520
|
def accepts_nominal_from_constant(self_type, constant, mode)
|
|
494
521
|
ruby_class = resolve_class(self_type.class_name)
|
|
495
|
-
return
|
|
522
|
+
return accepts_loaded_class_from_constant(ruby_class, constant, self_type, mode) if ruby_class
|
|
496
523
|
|
|
497
524
|
# The host process may not have required the constant's declared self_type (e.g. `BigDecimal`
|
|
498
525
|
# since Ruby 3.4 is no longer a default gem). Fall back to inspecting the value's own class
|
|
@@ -527,6 +554,13 @@ module Rigor
|
|
|
527
554
|
end
|
|
528
555
|
end
|
|
529
556
|
|
|
557
|
+
def accepts_loaded_class_from_constant(ruby_class, constant, self_type, mode)
|
|
558
|
+
result = constant_is_a_result(ruby_class, constant, self_type, mode)
|
|
559
|
+
return result unless result.yes?
|
|
560
|
+
|
|
561
|
+
accepts_range_constant_type_arg(self_type, constant, mode) || result
|
|
562
|
+
end
|
|
563
|
+
|
|
530
564
|
def constant_is_a_result(ruby_class, constant, self_type, mode)
|
|
531
565
|
if constant.value.is_a?(ruby_class)
|
|
532
566
|
Type::AcceptsResult.yes(mode: mode, reasons: "Constant value is_a?(#{self_type.class_name})")
|
|
@@ -538,10 +572,53 @@ module Rigor
|
|
|
538
572
|
end
|
|
539
573
|
end
|
|
540
574
|
|
|
575
|
+
# Issue #833 — the single exception to "the type_args of self are ignored for a Constant".
|
|
576
|
+
#
|
|
577
|
+
# A `Constant<Range>` is the one literal that does pin a generic instantiation: the engine
|
|
578
|
+
# builds it only when both endpoints are static, so `Range[T]` CAN be refuted from the literal.
|
|
579
|
+
# Without this, `Nominal[Range, [Integer]]` accepted `0.0...1.0` and `OverloadSelector` pass 1
|
|
580
|
+
# pinned whichever `Range[…]` arm came first in declaration order — for `Kernel#rand` that is
|
|
581
|
+
# `(::Range[Integer]) -> Integer?`, ahead of every Float arm.
|
|
582
|
+
#
|
|
583
|
+
# Returns nil — "no opinion, keep the class-level answer" — outside the envelope: a raw `Range`
|
|
584
|
+
# or any other arity of type_args, and a range the shared reader cannot read endpoints from.
|
|
585
|
+
# A missing endpoint contributes nothing, because a beginless or endless literal inhabits
|
|
586
|
+
# `Range[T]` for every T (`Range[Integer?]` is the common core spelling of the slicing param).
|
|
587
|
+
#
|
|
588
|
+
# Known coarse spot, deliberately not special-cased: a mixed-endpoint literal (`1.0..2`) is
|
|
589
|
+
# rejected by `Range[Integer]` and by `Range[Float]` alike, so overload selection falls through
|
|
590
|
+
# to its gradual pass and then to the first-overload fallback exactly as it did before.
|
|
591
|
+
def accepts_range_constant_type_arg(self_type, constant, mode)
|
|
592
|
+
return nil unless self_type.type_args.size == 1
|
|
593
|
+
|
|
594
|
+
endpoints = RangeConstant.literal_endpoints(constant)
|
|
595
|
+
return nil if endpoints.nil?
|
|
596
|
+
|
|
597
|
+
element = self_type.type_args.first
|
|
598
|
+
combine_range_endpoint_results(
|
|
599
|
+
endpoints.map { |endpoint| accepts(element, Type::Combinator.constant_of(endpoint), mode: mode) },
|
|
600
|
+
element,
|
|
601
|
+
mode
|
|
602
|
+
)
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
def combine_range_endpoint_results(per_endpoint, element, mode)
|
|
606
|
+
if per_endpoint.any?(&:no?)
|
|
607
|
+
Type::AcceptsResult.no(mode: mode, reasons: "a Range endpoint is rejected by #{element.describe}")
|
|
608
|
+
elsif per_endpoint.any?(&:maybe?)
|
|
609
|
+
Type::AcceptsResult.maybe(
|
|
610
|
+
mode: mode,
|
|
611
|
+
reasons: "a Range endpoint could not be proven accepted by #{element.describe}"
|
|
612
|
+
)
|
|
613
|
+
else
|
|
614
|
+
Type::AcceptsResult.yes(mode: mode, reasons: "every Range endpoint accepted by #{element.describe}")
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
|
|
541
618
|
# IntegerRange[a..b] accepts:
|
|
542
619
|
# - Constant[n] where n is an Integer covered by [a..b];
|
|
543
620
|
# - IntegerRange[c..d] where [c..d] ⊆ [a..b];
|
|
544
|
-
# - Nominal[Integer] only when self is the universal range (`
|
|
621
|
+
# - Nominal[Integer] only when self is the universal range (`Integer[min..max]`), since otherwise an
|
|
545
622
|
# arbitrary Integer could fall outside the bound.
|
|
546
623
|
# Anything else is rejected.
|
|
547
624
|
def accepts_integer_range(self_type, other_type, mode)
|
|
@@ -616,6 +693,65 @@ module Rigor
|
|
|
616
693
|
end
|
|
617
694
|
end
|
|
618
695
|
|
|
696
|
+
# ADR-109 WD4 — `FloatRange` accepts:
|
|
697
|
+
# - Constant[f] where f is a Float the range covers (never NaN: `cover?` compares);
|
|
698
|
+
# - FloatRange[c..d] whose canonical closed bounds sit inside self's.
|
|
699
|
+
# `Nominal[Float]` is never accepted, not even by the universal range: an arbitrary Float may be
|
|
700
|
+
# NaN, and the universal range is exactly "every Float except NaN".
|
|
701
|
+
def accepts_float_range(self_type, other_type, mode)
|
|
702
|
+
case other_type
|
|
703
|
+
when Type::Constant
|
|
704
|
+
accepts_float_range_from_constant(self_type, other_type, mode)
|
|
705
|
+
when Type::FloatRange
|
|
706
|
+
accepts_float_range_from_float_range(self_type, other_type, mode)
|
|
707
|
+
when Type::Nominal
|
|
708
|
+
Type::AcceptsResult.no(
|
|
709
|
+
mode: mode,
|
|
710
|
+
reasons: "#{self_type.describe} rejects Nominal[#{other_type.class_name}] (could be NaN or fall outside)"
|
|
711
|
+
)
|
|
712
|
+
else
|
|
713
|
+
Type::AcceptsResult.no(
|
|
714
|
+
mode: mode,
|
|
715
|
+
reasons: "FloatRange rejects #{other_type.class}"
|
|
716
|
+
)
|
|
717
|
+
end
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
def accepts_float_range_from_constant(self_type, constant, mode)
|
|
721
|
+
unless constant.value.is_a?(Float)
|
|
722
|
+
return Type::AcceptsResult.no(
|
|
723
|
+
mode: mode,
|
|
724
|
+
reasons: "FloatRange rejects non-Float Constant"
|
|
725
|
+
)
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
if self_type.covers?(constant.value)
|
|
729
|
+
Type::AcceptsResult.yes(
|
|
730
|
+
mode: mode,
|
|
731
|
+
reasons: "Constant[#{constant.value}] is in #{self_type.describe}"
|
|
732
|
+
)
|
|
733
|
+
else
|
|
734
|
+
Type::AcceptsResult.no(
|
|
735
|
+
mode: mode,
|
|
736
|
+
reasons: "Constant[#{constant.value}] outside #{self_type.describe}"
|
|
737
|
+
)
|
|
738
|
+
end
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
def accepts_float_range_from_float_range(self_type, other_range, mode)
|
|
742
|
+
if self_type.min <= other_range.min && other_range.canonical_max <= self_type.canonical_max
|
|
743
|
+
Type::AcceptsResult.yes(
|
|
744
|
+
mode: mode,
|
|
745
|
+
reasons: "#{other_range.describe} ⊆ #{self_type.describe}"
|
|
746
|
+
)
|
|
747
|
+
else
|
|
748
|
+
Type::AcceptsResult.no(
|
|
749
|
+
mode: mode,
|
|
750
|
+
reasons: "#{other_range.describe} not contained in #{self_type.describe}"
|
|
751
|
+
)
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
|
|
619
755
|
# `Difference[base, removed]` accepts another type X when the base accepts X *and* X's value set is
|
|
620
756
|
# provably disjoint from `removed`. The disjointness test is the subtle part — it is NOT the same as
|
|
621
757
|
# `removed.accepts(X)`, because `Nominal[String]` includes `""` even though `Constant[""]` does not
|
|
@@ -936,7 +1072,7 @@ module Rigor
|
|
|
936
1072
|
def resolve_class(name)
|
|
937
1073
|
return nil unless name.is_a?(::String)
|
|
938
1074
|
|
|
939
|
-
parts = name
|
|
1075
|
+
parts = class_name_parts(name)
|
|
940
1076
|
return nil if parts.empty?
|
|
941
1077
|
|
|
942
1078
|
mod = ::Object
|
|
@@ -950,7 +1086,16 @@ module Rigor
|
|
|
950
1086
|
rescue ::StandardError, ::ScriptError, ::SystemExit
|
|
951
1087
|
nil
|
|
952
1088
|
end
|
|
1089
|
+
|
|
1090
|
+
# #775 — the split of a class name is a pure function of the string, and the subtype check asks it
|
|
1091
|
+
# twice per Nominal-vs-Nominal comparison (~370k times on the lib self-check) for the same few
|
|
1092
|
+
# hundred names. Only the split is memoised; the constant walk above still runs every time, so a
|
|
1093
|
+
# class loaded (or a spec constant removed) after the first ask is answered by the live tree.
|
|
1094
|
+
def class_name_parts(name)
|
|
1095
|
+
@class_name_parts[name] ||= name.delete_prefix("::").split("::").freeze
|
|
1096
|
+
end
|
|
953
1097
|
end
|
|
1098
|
+
@class_name_parts = {}
|
|
954
1099
|
end
|
|
955
1100
|
end
|
|
956
1101
|
end
|
|
@@ -34,15 +34,14 @@ module Rigor
|
|
|
34
34
|
#
|
|
35
35
|
# See docs/internal-spec/inference-engine.md for the binding contract.
|
|
36
36
|
class BlockParameterBinder
|
|
37
|
-
# @param expected_param_types
|
|
37
|
+
# @param expected_param_types — positional block parameter types in order. Indices
|
|
38
38
|
# the binder cannot fill from this array (because the array is shorter than the parameter list, or
|
|
39
39
|
# because the slot is a kind we do not pull from the array) default to `Dynamic[Top]`.
|
|
40
40
|
def initialize(expected_param_types: [])
|
|
41
41
|
@expected_param_types = expected_param_types
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
# @
|
|
45
|
-
# @return [Hash{Symbol => Rigor::Type}] ordered map from parameter name to bound type. Anonymous
|
|
44
|
+
# @return ordered map from parameter name to bound type. Anonymous
|
|
46
45
|
# parameters are skipped; MultiTargetNode destructuring slots delegate to {MultiTargetBinder} and
|
|
47
46
|
# contribute every named local in declaration order. Numbered-parameter forms (`_1`, `_2`, ...) bind
|
|
48
47
|
# `:_1`, `:_2`, ... up to the maximum the block body refers to.
|
|
@@ -26,12 +26,12 @@ module Rigor
|
|
|
26
26
|
|
|
27
27
|
module_function
|
|
28
28
|
|
|
29
|
-
# @param names
|
|
30
|
-
# @param seed_bindings
|
|
31
|
-
# @param widen
|
|
32
|
-
# @param evaluate_body
|
|
29
|
+
# @param names — the outer locals the body can rebind.
|
|
30
|
+
# @param seed_bindings — pre-state binding per name.
|
|
31
|
+
# @param widen — value-pinned widener (Constant -> Nominal).
|
|
32
|
+
# @param evaluate_body — `bindings -> exit_bindings` — evaluates the body once from `bindings`
|
|
33
33
|
# (the per-name current assumption) and returns the per-name exit binding it produced.
|
|
34
|
-
# @return
|
|
34
|
+
# @return the continuation binding per name.
|
|
35
35
|
def converge(names:, seed_bindings:, widen:, evaluate_body:)
|
|
36
36
|
return {} if names.empty?
|
|
37
37
|
|
|
@@ -65,8 +65,6 @@ module Rigor
|
|
|
65
65
|
# plain `(receiver, method)` signature was already on the recursion guard stack.
|
|
66
66
|
# - {MEMO_REFUSE_UNROLL} — pre-ADR-84 blanket refusal (constant-arg unroll in flight). Kept in the table
|
|
67
67
|
# as the ADR-84 WD3 gate pin: structurally unreachable, must read ~0.
|
|
68
|
-
# - {MEMO_REFUSE_CONSULT_TAINTED} — a candidate frame computed a result but an ADR-55 fixpoint summary
|
|
69
|
-
# was *consulted* during the compute, so the result is a transient Kleene iterate and was NOT stored.
|
|
70
68
|
# - {MEMO_REFUSE_TRANSIENT} — ADR-84 WD3: a candidate frame's compute bracket saw a
|
|
71
69
|
# transient-machinery event (recursion-guard hit / unroll-fuel exhaustion / ADR-55 WD1 clamp /
|
|
72
70
|
# fixpoint-cap collapse — `ExpressionTyper#note_transient_fallback`) that referenced a stack frame
|
|
@@ -79,15 +77,13 @@ module Rigor
|
|
|
79
77
|
MEMO_BODY_EVALS = :memo_body_evals
|
|
80
78
|
MEMO_REFUSE_ON_STACK = :memo_refuse_on_stack
|
|
81
79
|
MEMO_REFUSE_UNROLL = :memo_refuse_unroll
|
|
82
|
-
MEMO_REFUSE_CONSULT_TAINTED = :memo_refuse_consult_tainted
|
|
83
80
|
MEMO_REFUSE_TRANSIENT = :memo_refuse_transient
|
|
84
81
|
|
|
85
82
|
CATEGORIES = [
|
|
86
83
|
RECURSION_GUARD, ANCESTOR_WALK_LIMIT, HKT_FUEL_EXHAUSTED, RECURSION_UNROLL_FUEL,
|
|
87
84
|
RECURSION_FIXPOINT_CAP, BLOCK_WRITEBACK_CAP,
|
|
88
85
|
MEMO_ENTRIES, MEMO_HITS, MEMO_MISSES, MEMO_BODY_EVALS,
|
|
89
|
-
MEMO_REFUSE_ON_STACK, MEMO_REFUSE_UNROLL,
|
|
90
|
-
MEMO_REFUSE_TRANSIENT
|
|
86
|
+
MEMO_REFUSE_ON_STACK, MEMO_REFUSE_UNROLL, MEMO_REFUSE_TRANSIENT
|
|
91
87
|
].freeze
|
|
92
88
|
|
|
93
89
|
# Distribution (histogram) categories — read-only observations of a value's size at a site, used to
|
|
@@ -30,9 +30,8 @@ module Rigor
|
|
|
30
30
|
|
|
31
31
|
module_function
|
|
32
32
|
|
|
33
|
-
# @param
|
|
34
|
-
# @
|
|
35
|
-
# @return [Array<Symbol>] the captured names the body writes, each once, in first-write order.
|
|
33
|
+
# @param base_scope — the call-site scope the block closes over.
|
|
34
|
+
# @return the captured names the body writes, each once, in first-write order.
|
|
36
35
|
def writes(block_node, base_scope)
|
|
37
36
|
body = block_node.body
|
|
38
37
|
return [] if body.nil?
|
|
@@ -51,11 +51,9 @@ module Rigor
|
|
|
51
51
|
module ClosureEscapeAnalyzer
|
|
52
52
|
module_function
|
|
53
53
|
|
|
54
|
-
# @param
|
|
55
|
-
# @param method_name [Symbol]
|
|
56
|
-
# @param environment [Rigor::Environment, nil] reserved for the future sub-phase that consults
|
|
54
|
+
# @param environment — reserved for the future sub-phase that consults
|
|
57
55
|
# `RBS::Extended` call-timing effects; sub-phase 3a ignores it.
|
|
58
|
-
# @return
|
|
56
|
+
# @return one of `:non_escaping`, `:escaping`, `:unknown`.
|
|
59
57
|
def classify(receiver_type:, method_name:, environment: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
60
58
|
return :unknown if receiver_type.nil?
|
|
61
59
|
|
|
@@ -22,17 +22,17 @@ module Rigor
|
|
|
22
22
|
# a tracer per visited node and discards the inferred type values.
|
|
23
23
|
class CoverageScanner
|
|
24
24
|
class Result < Data.define(:visits, :unrecognized, :events)
|
|
25
|
-
# @return
|
|
25
|
+
# @return sum of all visits across node classes.
|
|
26
26
|
def visited_count
|
|
27
27
|
visits.values.sum
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
# @return
|
|
30
|
+
# @return sum of directly-unrecognized counts across classes.
|
|
31
31
|
def unrecognized_count
|
|
32
32
|
unrecognized.values.sum
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
# @return
|
|
35
|
+
# @return unrecognized_count / visited_count, or 0.0 when empty.
|
|
36
36
|
def unrecognized_ratio
|
|
37
37
|
total = visited_count
|
|
38
38
|
return 0.0 if total.zero?
|
|
@@ -41,13 +41,11 @@ module Rigor
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
# @param scope
|
|
44
|
+
# @param scope — base scope used for every type_of call. Defaults to `Scope.empty`.
|
|
45
45
|
def initialize(scope: nil)
|
|
46
46
|
@scope = scope || Scope.empty
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
# @param root [Prism::Node]
|
|
50
|
-
# @return [Result]
|
|
51
49
|
def scan(root)
|
|
52
50
|
visits = Hash.new(0)
|
|
53
51
|
unrecognized = Hash.new(0)
|