rigortype 0.3.8 → 0.4.0
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 +2 -2
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +132 -14
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- 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 +19 -1
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +525 -13
- 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 +95 -6
- data/docs/manual/03-configuration.md +18 -0
- data/docs/manual/04-diagnostics.md +15 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/10-mcp-server.md +3 -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 +46 -8
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +261 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +138 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +3 -3
- 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/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
- data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
- 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/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +718 -79
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- 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 +15 -1
- data/lib/rigor/analysis/incremental.rb +42 -0
- data/lib/rigor/analysis/incremental_session.rb +117 -26
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -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 +3 -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 +131 -1
- data/lib/rigor/analysis/run_cache_key.rb +21 -12
- 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 +340 -33
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
- data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
- data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +407 -51
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +62 -20
- data/lib/rigor/bleeding_edge.rb +10 -24
- data/lib/rigor/builtins/hkt_builtins.rb +3 -2
- data/lib/rigor/builtins/imported_refinements.rb +159 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +21 -13
- data/lib/rigor/builtins/static_return_refinements.rb +7 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +63 -20
- data/lib/rigor/cache/engine_source.rb +33 -5
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +72 -6
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- 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 +112 -14
- 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 +76 -32
- data/lib/rigor/ci_detector.rb +1 -0
- 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 +4 -4
- data/lib/rigor/cli/docs_command.rb +6 -6
- 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 +4 -4
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +1 -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 +212 -31
- data/lib/rigor/cli/skill_command.rb +2 -2
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +35 -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 +29 -11
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- 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 +89 -9
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +25 -9
- data/lib/rigor/configuration.rb +109 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +12 -5
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +15 -10
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +11 -4
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +9 -9
- data/lib/rigor/effects/envelope_index.rb +20 -8
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +5 -7
- data/lib/rigor/effects/identity.rb +20 -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/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +22 -1
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +47 -37
- data/lib/rigor/effects/propagator.rb +297 -19
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +122 -73
- data/lib/rigor/effects/signature_sources.rb +4 -6
- data/lib/rigor/effects/snapshot.rb +12 -11
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +393 -38
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/effects/visibility.rb +101 -0
- 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 +68 -4
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- 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 +674 -79
- data/lib/rigor/environment.rb +174 -24
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +292 -17
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +75 -30
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +7 -6
- data/lib/rigor/inference/budget_trace.rb +3 -6
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +389 -18
- data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +180 -0
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +2124 -468
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- 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 +16 -7
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +168 -21
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
- 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/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -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/match_data_folding.rb +159 -0
- 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 +165 -111
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
- 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/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
- 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 +5 -6
- 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 +225 -25
- data/lib/rigor/inference/method_parameter_binder.rb +12 -9
- data/lib/rigor/inference/multi_target_binder.rb +341 -55
- data/lib/rigor/inference/mutation_rejoin.rb +171 -0
- data/lib/rigor/inference/mutation_widening.rb +156 -85
- data/lib/rigor/inference/narrowing.rb +835 -162
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +153 -16
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +9 -4
- data/lib/rigor/inference/project_patched_scanner.rb +10 -6
- 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 +93 -4
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +76 -0
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +5228 -627
- data/lib/rigor/inference/statement_evaluator.rb +3452 -595
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +97 -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/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- 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 +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
- 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 +4 -4
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +7 -8
- 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/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +258 -26
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +65 -11
- 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 +33 -13
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- 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 +94 -11
- data/lib/rigor/plugin/registry.rb +76 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- 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 +14 -12
- data/lib/rigor/protection/kill_signature.rb +1 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +7 -11
- 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 +88 -21
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +139 -0
- data/lib/rigor/reflection.rb +93 -110
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +165 -2
- data/lib/rigor/scope.rb +1041 -32
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +673 -53
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- 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/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +18 -16
- 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 +128 -14
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -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/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +189 -41
- data/lib/rigor/sig_gen.rb +3 -0
- 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 +0 -6
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- 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 +144 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +6 -6
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +4 -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/lib/rigor.rb +1 -0
- 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/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
- 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 +14 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -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/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -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 +10 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- 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 +322 -41
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- 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 +290 -19
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -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 +2 -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/types.rb +1 -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-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- 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 +2 -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 +12 -7
- 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 +36 -37
- 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 +0 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -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 +10 -17
- 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/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
- 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 +2 -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 +10 -5
- 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 +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +17 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +9 -14
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +51 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +9 -6
- data/sig/rigor/scope.rbs +148 -12
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +33 -1
- data/sig/rigor.rbs +39 -20
- data/skills/rigor-ask/SKILL.md +16 -11
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +15 -10
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +43 -14
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +226 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +133 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../type"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Inference
|
|
7
|
+
# Issue #963 — the lexical `self` of a `define_method(:name) { ... }` block.
|
|
8
|
+
#
|
|
9
|
+
# A block has no `self` of its own, so every block body enters with `Scope#entering_opaque_block`
|
|
10
|
+
# and the enclosing class body's `self_type` (`Singleton[C]`) rides along unchanged. For
|
|
11
|
+
# `define_method` that carrier is the wrong side of the class: `Module#define_method` turns the
|
|
12
|
+
# block into an INSTANCE method of the receiver, and Ruby runs its body with `self` bound to the
|
|
13
|
+
# receiving instance. A bare `text` inside the block therefore reaches `C`'s member / attr reader,
|
|
14
|
+
# while `Singleton[C]` answers only `C`'s class methods.
|
|
15
|
+
#
|
|
16
|
+
# The consequence #963 records is #618's veto going the wrong way: `ExpressionTyper#self_type_answers?`
|
|
17
|
+
# asked the singleton side, found nothing, and let a same-named top-level `def text` bind ahead of the
|
|
18
|
+
# reader — typing `text.upcase` inside `class Line < Struct.new(:text); define_method(:shout) { text.upcase }`
|
|
19
|
+
# as the top-level def's `nil`. Narrowing the block body's `self_type` to `Nominal[C]` makes the
|
|
20
|
+
# existing veto ask the instance side, which is the side Ruby dispatches on; nothing in the veto
|
|
21
|
+
# itself changes.
|
|
22
|
+
#
|
|
23
|
+
# The match is deliberately narrow — the receiver must be the class body's own `self`, and that `self`
|
|
24
|
+
# must be a known `Singleton[C]` on the instance side of the class. `Foo.define_method(...)` on some other
|
|
25
|
+
# receiver keeps the unmodelled-self answer, and so does a `class << ...` BODY, where `self` is the
|
|
26
|
+
# singleton class and the call defines a CLASS method: an instance reader is not in that MRO, MRI reaches
|
|
27
|
+
# the top-level `def` there, and Rigor must answer the same. The body is the exclusion, not the lexical
|
|
28
|
+
# singleton frame — a `def` reached from that body has the class object as its `self`, so the call defines
|
|
29
|
+
# an instance method and the narrowing applies. `Scope#singleton_class_body?` is what draws that line, and
|
|
30
|
+
# carrying it on the scope is what lets both block-entry paths apply it identically.
|
|
31
|
+
# A `module_function` module is the one shape where both answers are right at once: MRI makes the block
|
|
32
|
+
# BOTH an instance method, where the reader resolves, and a module function on the module object, where it
|
|
33
|
+
# does not. Narrowing silences the module-function half, which is the false-positive-averse direction
|
|
34
|
+
# AGENTS.md § Implementation Guidelines asks for.
|
|
35
|
+
module DefineMethodBlockSelf
|
|
36
|
+
module_function
|
|
37
|
+
|
|
38
|
+
# @return the block body's narrowed `self_type`, or `nil` when the call shape does not match.
|
|
39
|
+
def narrow_self_type_for(scope:, call_node:)
|
|
40
|
+
return nil if scope&.singleton_class_body?
|
|
41
|
+
return nil unless define_method_on_lexical_self?(call_node)
|
|
42
|
+
|
|
43
|
+
self_type = scope&.self_type
|
|
44
|
+
return nil unless self_type.is_a?(Type::Singleton)
|
|
45
|
+
|
|
46
|
+
class_name = self_type.class_name
|
|
47
|
+
return nil if class_name.nil?
|
|
48
|
+
|
|
49
|
+
instance_type_for(class_name, scope.environment)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def define_method_on_lexical_self?(call_node)
|
|
53
|
+
return false unless call_node.is_a?(Prism::CallNode)
|
|
54
|
+
return false unless call_node.name == :define_method
|
|
55
|
+
|
|
56
|
+
call_node.receiver.nil? || call_node.receiver.is_a?(Prism::SelfNode)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def instance_type_for(class_name, environment)
|
|
60
|
+
environment&.nominal_for_name(class_name) || Type::Nominal.new(class_name)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -60,7 +60,7 @@ module Rigor
|
|
|
60
60
|
|
|
61
61
|
module_function
|
|
62
62
|
|
|
63
|
-
# @return
|
|
63
|
+
# @return the tractability category for a cause, or nil when the cause is unknown /
|
|
64
64
|
# absent.
|
|
65
65
|
def tractability(cause)
|
|
66
66
|
TRACTABILITY[cause]
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "prism"
|
|
4
|
+
|
|
5
|
+
require_relative "../type"
|
|
6
|
+
require_relative "mutation_widening"
|
|
7
|
+
|
|
8
|
+
module Rigor
|
|
9
|
+
module Inference
|
|
10
|
+
# Widens the element a mutator call reaches THROUGH a read, when the container is a local's
|
|
11
|
+
# literal-shape carrier. {MutationWidening} widens the bindings a receiver expression NAMES;
|
|
12
|
+
# this module covers the case where it names none because the receiver is an rvalue temp.
|
|
13
|
+
module ElementReadWidening
|
|
14
|
+
# Element reads that name ONE element of a container: the only receiver shapes whose mutation
|
|
15
|
+
# is attributable to a single position inside a local's literal-shape carrier. `first` / `last`
|
|
16
|
+
# with an argument return a sub-ARRAY, not an element, so they are excluded by arity below.
|
|
17
|
+
ELEMENT_READERS = %i[[] first last dig].to_set.freeze
|
|
18
|
+
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
# Widens an element read through an index / `first` / `last` / `dig` chain rooted at a LOCAL,
|
|
22
|
+
# when that read is the RECEIVER of a content mutator (issue #643).
|
|
23
|
+
#
|
|
24
|
+
# `c = [flag ? [1] : [2]]; c[0] << 5` mutates the rvalue temp `c[0]`, so
|
|
25
|
+
# {MutationWidening.widen_after_call} — which widens exactly the bindings the receiver expression NAMES —
|
|
26
|
+
# sees no variable and records nothing. `c` keeps `Tuple[[1] | [2]]`, and the later
|
|
27
|
+
# `c[0].last == 5` folds always-falsey on a value the program does hold. The nested plain
|
|
28
|
+
# literal (`b = [[[]]]; b[0][0] << 1`) reads `b[0][0].first` as `nil` for the same reason.
|
|
29
|
+
#
|
|
30
|
+
# The fix widens the element's pin ONE STEP INSIDE the container and writes the rebuilt
|
|
31
|
+
# container back to the local: `Tuple[[1] | [2]]` becomes `Tuple[Array[Integer]]`. The outer
|
|
32
|
+
# arity survives — mutating an element cannot change how many elements the container has —
|
|
33
|
+
# so `c.size == 1` keeps folding. A non-literal index widens every position instead, since
|
|
34
|
+
# which one was mutated is not decidable.
|
|
35
|
+
#
|
|
36
|
+
# Rooted at a local only: a mutation through a method call's result (`foo[0] << 5`) has no
|
|
37
|
+
# binding to write back to, and inventing one would be unsound.
|
|
38
|
+
def widen_element_read(call_node:, current_scope:, arg_types: MutationWidening::NO_ARG_TYPES)
|
|
39
|
+
return current_scope if MutationWidening.pure_self_returner?(call_node.name)
|
|
40
|
+
|
|
41
|
+
path = element_read_path(call_node.receiver)
|
|
42
|
+
return current_scope if path.nil?
|
|
43
|
+
|
|
44
|
+
read, steps = path
|
|
45
|
+
widened = widen_through_path(current_scope.local(read.name), steps, call_node.name, arg_types)
|
|
46
|
+
return current_scope if widened.nil?
|
|
47
|
+
|
|
48
|
+
current_scope.with_mutated_local(read.name, widened)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# True when `receiver` is an element read whose target element is a literal-shape carrier —
|
|
52
|
+
# the {#joinable_receiver?} counterpart for the element path, gating whether the caller types
|
|
53
|
+
# the mutator's arguments at all.
|
|
54
|
+
def joinable_element_read?(receiver, scope)
|
|
55
|
+
path = element_read_path(receiver)
|
|
56
|
+
return false if path.nil?
|
|
57
|
+
|
|
58
|
+
read, steps = path
|
|
59
|
+
!element_at_path(scope.local(read.name), steps).nil?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# `[<local read>, [step, …]]` for a chain of element reads rooted at a local variable, or
|
|
63
|
+
# `nil` when the expression is anything else. A step is an Integer position (negative counts
|
|
64
|
+
# from the end, as Ruby's own indexing does) or `:all` when the index is not a literal.
|
|
65
|
+
#
|
|
66
|
+
# Every mutation site's receiver is asked, and nearly every one is a plain variable read, so a
|
|
67
|
+
# receiver that is no call answers before the step list is allocated.
|
|
68
|
+
def element_read_path(node)
|
|
69
|
+
return nil unless node.is_a?(Prism::CallNode)
|
|
70
|
+
|
|
71
|
+
steps = []
|
|
72
|
+
cursor = node
|
|
73
|
+
while cursor.is_a?(Prism::CallNode)
|
|
74
|
+
step = element_read_step(cursor)
|
|
75
|
+
return nil if step.nil?
|
|
76
|
+
|
|
77
|
+
steps.unshift(*step)
|
|
78
|
+
cursor = cursor.receiver
|
|
79
|
+
end
|
|
80
|
+
return nil unless cursor.is_a?(Prism::LocalVariableReadNode) && !steps.empty?
|
|
81
|
+
|
|
82
|
+
[cursor, steps]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# The positions one element-read call selects, or `nil` when the call is not an element read.
|
|
86
|
+
# A block makes the call something other than a plain read (`arr.first { … }` is not one), and
|
|
87
|
+
# `[]` with anything but a single argument is a slice.
|
|
88
|
+
def element_read_step(call_node)
|
|
89
|
+
return nil unless ELEMENT_READERS.include?(call_node.name)
|
|
90
|
+
return nil if call_node.receiver.nil? || call_node.block
|
|
91
|
+
|
|
92
|
+
positional_steps(call_node.name, call_node.arguments&.arguments || [])
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def positional_steps(name, args)
|
|
96
|
+
case name
|
|
97
|
+
when :[] then args.size == 1 ? [index_step(args.first)] : nil
|
|
98
|
+
when :first then args.empty? ? [0] : nil
|
|
99
|
+
when :last then args.empty? ? [-1] : nil
|
|
100
|
+
when :dig then args.empty? ? nil : args.map { |arg| index_step(arg) }
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# `:all` stands for "some position, not statically known" — every position is widened, which
|
|
105
|
+
# is the only answer that cannot under-approximate.
|
|
106
|
+
def index_step(node)
|
|
107
|
+
node.is_a?(Prism::IntegerNode) ? node.value : :all
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# The type at `steps` inside `type`, or `nil` when the path does not resolve to a widenable
|
|
111
|
+
# literal-shape carrier.
|
|
112
|
+
def element_at_path(type, steps)
|
|
113
|
+
return MutationWidening.shape_carrier?(type) ? type : nil if steps.empty?
|
|
114
|
+
|
|
115
|
+
case type
|
|
116
|
+
when Type::Tuple
|
|
117
|
+
tuple_positions(type, steps.first).lazy
|
|
118
|
+
.filter_map { |i| element_at_path(type.elements[i], steps.drop(1)) }
|
|
119
|
+
.first
|
|
120
|
+
when Type::Union
|
|
121
|
+
type.members.lazy.filter_map { |member| element_at_path(member, steps) }.first
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Rebuilds `type` with the element at `steps` widened against `method_name`, or `nil` when
|
|
126
|
+
# nothing along the path widened. A block, when given, replaces the straight-line widening of the
|
|
127
|
+
# element itself: it receives the element's type and answers the widened one, or `nil` to decline.
|
|
128
|
+
# {UnknownStoreWidening} passes one so a site on an element takes the same unknown-store widening a
|
|
129
|
+
# site on a variable does.
|
|
130
|
+
def widen_through_path(type, steps, method_name, arg_types, &element_widening)
|
|
131
|
+
if steps.empty?
|
|
132
|
+
return element_widening.call(type) if element_widening
|
|
133
|
+
|
|
134
|
+
return MutationWidening.widen_for_mutator(type, method_name, arg_types: arg_types)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
case type
|
|
138
|
+
when Type::Tuple then widen_tuple_path(type, steps, method_name, arg_types, &element_widening)
|
|
139
|
+
when Type::Union then widen_union_path(type, steps, method_name, arg_types, &element_widening)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def widen_tuple_path(tuple, steps, method_name, arg_types, &)
|
|
144
|
+
elements = tuple.elements.dup
|
|
145
|
+
rest = steps.drop(1)
|
|
146
|
+
widened_any = false
|
|
147
|
+
tuple_positions(tuple, steps.first).each do |position|
|
|
148
|
+
inner = widen_through_path(elements[position], rest, method_name, arg_types, &)
|
|
149
|
+
next if inner.nil?
|
|
150
|
+
|
|
151
|
+
elements[position] = inner
|
|
152
|
+
widened_any = true
|
|
153
|
+
end
|
|
154
|
+
widened_any ? Type::Tuple.new(elements) : nil
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def widen_union_path(union, steps, method_name, arg_types, &)
|
|
158
|
+
widened_any = false
|
|
159
|
+
members = union.members.map do |member|
|
|
160
|
+
widened = widen_through_path(member, steps, method_name, arg_types, &)
|
|
161
|
+
next member if widened.nil?
|
|
162
|
+
|
|
163
|
+
widened_any = true
|
|
164
|
+
widened
|
|
165
|
+
end
|
|
166
|
+
widened_any ? Type::Combinator.union(*members) : nil
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# An out-of-range literal index selects nothing: the mutation cannot be attributed to any
|
|
170
|
+
# position of THIS tuple, so no widening is justified.
|
|
171
|
+
def tuple_positions(tuple, step)
|
|
172
|
+
size = tuple.elements.size
|
|
173
|
+
return (0...size).to_a if step == :all
|
|
174
|
+
|
|
175
|
+
position = step.negative? ? step + size : step
|
|
176
|
+
position.between?(0, size - 1) ? [position] : []
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "prism"
|
|
4
|
+
|
|
5
|
+
require_relative "../reflection"
|
|
6
|
+
require_relative "../source/node_children"
|
|
7
|
+
require_relative "../type"
|
|
8
|
+
require_relative "block_call_timing"
|
|
9
|
+
|
|
10
|
+
module Rigor
|
|
11
|
+
module Inference
|
|
12
|
+
# Issue #1360 — `$!`, the exception being rescued, and `$@`, its backtrace. Ruby does not keep them in the method
|
|
13
|
+
# frame's special-variable slot, as it keeps `$~` and `$_`: a read of `$!` walks the running execution context's
|
|
14
|
+
# frames to the nearest rescue frame. So:
|
|
15
|
+
#
|
|
16
|
+
# - inside a `rescue` clause, and inside a rescue modifier's fallback, `$!` is the exception that clause rescued,
|
|
17
|
+
# in every block the clause runs and every method it calls;
|
|
18
|
+
# - once the `begin` or the modifier exits, however it exits, `$!` is what it was before it started: `nil` at the
|
|
19
|
+
# top of a method called from nowhere special, the outer exception after a nested `begin` in a rescue clause;
|
|
20
|
+
# - an `else` clause and the body read that earlier value too, and an `ensure` clause reads it when the body or a
|
|
21
|
+
# rescue clause finished, but the exception in flight when one raised.
|
|
22
|
+
#
|
|
23
|
+
# A method body cannot know what its caller is rescuing, so it starts unbound; a thread's or fiber's root block
|
|
24
|
+
# runs in an execution context of its own, where `$!` is `nil` ({FreshFrameBlocks.entry}); and a closure's body
|
|
25
|
+
# runs whenever it is called, usually after the clause it is written in exited ({FreshFrameBlocks.closure_entry}).
|
|
26
|
+
module ErrorInfo
|
|
27
|
+
ERROR_INFO = :$!
|
|
28
|
+
BACKTRACE = :$@
|
|
29
|
+
NAMES = [ERROR_INFO, BACKTRACE].freeze
|
|
30
|
+
# The globals a rescue modifier's fallback reads differently from the modifier's entry ({.modifier_entry}).
|
|
31
|
+
MODIFIER_NAMES = [ERROR_INFO, BACKTRACE, :$?].freeze
|
|
32
|
+
EXCEPTION_ORDERINGS = Set[:equal, :subclass].freeze
|
|
33
|
+
DEFINERS = Set[:define_method, :define_singleton_method].freeze
|
|
34
|
+
# The class guards a clause may put on `$!` ({.guarded?}).
|
|
35
|
+
GUARDS = Set[:is_a?, :kind_of?, :instance_of?, :respond_to?].freeze
|
|
36
|
+
private_constant :ERROR_INFO, :BACKTRACE, :NAMES, :MODIFIER_NAMES, :EXCEPTION_ORDERINGS, :GUARDS, :DEFINERS
|
|
37
|
+
|
|
38
|
+
module_function
|
|
39
|
+
|
|
40
|
+
# The scope a `rescue` clause, or a rescue modifier's fallback, runs from: `$!` bound to the exception it rescued
|
|
41
|
+
# and `$@` to that exception's backtrace, with `$?` unbound. `exception_type` is what `rescue … => e` binds `e` to
|
|
42
|
+
# (`StatementEvaluator#rescue_exception_type`): the union of the named classes' instances, `StandardError` for a
|
|
43
|
+
# bare `rescue`. A member that is not a class RBS or the program places below `Exception` reads `Dynamic[top]`
|
|
44
|
+
# instead: a rescue list may name a module with its own `===` (`rescue NetworkErrors`), which matches exceptions
|
|
45
|
+
# that are not instances of it, and a class the analyzer cannot place may be such an object too. So does a class
|
|
46
|
+
# that it or a project ancestor gives its own singleton `===` (`class Matchy < StandardError; def self.===(o) =
|
|
47
|
+
# true`).
|
|
48
|
+
#
|
|
49
|
+
# `body` is the clause's statements or the fallback, and `reference` the name of the local a `rescue … => e`
|
|
50
|
+
# clause binds. When the body guards `$!`, or that local, which is the same object, by its class ({.guarded?}),
|
|
51
|
+
# the clause reads `$!` and `$@` unbound, as it did before issue #1360: `$!.key if e.is_a?(KeyError)` would report
|
|
52
|
+
# the bound `StandardError` against the guard (ADR-117, point 3), since narrowing `e` does not narrow `$!`. #1429
|
|
53
|
+
# made a class guard on `$!` itself narrow it; #1447 narrows this decline to the guards that still do not.
|
|
54
|
+
#
|
|
55
|
+
# `$@` calls the exception's `backtrace`, which is an `Array[String]` for a raised exception. It is left unbound
|
|
56
|
+
# in a program that defines a method named `backtrace` anywhere, which may return anything, and in a clause
|
|
57
|
+
# whose body calls `set_backtrace`, which may set it to nil.
|
|
58
|
+
#
|
|
59
|
+
# `$?` is unbound because the exception may have been raised while a subprocess waited: a backtick, `%x` or
|
|
60
|
+
# `system` sets `$?` to nil before it runs the child, so a `Timeout::Error`, an `Interrupt` or a `Thread#raise`
|
|
61
|
+
# there leaves it nil.
|
|
62
|
+
def rescue_entry(scope, exception_type, body = nil, reference = nil)
|
|
63
|
+
entered = scope.forget_error_info.forget_last_status
|
|
64
|
+
# Narrowed to the guards #1429 does not narrow in #1447.
|
|
65
|
+
return entered if guarded?(body, reference)
|
|
66
|
+
|
|
67
|
+
entered = entered.with_global(ERROR_INFO, rescued_type(exception_type, scope))
|
|
68
|
+
return entered if calls_set_backtrace?(body) || BlockCallTiming.project_defines_anywhere?(:backtrace, scope)
|
|
69
|
+
|
|
70
|
+
entered.with_global(BACKTRACE, backtrace_type)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# The scope a rescue modifier's fallback (`expr rescue fallback`) runs from, which rescues a `StandardError`.
|
|
74
|
+
def modifier_entry(scope, fallback = nil)
|
|
75
|
+
rescue_entry(scope, Type::Combinator.nominal_of("StandardError"), fallback)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# The class guards on `$!` that {.rescue_entry} declines on, anywhere in `node`: `$!.is_a?`, `kind_of?`,
|
|
79
|
+
# `instance_of?` or `respond_to?`, a `===` whose argument is `$!` (`KeyError === $!`), and `case $!`, and the
|
|
80
|
+
# same on a read of the local named `reference`.
|
|
81
|
+
def guarded?(node, reference = nil)
|
|
82
|
+
return false unless node.is_a?(Prism::Node)
|
|
83
|
+
return true if guard?(node, reference)
|
|
84
|
+
|
|
85
|
+
found = false
|
|
86
|
+
node.rigor_each_child { |child| found ||= guarded?(child, reference) }
|
|
87
|
+
found
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def guard?(node, reference)
|
|
91
|
+
case node
|
|
92
|
+
when Prism::CallNode
|
|
93
|
+
(GUARDS.include?(node.name) && error_info_read?(node.receiver, reference)) ||
|
|
94
|
+
(node.name == :=== && error_info_read?(node.arguments&.arguments&.first, reference))
|
|
95
|
+
when Prism::CaseNode, Prism::CaseMatchNode then error_info_read?(node.predicate, reference)
|
|
96
|
+
else false
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def error_info_read?(node, reference)
|
|
101
|
+
case node
|
|
102
|
+
when Prism::GlobalVariableReadNode then node.name == ERROR_INFO
|
|
103
|
+
when Prism::LocalVariableReadNode then !reference.nil? && node.name == reference
|
|
104
|
+
else false
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# True when `node` calls `set_backtrace` anywhere, on any receiver: `$!.set_backtrace(nil)` makes `$@` nil.
|
|
109
|
+
def calls_set_backtrace?(node)
|
|
110
|
+
return false unless node.is_a?(Prism::Node)
|
|
111
|
+
return true if node.is_a?(Prism::CallNode) && node.name == :set_backtrace
|
|
112
|
+
|
|
113
|
+
found = false
|
|
114
|
+
node.rigor_each_child { |child| found ||= calls_set_backtrace?(child) }
|
|
115
|
+
found
|
|
116
|
+
end
|
|
117
|
+
private_class_method :guard?, :error_info_read?, :calls_set_backtrace?
|
|
118
|
+
|
|
119
|
+
# True when `node` reads `$!`, `$@` or `$?` anywhere in it: the gate on typing a rescue modifier's fallback
|
|
120
|
+
# under {.modifier_entry}, which most fallbacks (`rescue nil`) never need.
|
|
121
|
+
def read_in?(node)
|
|
122
|
+
return false unless node.is_a?(Prism::Node)
|
|
123
|
+
return MODIFIER_NAMES.include?(node.name) if node.is_a?(Prism::GlobalVariableReadNode)
|
|
124
|
+
|
|
125
|
+
found = false
|
|
126
|
+
node.rigor_each_child { |child| found ||= read_in?(child) }
|
|
127
|
+
found
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# `scope` with `$!` and `$@` as `entry` binds them, and unbound where `entry` leaves them unbound: the scope past
|
|
131
|
+
# a `begin` or a rescue modifier that started from `entry`, whichever way it left.
|
|
132
|
+
def restore(scope, entry)
|
|
133
|
+
return scope if NAMES.all? { |name| scope.global(name).equal?(entry.global(name)) }
|
|
134
|
+
|
|
135
|
+
NAMES.reduce(scope.forget_error_info) do |acc, name|
|
|
136
|
+
bound = entry.global(name)
|
|
137
|
+
bound ? acc.with_global(name, bound) : acc
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def rescued_type(exception_type, scope)
|
|
142
|
+
members = exception_type.is_a?(Type::Union) ? exception_type.members : [exception_type]
|
|
143
|
+
return exception_type if members.all? { |member| exception_instance?(member, scope) }
|
|
144
|
+
|
|
145
|
+
Type::Combinator.union(
|
|
146
|
+
*members.map { |member| exception_instance?(member, scope) ? member : Type::Combinator.untyped }
|
|
147
|
+
)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# True when `type` is an instance of a class below `Exception`: one RBS places there, or a project class whose
|
|
151
|
+
# superclass chain reaches one (`class MyError < StandardError`), which the RBS environment does not know.
|
|
152
|
+
def exception_instance?(type, scope)
|
|
153
|
+
return false unless type.is_a?(Type::Nominal)
|
|
154
|
+
|
|
155
|
+
class_name = type.class_name
|
|
156
|
+
return false if own_case_equality?(class_name, scope)
|
|
157
|
+
return true if exception_class?(class_name, scope)
|
|
158
|
+
return false unless scope.known_user_class?(class_name)
|
|
159
|
+
|
|
160
|
+
scope.external_ancestor_name_candidates(class_name, mixins: false).any? do |candidates|
|
|
161
|
+
known = candidates.find { |candidate| Reflection.rbs_class_known?(candidate, scope: scope) }
|
|
162
|
+
!known.nil? && exception_class?(known, scope)
|
|
163
|
+
end
|
|
164
|
+
rescue StandardError
|
|
165
|
+
false
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# True when the program gives `class_name`, or a project ancestor of it, a singleton `===`, which `rescue` calls
|
|
169
|
+
# to match and which may accept an exception that is not an instance of it: a `def self.===` or `class << self`
|
|
170
|
+
# `def ===`, or, anywhere in the file being read, a `define_method` or `define_singleton_method` naming `===`
|
|
171
|
+
# ({.defines_case_equality?}), which the discovery tables do not place on a class, so it counts for every class.
|
|
172
|
+
def own_case_equality?(class_name, scope)
|
|
173
|
+
scope.discovery.defines_case_equality ||
|
|
174
|
+
!scope.singleton_def_through_ancestors(class_name, :===).first.nil?
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# True when `node` is a `define_method` or `define_singleton_method` call whose literal name is `===`.
|
|
178
|
+
# `Inference::ScopeIndexer` records whether a file holds one ({Scope::DiscoveryIndex#defines_case_equality}).
|
|
179
|
+
def defines_case_equality?(node)
|
|
180
|
+
return false unless node.is_a?(Prism::CallNode) && DEFINERS.include?(node.name)
|
|
181
|
+
|
|
182
|
+
name = node.arguments&.arguments&.first
|
|
183
|
+
(name.is_a?(Prism::SymbolNode) || name.is_a?(Prism::StringNode)) && name.unescaped == "==="
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def exception_class?(class_name, scope)
|
|
187
|
+
EXCEPTION_ORDERINGS.include?(scope.environment.class_ordering(class_name, "Exception"))
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def backtrace_type
|
|
191
|
+
Type::Combinator.nominal_of("Array", type_args: [Type::Combinator.nominal_of("String")])
|
|
192
|
+
end
|
|
193
|
+
private_class_method :rescued_type, :exception_instance?, :own_case_equality?, :exception_class?, :backtrace_type
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|