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,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "prism"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Inference
|
|
7
|
+
# The calls that keep their literal block to run later instead of running it before they return: the Kernel
|
|
8
|
+
# functions that wrap it in a Proc (`lambda`, `proc`), the definers that install it as a method body
|
|
9
|
+
# (`define_method`, `define_singleton_method`, on any receiver), and the constructors that keep it as a proc,
|
|
10
|
+
# a thread or fiber body, an enumerator's generator or a hash's default proc.
|
|
11
|
+
#
|
|
12
|
+
# A `break` in such a block never becomes the call's value — it returns from the lambda or the defined method
|
|
13
|
+
# when that is called, or raises `LocalJumpError` — so the #853 break-arm union
|
|
14
|
+
# (`ExpressionTyper#call_break_arm_types`) MUST NOT read it. Unioning the arm typed
|
|
15
|
+
# `lambda do |t| break if flag; t end` as `Proc | nil`, and the lambda's next `.call` drew
|
|
16
|
+
# `call.possible-nil-receiver`.
|
|
17
|
+
#
|
|
18
|
+
# A project redefinition of one of these names is not excluded: dropping the arm there loses a `break`
|
|
19
|
+
# value, never invents one.
|
|
20
|
+
module StoredBlockCall
|
|
21
|
+
KERNEL_WRAPPERS = %i[lambda proc].freeze
|
|
22
|
+
DEFINERS = %i[define_method define_singleton_method].freeze
|
|
23
|
+
CONSTRUCTORS = {
|
|
24
|
+
Proc: %i[new], Thread: %i[new start fork], Fiber: %i[new], Enumerator: %i[new], Hash: %i[new]
|
|
25
|
+
}.transform_values(&:freeze).freeze
|
|
26
|
+
NO_NAMES = [].freeze
|
|
27
|
+
private_constant :KERNEL_WRAPPERS, :DEFINERS, :CONSTRUCTORS, :NO_NAMES
|
|
28
|
+
|
|
29
|
+
module_function
|
|
30
|
+
|
|
31
|
+
def stores_block?(call_node)
|
|
32
|
+
name = call_node.name
|
|
33
|
+
return kernel_spelled?(call_node.receiver) if KERNEL_WRAPPERS.include?(name)
|
|
34
|
+
return true if DEFINERS.include?(name)
|
|
35
|
+
|
|
36
|
+
constant = root_constant_name(call_node.receiver)
|
|
37
|
+
!constant.nil? && CONSTRUCTORS.fetch(constant, NO_NAMES).include?(name)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Implicit self, `self.`, or `Kernel.` / `::Kernel.` — the spellings that reach Kernel's function.
|
|
41
|
+
def kernel_spelled?(receiver)
|
|
42
|
+
receiver.nil? || receiver.is_a?(Prism::SelfNode) || root_constant_name(receiver) == :Kernel
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# `Foo` or `::Foo`'s name, else nil.
|
|
46
|
+
def root_constant_name(receiver)
|
|
47
|
+
case receiver
|
|
48
|
+
when Prism::ConstantReadNode then receiver.name
|
|
49
|
+
when Prism::ConstantPathNode then receiver.name if receiver.parent.nil?
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../type"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Inference
|
|
7
|
+
# The String half of {MutationWidening}'s straight-line seam (issue #617 residue (4)).
|
|
8
|
+
#
|
|
9
|
+
# `s = +"ab"; s << "c"; s == "ab"` folded `flow.always-truthy-condition` on correct code: the seam
|
|
10
|
+
# responded to `Tuple` / `HashShape` / empty-witness carriers only, while a `Constant[String]` is just as
|
|
11
|
+
# falsified by an in-place mutator as a `Tuple` is by `<<`. The ADR-56 block-capture path already widened
|
|
12
|
+
# the same binding, so the two seams disagreed about one carrier.
|
|
13
|
+
#
|
|
14
|
+
# It lives beside `MutationWidening` rather than inside it because the tables here answer a different
|
|
15
|
+
# question from the Array / Hash ones: those partition a carrier's SHAPE evidence, this one partitions a
|
|
16
|
+
# VALUE pin and an emptiness proof.
|
|
17
|
+
module StringMutation
|
|
18
|
+
# Receiver-mutating String methods only. The non-bang siblings (`upcase` vs `upcase!`, `sub` vs `sub!`)
|
|
19
|
+
# return a new String and leave the receiver's value intact, so they stay precise.
|
|
20
|
+
#
|
|
21
|
+
# This is the one String table: `MutationWidening::SHAPE_MUTATORS` unions it with the Array and Hash ones, and
|
|
22
|
+
# the effect classifier and the effect catalogue's `mutators: string` cite it rather than keep a list of their
|
|
23
|
+
# own (ADR-103 WD3). A spec holds it to every bang method `String` defines plus the non-bang mutators reflection
|
|
24
|
+
# cannot find by name.
|
|
25
|
+
MUTATORS = %i[
|
|
26
|
+
<< concat insert prepend replace clear []= slice!
|
|
27
|
+
setbyte bytesplice append_as_bytes force_encoding
|
|
28
|
+
sub! gsub! tr! tr_s! delete! squeeze! succ! next!
|
|
29
|
+
upcase! downcase! capitalize! swapcase! reverse!
|
|
30
|
+
strip! lstrip! rstrip! chomp! chop!
|
|
31
|
+
delete_prefix! delete_suffix! encode! scrub! unicode_normalize!
|
|
32
|
+
].to_set.freeze
|
|
33
|
+
|
|
34
|
+
# The {MUTATORS} that CANNOT leave a non-empty receiver empty, and so keep a `non-empty-string` refinement:
|
|
35
|
+
# appenders (`<<`, `concat`, `insert`, `prepend`, `append_as_bytes`), and rewrites that keep at least one
|
|
36
|
+
# character (`setbyte`, `force_encoding`, the case mappings, `reverse!`, `succ!` / `next!`, `squeeze!`,
|
|
37
|
+
# `unicode_normalize!`). A whitelist, as `RefinementMutation::EMPTY_PRESERVING` is for Array and Hash: a mutator
|
|
38
|
+
# missing here retracts the witness, which costs precision, where a mutator missing from a list of emptiers kept
|
|
39
|
+
# the witness of a string it had just emptied — `tr!` and `tr_s!` did, since `"a".tr!("a", "")` is `""`.
|
|
40
|
+
EMPTY_PRESERVING = %i[
|
|
41
|
+
<< concat insert prepend append_as_bytes
|
|
42
|
+
setbyte force_encoding
|
|
43
|
+
upcase! downcase! capitalize! swapcase! reverse! succ! next! squeeze! unicode_normalize!
|
|
44
|
+
].to_set.freeze
|
|
45
|
+
|
|
46
|
+
# `tr!` / `tr_s!` map every character they match to one character of the replacement (padded with its last), so
|
|
47
|
+
# they empty the buffer only through an EMPTY replacement: `"a".tr!("a", "")` is `""`, `"a".tr!("a", "_")` is
|
|
48
|
+
# `"_"`. They keep the witness when their second argument is provably a non-empty String.
|
|
49
|
+
TRANSLATORS = %i[tr! tr_s!].to_set.freeze
|
|
50
|
+
|
|
51
|
+
NO_ARG_TYPES = [].freeze
|
|
52
|
+
|
|
53
|
+
module_function
|
|
54
|
+
|
|
55
|
+
# `Constant["ab"]` under a String mutator → the bare `String` nominal. The pinned value is what the
|
|
56
|
+
# mutation falsifies, and nothing else about the carrier survives it, so there is no `values: :keep`
|
|
57
|
+
# half to preserve the way a `Tuple`'s surviving slots have one: an appended, substituted or
|
|
58
|
+
# case-folded string is a different string.
|
|
59
|
+
#
|
|
60
|
+
# Only a String-valued `Constant` widens. Every other literal (`Integer`, `Symbol`, `Range`) can only
|
|
61
|
+
# reach this arm through a name in the Array or Hash table and not in {MUTATORS}, and answering for it
|
|
62
|
+
# would erase a value no in-place mutator on that class can change.
|
|
63
|
+
#
|
|
64
|
+
# `nil` — no widening — for every other input, which is the contract `MutationWidening#widen_for_mutator`
|
|
65
|
+
# signals a decline with.
|
|
66
|
+
def widen_constant(constant, method_name)
|
|
67
|
+
return nil unless constant?(constant)
|
|
68
|
+
return nil unless MUTATORS.include?(method_name)
|
|
69
|
+
|
|
70
|
+
Type::Combinator.nominal_of("String")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def constant?(type)
|
|
74
|
+
type.is_a?(Type::Constant) && type.value.is_a?(String)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Whether `method_name`, called with `arg_types` (the call's positional argument types, possibly none), can leave
|
|
78
|
+
# a non-empty receiver empty, and so retract a `non-empty-string` refinement. Every mutator outside
|
|
79
|
+
# {EMPTY_PRESERVING} can, except a {TRANSLATORS} call whose replacement is provably non-empty.
|
|
80
|
+
def may_empty?(method_name, arg_types = NO_ARG_TYPES)
|
|
81
|
+
return false if EMPTY_PRESERVING.include?(method_name)
|
|
82
|
+
return true unless TRANSLATORS.include?(method_name)
|
|
83
|
+
|
|
84
|
+
!non_empty_string?(arg_types[1])
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def non_empty_string?(type)
|
|
88
|
+
case type
|
|
89
|
+
when Type::Constant then constant?(type) && !type.value.empty?
|
|
90
|
+
when Type::Difference then type.removes_empty_witness? && type.base.class_name == "String"
|
|
91
|
+
when Type::Union then type.members.all? { |member| non_empty_string?(member) }
|
|
92
|
+
else false
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -55,10 +55,10 @@ module Rigor
|
|
|
55
55
|
node.is_a?(Prism::ModuleNode) || node.is_a?(Prism::SingletonClassNode)
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
# @param root
|
|
59
|
-
# @param layout_lookup
|
|
58
|
+
# @param root — the local-variable scope to scan.
|
|
59
|
+
# @param layout_lookup — a `String -> Array[Symbol] | nil` resolver mapping a constant receiver name to its
|
|
60
60
|
# struct member list.
|
|
61
|
-
# @return
|
|
61
|
+
# @return the fold-safe local names.
|
|
62
62
|
def fold_safe_locals(root, layout_lookup)
|
|
63
63
|
return EMPTY if root.nil?
|
|
64
64
|
|
|
@@ -208,10 +208,9 @@ module Rigor
|
|
|
208
208
|
# Nested `def` / `class` / `module` bodies are skipped: their statements do not run during THIS body's
|
|
209
209
|
# evaluation. Blocks are descended into — they share `self`.
|
|
210
210
|
#
|
|
211
|
-
# @param
|
|
212
|
-
# @
|
|
213
|
-
# @
|
|
214
|
-
# @yieldreturn [Boolean] whether that sibling method is itself self-fold-safe.
|
|
211
|
+
# @param member_names — the receiver carrier's member names.
|
|
212
|
+
# @yieldparam name — an unrecognised self-call selector.
|
|
213
|
+
# @yieldreturn whether that sibling method is itself self-fold-safe.
|
|
215
214
|
def self_fold_safe_body?(body, member_names, &sibling_pure)
|
|
216
215
|
return false if body.nil?
|
|
217
216
|
|
|
@@ -22,8 +22,7 @@ module Rigor
|
|
|
22
22
|
class SyntheticMethodIndex
|
|
23
23
|
attr_reader :entries, :class_names
|
|
24
24
|
|
|
25
|
-
# @param
|
|
26
|
-
# @param class_names [Array<String>, Set<String>] names of classes the substrate synthesises wholesale (ADR-36
|
|
25
|
+
# @param class_names — names of classes the substrate synthesises wholesale (ADR-36
|
|
27
26
|
# nested-class emission — the variant subclasses that have no RBS/source declaration of their own). Recorded so
|
|
28
27
|
# `Environment#class_known?` can resolve them as classes (their constant reference + `.new` dispatch) even
|
|
29
28
|
# though nothing else in the type universe declares them. Tier B/C method emissions leave this empty (their
|
|
@@ -40,26 +40,24 @@ module Rigor
|
|
|
40
40
|
module SyntheticMethodScanner # rubocop:disable Metrics/ModuleLength
|
|
41
41
|
module_function
|
|
42
42
|
|
|
43
|
-
# @param
|
|
44
|
-
# @param paths [Array<String>] absolute paths to the project
|
|
43
|
+
# @param paths — absolute paths to the project
|
|
45
44
|
# source files to scan.
|
|
46
|
-
# @param environment
|
|
45
|
+
# @param environment — used for
|
|
47
46
|
# inheritance resolution against RBS-known classes
|
|
48
47
|
# (ActiveRecord::Base, Dry::Struct, etc.) that aren't
|
|
49
48
|
# declared in project source.
|
|
50
|
-
# @param fact_store
|
|
49
|
+
# @param fact_store —
|
|
51
50
|
# the per-run cross-plugin fact store. ADR-18 lookups
|
|
52
51
|
# (`Plugin::Macro::HeredocTemplate::Emit#returns_from_arg`)
|
|
53
52
|
# consult this at scan time to resolve per-call-site
|
|
54
53
|
# return types from published facts; without it, those
|
|
55
54
|
# emit rows fall back to their static `returns:` (or
|
|
56
55
|
# `"untyped"` → `Dynamic[Top]`).
|
|
57
|
-
# @param buffer
|
|
56
|
+
# @param buffer —
|
|
58
57
|
# editor-mode buffer binding. When set, reads for the
|
|
59
58
|
# logical path resolve to the buffer's physical path so
|
|
60
59
|
# the pre-pass sees the in-flight bytes instead of the
|
|
61
60
|
# on-disk copy.
|
|
62
|
-
# @return [Rigor::Inference::SyntheticMethodIndex]
|
|
63
61
|
def scan(plugin_registry:, paths:, environment: nil, fact_store: nil, buffer: nil)
|
|
64
62
|
templates = collect_templates(plugin_registry)
|
|
65
63
|
registries = collect_trait_registries(plugin_registry)
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "prism"
|
|
4
|
+
|
|
5
|
+
require_relative "../type"
|
|
6
|
+
require_relative "element_read_widening"
|
|
7
|
+
require_relative "mutation_widening"
|
|
8
|
+
|
|
9
|
+
module Rigor
|
|
10
|
+
module Inference
|
|
11
|
+
# What a binding can hold after each of a set of in-place mutation sites — the nodes
|
|
12
|
+
# {CapturedLocals.content_mutations} collects — has run any number of times, storing values nothing typed.
|
|
13
|
+
#
|
|
14
|
+
# Each site takes its own straight-line widening ({MutationWidening.widen_for_mutator}), fed one
|
|
15
|
+
# `Dynamic[top]` per argument, and every site that can STORE a value then gives each type argument of the
|
|
16
|
+
# widened `Array` / `Hash` a `Dynamic[top]` arm: `{ a: 0 }` under `h[k] += 1` reads
|
|
17
|
+
# `Hash[Dynamic[top] | Symbol, Dynamic[top] | Integer]`. The second step is not redundant. The widening
|
|
18
|
+
# joins argument evidence only for the plain adders (`<<`, `push`, `[]=`, `store`, …); a site whose stored
|
|
19
|
+
# values its arguments do not describe — `map!`, a block-form `fill`, `transform_values!`, `merge!`,
|
|
20
|
+
# `flatten!` — comes back with the seed's element types alone, which is a wrong precise answer once the
|
|
21
|
+
# block has run: `a = [1]` under `a.map!(&:to_s)` would read `Array[Integer]`. Only a site that removes or
|
|
22
|
+
# reorders ({VALUE_PRESERVING}) keeps its content as the widening left it, since it cannot put a value
|
|
23
|
+
# there that was not there before — unless it is the site that CLOSES a literal carrier. A `Tuple` or
|
|
24
|
+
# `HashShape` knows which slots and keys exist, and the nominal it widens to cannot say that any may be
|
|
25
|
+
# missing, so it takes the gradual arm too: `{ a: 0 }` under a lone `h.delete(:a)` read `Hash[Symbol, 0]`,
|
|
26
|
+
# whose `h[:b]` answered `0` where Ruby answers `nil`, and `s = [0]` under `p = s.pop; s.push(x)` closed to
|
|
27
|
+
# `Array[0]`, a precise nominal the `push` after it then declined, so `p` stayed `0?`. With the arm the
|
|
28
|
+
# answer for a `Tuple` / `HashShape` seed (alone or in a `Union`) no longer depends on the order the sites are
|
|
29
|
+
# written in; a refinement seed (`non-empty-array[0]`) still can, since its remover does not close a literal.
|
|
30
|
+
#
|
|
31
|
+
# A site whose widening declines leaves the binding as it is, exactly as the straight-line seam does: a
|
|
32
|
+
# precise nominal (a declared or inferred `Array[String]` is a claim this seam may not grow), a receiver
|
|
33
|
+
# that is no carrier, or a name the mutator tables do not list for that carrier (`store` on a `Tuple`, a method
|
|
34
|
+
# its class does not define). The caller MUST therefore not read an unchanged binding as describing later
|
|
35
|
+
# iterations. An empty-witness refinement under a storing mutator that keeps the witness is not such a decline:
|
|
36
|
+
# the straight-line widening grows it (issue #936), and gives a site whose arguments describe nothing it stores
|
|
37
|
+
# (`non-empty-array[String]` under `map!`) the gradual arm itself ({RewriteMutation}),
|
|
38
|
+
# so the site widens like any other storing site.
|
|
39
|
+
#
|
|
40
|
+
# The per-element block fold is the consumer: it types every position from one entry scope, so the binding
|
|
41
|
+
# it lays under each position has to hold whatever earlier iterations stored. Unknown evidence is the point,
|
|
42
|
+
# not a shortcut — a stored value typed in that same entry scope (`h[k] = h[k] + 1`) is itself a
|
|
43
|
+
# first-iteration answer.
|
|
44
|
+
#
|
|
45
|
+
# Two more kinds of site change a binding's contents without naming it as the receiver, and each is widened
|
|
46
|
+
# the way straight-line code widens it:
|
|
47
|
+
#
|
|
48
|
+
# - A mutator on an ELEMENT of the binding (`a[0] << e`, `a.first.push(e)`): the site's receiver is an element
|
|
49
|
+
# read rooted at the variable ({ElementReadWidening.element_read_path}), and the same widening runs on the
|
|
50
|
+
# element the path selects, rebuilding the carrier around it. The other slots keep their types, and a path
|
|
51
|
+
# {ElementReadWidening} cannot follow (a `HashShape` slot) declines, as it does on straight-line code.
|
|
52
|
+
# - A self-call whose callee content-mutates the parameter the binding is passed to (`add_to(a, e)`, a
|
|
53
|
+
# {CalleeStore}): nothing at the call says what the callee stores or removes, so each collection the binding
|
|
54
|
+
# can hold is floored to its bare carrier ({.content_floor}), as ADR-57's callee floor does after the call.
|
|
55
|
+
module UnknownStoreWidening
|
|
56
|
+
# Mutators that only remove or reorder what the receiver already holds.
|
|
57
|
+
VALUE_PRESERVING = %i[
|
|
58
|
+
pop shift delete delete_at delete_if reject! select! filter! keep_if clear compact! uniq! slice!
|
|
59
|
+
sort! sort_by! reverse! rotate! shuffle!
|
|
60
|
+
].to_set.freeze
|
|
61
|
+
|
|
62
|
+
# A site that mutates a binding through a callee: `call` passes the variable, read by one of `arguments`, to
|
|
63
|
+
# a parameter the callee content-mutates.
|
|
64
|
+
CalleeStore = Data.define(:call, :arguments)
|
|
65
|
+
|
|
66
|
+
COLLECTION_CLASSES = %w[Array Hash].freeze
|
|
67
|
+
FLOORED_CLASSES = %w[Array Hash String].freeze
|
|
68
|
+
|
|
69
|
+
NO_ARG_NODES = [].freeze
|
|
70
|
+
private_constant :COLLECTION_CLASSES, :FLOORED_CLASSES, :NO_ARG_NODES
|
|
71
|
+
|
|
72
|
+
module_function
|
|
73
|
+
|
|
74
|
+
# @param sites — in-place mutation nodes whose receiver, or an element read their receiver starts from, can
|
|
75
|
+
# evaluate to the binding `type` describes, and {CalleeStore}s whose call passes that binding.
|
|
76
|
+
# @return `type` widened through every site; `type` itself when no site's widening applies.
|
|
77
|
+
def widen(type, sites)
|
|
78
|
+
sites.reduce(type) { |acc, site| widen_site(acc, site) || acc }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# `type` widened through one site, or `nil` when its widening declines.
|
|
82
|
+
def widen_site(type, site)
|
|
83
|
+
return content_floor(type) if site.is_a?(CalleeStore)
|
|
84
|
+
|
|
85
|
+
method_name, arg_types = unknown_store(site)
|
|
86
|
+
path = ElementReadWidening.element_read_path(site.receiver)
|
|
87
|
+
return widen_store(type, method_name, arg_types) if path.nil?
|
|
88
|
+
|
|
89
|
+
ElementReadWidening.widen_through_path(type, path.last, method_name, arg_types) do |element|
|
|
90
|
+
widen_store(element, method_name, arg_types)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# The straight-line widening of `type` under `method_name`, with the gradual arm on every site that can store.
|
|
95
|
+
def widen_store(type, method_name, arg_types)
|
|
96
|
+
widened = MutationWidening.widen_for_mutator(type, method_name, arg_types: arg_types)
|
|
97
|
+
return nil if widened.nil?
|
|
98
|
+
|
|
99
|
+
VALUE_PRESERVING.include?(method_name) && !literal_carrier?(type) ? widened : gradual_content(widened)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Every `Array` / `Hash` / `String` carrier `type` can be as its bare carrier: `Array[Dynamic[top]]`,
|
|
103
|
+
# `Hash[Dynamic[top], Dynamic[top]]`, `String`. A literal, a nominal (a precise one included) and a refinement
|
|
104
|
+
# over one ({.carrier_class}) all floor; so `non-empty-string`, which a callee can empty, reads `String`.
|
|
105
|
+
# Unlike the escaping floor (`StatementEvaluator#content_floor_for`), which answers one carrier for a whole
|
|
106
|
+
# `Union`, this floors a `Union` member by member, so a member no callee can fill (`nil`) stays: the binding
|
|
107
|
+
# stands where the entry binding stood, and dropping a member would narrow it. Anything else is returned
|
|
108
|
+
# untouched.
|
|
109
|
+
def content_floor(type)
|
|
110
|
+
return Type::Combinator.union(*type.members.map { |member| content_floor(member) }) if type.is_a?(Type::Union)
|
|
111
|
+
|
|
112
|
+
carrier = carrier_class(type)
|
|
113
|
+
carrier ? carrier_floor(carrier) : type
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# `"Array"`, `"Hash"` or `"String"` when `type` is a form of that carrier — a literal, a nominal, or a
|
|
117
|
+
# difference, refinement or intersection over one (`non-empty-array[Integer]`, `decimal-int-string`,
|
|
118
|
+
# `non-empty-uppercase-string`) — else nil.
|
|
119
|
+
def carrier_class(type)
|
|
120
|
+
case type
|
|
121
|
+
when Type::Tuple then "Array"
|
|
122
|
+
when Type::HashShape then "Hash"
|
|
123
|
+
when Type::Constant then "String" if type.value.is_a?(String)
|
|
124
|
+
when Type::Nominal then type.class_name if FLOORED_CLASSES.include?(type.class_name)
|
|
125
|
+
when Type::Difference, Type::Refined then carrier_class(type.base)
|
|
126
|
+
when Type::Intersection then intersection_carrier_class(type)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def intersection_carrier_class(type)
|
|
131
|
+
type.members.each do |member|
|
|
132
|
+
carrier = carrier_class(member)
|
|
133
|
+
return carrier if carrier
|
|
134
|
+
end
|
|
135
|
+
nil
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def carrier_floor(class_name)
|
|
139
|
+
return Type::Combinator.nominal_of("String") if class_name == "String"
|
|
140
|
+
|
|
141
|
+
arity = class_name == "Hash" ? 2 : 1
|
|
142
|
+
Type::Combinator.nominal_of(class_name, type_args: Array.new(arity) { Type::Combinator.untyped })
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# A carrier that still records its slots or keys: a `Tuple` / `HashShape`, alone or as a `Union` member.
|
|
146
|
+
def literal_carrier?(type)
|
|
147
|
+
case type
|
|
148
|
+
when Type::Tuple, Type::HashShape then true
|
|
149
|
+
when Type::Union then type.members.any? { |member| literal_carrier?(member) }
|
|
150
|
+
else false
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# `[mutator, arg_types]` for one site: a call stores through its own name and arguments, an index write
|
|
155
|
+
# through `[]=` with its index arguments ahead of the value. A splat stays the `nil` arity marker the
|
|
156
|
+
# `[]=` splice classifier reads.
|
|
157
|
+
def unknown_store(site)
|
|
158
|
+
arguments = site.arguments&.arguments || NO_ARG_NODES
|
|
159
|
+
unknown = arguments.map { |arg| arg.is_a?(Prism::SplatNode) ? nil : Type::Combinator.untyped }
|
|
160
|
+
return [site.name, unknown] if site.is_a?(Prism::CallNode)
|
|
161
|
+
|
|
162
|
+
[:[]=, unknown + [Type::Combinator.untyped]]
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# An `Array` / `Hash` nominal (alone, as a `Union` member, or as a refinement's base) with a value-pinned type
|
|
166
|
+
# argument. `Type::Combinator.widen_value_pinned` does not look inside type arguments, so each one is asked on
|
|
167
|
+
# its own. A `bool` or a literal union a signature declared (`Array[:a | :b]`) counts as pinned too; the arm it
|
|
168
|
+
# takes can only quiet a report, which is the accepted cost of reading every such binding past one iteration.
|
|
169
|
+
# A class-level argument (`Array[Integer]`) is not pinned: a store of the same class leaves it true, which is
|
|
170
|
+
# the claim this seam may not grow.
|
|
171
|
+
def value_pinned_collection?(type)
|
|
172
|
+
case type
|
|
173
|
+
when Type::Union then type.members.any? { |member| value_pinned_collection?(member) }
|
|
174
|
+
when Type::Difference then value_pinned_collection?(type.base)
|
|
175
|
+
when Type::Nominal
|
|
176
|
+
COLLECTION_CLASSES.include?(type.class_name) &&
|
|
177
|
+
type.type_args.any? { |arg| Type::Combinator.widen_value_pinned(arg) != arg }
|
|
178
|
+
else false
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Every type argument of an `Array` / `Hash` carrier joined with `Dynamic[top]`, member-wise through a
|
|
183
|
+
# `Union` and through a `Difference`'s base. Anything else is returned untouched.
|
|
184
|
+
def gradual_content(type)
|
|
185
|
+
case type
|
|
186
|
+
when Type::Union then Type::Combinator.union(*type.members.map { |member| gradual_content(member) })
|
|
187
|
+
when Type::Difference then Type::Combinator.difference(gradual_content(type.base), type.removed)
|
|
188
|
+
when Type::Nominal
|
|
189
|
+
return type unless COLLECTION_CLASSES.include?(type.class_name) && !type.type_args.empty?
|
|
190
|
+
|
|
191
|
+
Type::Combinator.nominal_of(
|
|
192
|
+
type.class_name,
|
|
193
|
+
type_args: type.type_args.map { |arg| Type::Combinator.union(arg, Type::Combinator.untyped) }
|
|
194
|
+
)
|
|
195
|
+
else type
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|