rigortype 0.3.8 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +109 -13
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +37 -4
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +14 -1
- data/docs/handbook/11-sig-gen.md +72 -1
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +32 -4
- data/docs/manual/03-configuration.md +11 -0
- data/docs/manual/04-diagnostics.md +11 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +6 -1
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/plugins/rigor-actionpack.md +18 -0
- data/docs/manual/plugins/rigor-activerecord.md +28 -0
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +32 -2
- data/docs/manual/plugins/rigor-rbs-inline.md +42 -1
- data/lib/rigor/analysis/baseline.rb +2 -2
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +39 -4
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +200 -32
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +6 -1
- data/lib/rigor/analysis/incremental.rb +16 -0
- data/lib/rigor/analysis/incremental_session.rb +81 -22
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +2 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +4 -1
- data/lib/rigor/analysis/run_cache_key.rb +1 -1
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +177 -26
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -10
- data/lib/rigor/analysis/runner/pool_coordinator.rb +256 -88
- data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +133 -35
- data/lib/rigor/analysis/worker_session.rb +9 -10
- data/lib/rigor/bleeding_edge.rb +12 -24
- data/lib/rigor/builtins/hkt_builtins.rb +2 -2
- data/lib/rigor/builtins/imported_refinements.rb +155 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +4 -4
- data/lib/rigor/builtins/static_return_refinements.rb +5 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +58 -20
- data/lib/rigor/cache/engine_source.rb +4 -4
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +40 -6
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +79 -11
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +77 -32
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +3 -3
- data/lib/rigor/cli/docs_command.rb +2 -2
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +1 -1
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +2 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +2 -2
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +36 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +10 -6
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +68 -6
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +6 -6
- data/lib/rigor/configuration.rb +43 -4
- data/lib/rigor/effects/attribution.rb +1 -3
- data/lib/rigor/effects/config_envelopes.rb +6 -8
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +0 -1
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +8 -8
- data/lib/rigor/effects/envelope_index.rb +5 -8
- data/lib/rigor/effects/framework_units.rb +4 -6
- data/lib/rigor/effects/identity.rb +4 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/method_key.rb +1 -1
- data/lib/rigor/effects/plugin_facts.rb +4 -6
- data/lib/rigor/effects/propagator.rb +2 -3
- data/lib/rigor/effects/scanner.rb +1 -1
- data/lib/rigor/effects/signature_sources.rb +3 -5
- data/lib/rigor/effects/snapshot.rb +10 -10
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/unit_scan.rb +10 -10
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +51 -4
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +388 -59
- data/lib/rigor/environment.rb +105 -20
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/inference/acceptance.rb +153 -8
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/body_fixpoint.rb +5 -5
- data/lib/rigor/inference/budget_trace.rb +1 -5
- data/lib/rigor/inference/captured_locals.rb +2 -3
- data/lib/rigor/inference/closure_escape_analyzer.rb +2 -4
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +168 -0
- data/lib/rigor/inference/expression_typer.rb +763 -143
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +1 -5
- data/lib/rigor/inference/macro_block_self_type.rb +1 -4
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +2 -9
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +61 -47
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +165 -31
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +4 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +12 -13
- data/lib/rigor/inference/method_parameter_binder.rb +4 -6
- data/lib/rigor/inference/multi_target_binder.rb +1 -3
- data/lib/rigor/inference/mutation_rejoin.rb +168 -0
- data/lib/rigor/inference/mutation_widening.rb +100 -51
- data/lib/rigor/inference/narrowing.rb +299 -46
- data/lib/rigor/inference/optimistic_origin.rb +1 -7
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_patched_methods.rb +2 -2
- data/lib/rigor/inference/project_patched_scanner.rb +3 -3
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +3 -3
- data/lib/rigor/inference/refinement_mutation.rb +72 -0
- data/lib/rigor/inference/scope_indexer.rb +688 -151
- data/lib/rigor/inference/statement_evaluator.rb +221 -50
- data/lib/rigor/inference/string_mutation.rb +60 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +1 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +2 -2
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +2 -5
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/plugin/base.rb +90 -21
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +7 -7
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +31 -12
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +23 -1
- data/lib/rigor/plugin/registry.rb +42 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +12 -1
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +11 -11
- data/lib/rigor/protection/kill_signature.rb +2 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +6 -9
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +61 -21
- data/lib/rigor/reflection/constant_path.rb +126 -0
- data/lib/rigor/reflection.rb +26 -10
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +30 -0
- data/lib/rigor/scope.rb +203 -4
- data/lib/rigor/sig_gen/generator.rb +115 -22
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/observation_collector.rb +17 -15
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +4 -5
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +111 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/writer.rb +23 -6
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +2 -5
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +68 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +5 -5
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +3 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +1 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +33 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +28 -2
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +1 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +3 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +42 -7
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +119 -14
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +1 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +6 -3
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +0 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +1 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +1 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +3 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -0
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +128 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +1 -0
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +5 -5
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/environment.rbs +5 -0
- data/sig/rigor/inference.rbs +3 -10
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/manifest.rbs +2 -1
- data/sig/rigor/reflection.rbs +3 -1
- data/sig/rigor/scope.rbs +24 -3
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -0
- data/sig/rigor/type.rbs +27 -1
- data/sig/rigor.rbs +1 -0
- data/skills/rigor-ask/SKILL.md +8 -6
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +13 -2
- data/skills/rigor-project-init/SKILL.md +6 -3
- data/skills/rigor-project-init/references/02-configure.md +10 -6
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-type-oracle/SKILL.md +228 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +261 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +128 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +8 -5
- metadata +26 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -122,13 +122,12 @@ module Rigor
|
|
|
122
122
|
end
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
-
# @param scope
|
|
125
|
+
# @param scope — base scope for type inference.
|
|
126
126
|
def initialize(scope: nil)
|
|
127
127
|
@scope = scope || Scope.empty
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
-
# @param root
|
|
131
|
-
# @return [FileResult]
|
|
130
|
+
# @param root — the parsed AST
|
|
132
131
|
def scan(root)
|
|
133
132
|
scope_index = ScopeIndexer.index(root, default_scope: @scope)
|
|
134
133
|
tier_counts = TIERS.to_h { |t| [t, 0] }
|
|
@@ -156,7 +155,7 @@ module Rigor
|
|
|
156
155
|
when Type::Nominal, Type::Singleton,
|
|
157
156
|
Type::DataClass, Type::StructClass then :nominal
|
|
158
157
|
when Type::Tuple, Type::HashShape,
|
|
159
|
-
Type::IntegerRange, Type::App,
|
|
158
|
+
Type::IntegerRange, Type::FloatRange, Type::App,
|
|
160
159
|
Type::DataInstance, Type::StructInstance,
|
|
161
160
|
Type::BoundMethod then :shaped
|
|
162
161
|
when Type::Refined then :refined
|
|
@@ -28,7 +28,7 @@ module Rigor
|
|
|
28
28
|
|
|
29
29
|
attr_reader :by_key
|
|
30
30
|
|
|
31
|
-
# @param entries
|
|
31
|
+
# @param entries — flat list of declarations observed during the pre-pass.
|
|
32
32
|
# First-write-wins on `(class_name, method_name, kind)` duplicates so the
|
|
33
33
|
# `pre-eval.duplicate-declaration` diagnostic emission stays decoupled from registry behaviour.
|
|
34
34
|
def initialize(entries: [])
|
|
@@ -39,7 +39,7 @@ module Rigor
|
|
|
39
39
|
freeze
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
# @return
|
|
42
|
+
# @return the recorded entry for the given `(class_name, method_name, kind)` triple,
|
|
43
43
|
# or `nil` when no pre-eval file declared it.
|
|
44
44
|
def lookup(class_name:, method_name:, kind:)
|
|
45
45
|
@by_key[[class_name, method_name, kind]]
|
|
@@ -31,13 +31,13 @@ module Rigor
|
|
|
31
31
|
|
|
32
32
|
module_function
|
|
33
33
|
|
|
34
|
-
# @param paths
|
|
34
|
+
# @param paths — absolute paths to the pre-eval files. The runner has already
|
|
35
35
|
# validated that each path exists (slice-1 `pre-eval.file-not-found` `:error` covers missing
|
|
36
36
|
# entries); the scanner does NOT re-check existence.
|
|
37
|
-
# @param buffer
|
|
37
|
+
# @param buffer — editor-mode buffer binding. When set, the
|
|
38
38
|
# scanner reads the buffer's physical bytes if a pre-eval entry matches the logical path, so
|
|
39
39
|
# users editing a monkey-patch file see the in-flight version in their analysis.
|
|
40
|
-
# @return
|
|
40
|
+
# @return the populated registry plus any per-file warnings.
|
|
41
41
|
def scan(paths, buffer: nil)
|
|
42
42
|
entries = []
|
|
43
43
|
diagnostics = []
|
|
@@ -37,8 +37,7 @@ module Rigor
|
|
|
37
37
|
@scope = scope || Scope.empty
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
# @param root
|
|
41
|
-
# @return [FileResult]
|
|
40
|
+
# @param root — the parsed AST
|
|
42
41
|
def scan(root)
|
|
43
42
|
index = ScopeIndexer.index(root, default_scope: @scope)
|
|
44
43
|
protected_count = 0
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../type"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Inference
|
|
7
|
+
# Reads the endpoints out of a `Constant<Range>`.
|
|
8
|
+
#
|
|
9
|
+
# A `Constant` normally carries a value and no generic instantiation, which is why acceptance
|
|
10
|
+
# ignores a nominal's `type_args` against one. A Range value is the exception: the engine only
|
|
11
|
+
# builds `Constant<Range>` when both endpoints are static (`ExpressionTyper#type_of_range`), so
|
|
12
|
+
# the element the range would yield IS known, and a `Range[T]` parameter can be judged against it.
|
|
13
|
+
#
|
|
14
|
+
# Two consumers share the reading so they cannot drift: `Acceptance` refutes a `Range[T]`
|
|
15
|
+
# parameter whose `T` rejects an endpoint (issue #833), and `RbsDispatch` binds a method-level
|
|
16
|
+
# `Range[A]` parameter's `A` from the endpoints (issue #834).
|
|
17
|
+
module RangeConstant
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
# The non-`nil` endpoints of the range `type` pins, or nil when there is nothing to read from.
|
|
21
|
+
#
|
|
22
|
+
# nil — meaning "no opinion, keep the answer you already had" — covers a carrier that is not a
|
|
23
|
+
# `Constant<Range>`, a range with no endpoint at all (`nil..nil` constrains nothing), and a
|
|
24
|
+
# range whose endpoints are not literals. The literal set is the one
|
|
25
|
+
# `ExpressionTyper#static_range_endpoint` pins; a value outside it reached the carrier by some
|
|
26
|
+
# other route and the caller has no lifting for it.
|
|
27
|
+
def literal_endpoints(type)
|
|
28
|
+
return nil unless type.is_a?(Type::Constant)
|
|
29
|
+
|
|
30
|
+
value = type.value
|
|
31
|
+
return nil unless value.is_a?(::Range)
|
|
32
|
+
|
|
33
|
+
endpoints = [value.begin, value.end].compact
|
|
34
|
+
return nil if endpoints.empty?
|
|
35
|
+
return nil unless endpoints.all? { |endpoint| literal_endpoint?(endpoint) }
|
|
36
|
+
|
|
37
|
+
endpoints
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# The endpoints lifted to their own classes and unioned — the element type the range would
|
|
41
|
+
# yield. Lifting rather than pinning the values mirrors
|
|
42
|
+
# `ExpressionTyper#nominal_range_for_endpoints`: `1..9` yields Integers, not the two values 1
|
|
43
|
+
# and 9, so binding a `Range[A]` parameter's `A` to `Integer` states what the runtime can
|
|
44
|
+
# honour. Nil when {#literal_endpoints} has nothing to read.
|
|
45
|
+
def element_type(type)
|
|
46
|
+
endpoints = literal_endpoints(type)
|
|
47
|
+
return nil if endpoints.nil?
|
|
48
|
+
|
|
49
|
+
Type::Combinator.union(*endpoints.map { |endpoint| Type::Combinator.nominal_of(endpoint.class.name) })
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def literal_endpoint?(value)
|
|
53
|
+
value.is_a?(::Integer) || value.is_a?(::Float) || value.is_a?(::String)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -100,17 +100,31 @@ module Rigor
|
|
|
100
100
|
ALIAS_EXPANSION_LIMIT = 8
|
|
101
101
|
private_constant :ALIAS_EXPANSION_LIMIT
|
|
102
102
|
|
|
103
|
+
# #775 — `TypeName#relative!` allocates a TypeName and a Namespace and `#to_s` joins the path: four
|
|
104
|
+
# objects per class-instance translation, ~380k of them on the lib self-check, for the same few
|
|
105
|
+
# hundred names. rbs compares a TypeName by namespace + name, so a value-keyed memo answers every
|
|
106
|
+
# repeat with one frozen String.
|
|
107
|
+
@relative_names = {}
|
|
108
|
+
|
|
109
|
+
# #775 — the translated form of a CLOSED alias expansion, keyed by the expansion. Closed means no
|
|
110
|
+
# `self`, `instance` or type variable anywhere inside, so the caller's context cannot change the
|
|
111
|
+
# answer; at expansion depth 0 the budget cannot either. rbs compares types by value, so the memo
|
|
112
|
+
# is per distinct expansion, not per loader (a re-parsed identical alias hits), and the weak keys
|
|
113
|
+
# let an entry go with the loader whose memo held the expansion. `Rigor::Type::t` on the self-check
|
|
114
|
+
# is a 21-member union that was re-translated ~13k times, each time re-normalising the union from
|
|
115
|
+
# scratch; every repeat now shares one Union.
|
|
116
|
+
@closed_alias_translations = ObjectSpace::WeakKeyMap.new
|
|
117
|
+
|
|
103
118
|
class << self
|
|
104
|
-
# @param
|
|
105
|
-
# @param
|
|
106
|
-
# @param instance_type [Rigor::Type, nil] substitute for `Bases::Instance`. Defaults to `nil`,
|
|
119
|
+
# @param self_type — substitute for `Bases::Self`.
|
|
120
|
+
# @param instance_type — substitute for `Bases::Instance`. Defaults to `nil`,
|
|
107
121
|
# which degrades to Dynamic[Top].
|
|
108
|
-
# @param type_vars
|
|
122
|
+
# @param type_vars — substitution map for `Bases::Variable`. Keys
|
|
109
123
|
# are the RBS variable names (e.g., `:Elem`); values are Rigor types that replace the
|
|
110
124
|
# variable. Variables that are not bound in the map degrade to Dynamic[Top].
|
|
111
|
-
# @param alias_expander
|
|
112
|
-
# in practice the environment's `RbsLoader`. When nil, aliases degrade to
|
|
113
|
-
#
|
|
125
|
+
# @param alias_expander — anything answering `expand_type_alias`, which resolves `RBS::Types::Alias`
|
|
126
|
+
# one level out — in practice the environment's `RbsLoader`. When nil, aliases degrade to
|
|
127
|
+
# Dynamic[Top].
|
|
114
128
|
def translate(rbs_type, self_type: nil, instance_type: nil, type_vars: EMPTY_TYPE_VARS,
|
|
115
129
|
alias_expander: nil)
|
|
116
130
|
translate_in(rbs_type, Context.new(self_type, instance_type, type_vars, alias_expander, 0))
|
|
@@ -180,11 +194,17 @@ module Rigor
|
|
|
180
194
|
# `Nominal["Array", [Nominal["Integer"]]]`. Variables inside the args participate in
|
|
181
195
|
# substitution through the same `type_vars:` map.
|
|
182
196
|
def translate_class_instance(rbs_type, context)
|
|
183
|
-
name = rbs_type.name
|
|
197
|
+
name = relative_name(rbs_type.name)
|
|
198
|
+
return Type::Combinator.nominal_of(name) if rbs_type.args.empty?
|
|
199
|
+
|
|
184
200
|
translated_args = rbs_type.args.map { |arg| translate_in(arg, context) }
|
|
185
201
|
Type::Combinator.nominal_of(name, type_args: translated_args)
|
|
186
202
|
end
|
|
187
203
|
|
|
204
|
+
def relative_name(type_name)
|
|
205
|
+
@relative_names[type_name] ||= type_name.relative!.to_s.freeze
|
|
206
|
+
end
|
|
207
|
+
|
|
188
208
|
# Preserves tuple precision through the boundary. Each positional element type is translated
|
|
189
209
|
# recursively under the caller's substitution context, and the resulting list is wrapped in a
|
|
190
210
|
# `Rigor::Type::Tuple`.
|
|
@@ -218,8 +238,7 @@ module Rigor
|
|
|
218
238
|
# `singleton(Foo)` is the type of the constant `Foo` itself (the class object). With the
|
|
219
239
|
# dedicated Singleton type, we map directly to `Singleton[Foo]`.
|
|
220
240
|
def translate_class_singleton(rbs_type, _context)
|
|
221
|
-
|
|
222
|
-
Type::Combinator.singleton_of(name)
|
|
241
|
+
Type::Combinator.singleton_of(relative_name(rbs_type.name))
|
|
223
242
|
end
|
|
224
243
|
|
|
225
244
|
# #529 — sees through a type alias instead of reading `untyped`. `expand_type_alias` resolves
|
|
@@ -232,8 +251,27 @@ module Rigor
|
|
|
232
251
|
|
|
233
252
|
expanded = expander.expand_type_alias(rbs_type)
|
|
234
253
|
return Type::Combinator.untyped if expanded.nil?
|
|
254
|
+
# A nested expansion is translated under its parent's budget, and `rigor trace` records every
|
|
255
|
+
# union merge as it happens, so neither consults the memo.
|
|
256
|
+
return translate_in(expanded, context.deeper) unless context.alias_depth.zero? && !FlowTracer.active?
|
|
257
|
+
|
|
258
|
+
cached = @closed_alias_translations[expanded]
|
|
259
|
+
return cached if cached
|
|
260
|
+
|
|
261
|
+
translated = translate_in(expanded, context.deeper)
|
|
262
|
+
@closed_alias_translations[expanded] = translated if closed_type?(expanded)
|
|
263
|
+
translated
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# True when nothing in `rbs_type`'s tree reads the translation context: no `self`, no `instance`,
|
|
267
|
+
# no type variable. Every rbs type answers `each_type` (the leaves through `EmptyEachType`).
|
|
268
|
+
def closed_type?(rbs_type)
|
|
269
|
+
case rbs_type
|
|
270
|
+
when RBS::Types::Bases::Self, RBS::Types::Bases::Instance, RBS::Types::Variable then return false
|
|
271
|
+
end
|
|
235
272
|
|
|
236
|
-
|
|
273
|
+
rbs_type.each_type { |inner| return false unless closed_type?(inner) }
|
|
274
|
+
true
|
|
237
275
|
end
|
|
238
276
|
|
|
239
277
|
# #529 — `A & B` reads as its first member that carries static evidence. Every value of the
|
|
@@ -30,9 +30,9 @@ module Rigor
|
|
|
30
30
|
|
|
31
31
|
module_function
|
|
32
32
|
|
|
33
|
-
# @param node
|
|
34
|
-
# @param depth
|
|
35
|
-
# @return
|
|
33
|
+
# @param node — the receiver expression.
|
|
34
|
+
# @param depth — recursion depth, internal.
|
|
35
|
+
# @return every variable
|
|
36
36
|
# read the expression can evaluate to; empty when it can evaluate to none.
|
|
37
37
|
def candidates(node, depth = 0)
|
|
38
38
|
return [] if node.nil? || depth > WALK_DEPTH_CAP
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../type"
|
|
4
|
+
require_relative "string_mutation"
|
|
5
|
+
|
|
6
|
+
module Rigor
|
|
7
|
+
module Inference
|
|
8
|
+
# The empty-witness `Difference` arm of {MutationWidening} — `non-empty-array[T]`,
|
|
9
|
+
# `non-empty-hash[K, V]` and `non-empty-string`, the refinement carriers `empty?` / `any?`
|
|
10
|
+
# narrowing writes (ADR-47 §4-4).
|
|
11
|
+
#
|
|
12
|
+
# Two questions, which the seam used to answer as one. **What the receiver now holds** is the
|
|
13
|
+
# ordinary content join, and it applies to a refinement exactly as it applies to a `Tuple`:
|
|
14
|
+
# {MutationWidening} owns that algebra and passes it in. **Whether the receiver is still
|
|
15
|
+
# provably non-empty** is this module's own, and it is a property of the mutator alone.
|
|
16
|
+
#
|
|
17
|
+
# Answering both with "widen to the bare base" was ADR-56 WD2.9's deferred branch (issue #936):
|
|
18
|
+
# `if xs.any?; xs << "s"` read `Array[String]` for an array that holds a String too — a wrong
|
|
19
|
+
# type, not a wide one — and lost a witness an append cannot falsify.
|
|
20
|
+
module RefinementMutation
|
|
21
|
+
# Mutators that CANNOT leave a non-empty receiver empty. Whitelists rather than a table of
|
|
22
|
+
# emptiers: a name missing from these retracts the witness, which is the conservative answer
|
|
23
|
+
# every mutator got before. The listed ones either only add (`<< push …`) or only permute a
|
|
24
|
+
# fixed number of slots (`sort! map! …`); `replace`, `compact!`, `flatten!`, `uniq!` and every
|
|
25
|
+
# remover are deliberately absent, since each has an input that empties the receiver.
|
|
26
|
+
EMPTY_PRESERVING = {
|
|
27
|
+
"Array" => %i[
|
|
28
|
+
<< push append prepend unshift concat insert
|
|
29
|
+
map! collect! sort! sort_by! reverse! rotate! shuffle!
|
|
30
|
+
].to_set.freeze,
|
|
31
|
+
"Hash" => %i[[]= store merge! update transform_keys! transform_values!].to_set.freeze
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
34
|
+
module_function
|
|
35
|
+
|
|
36
|
+
# The widened binding for an empty-witness refinement about to be mutated by `method_name`,
|
|
37
|
+
# or `nil` when nothing applies — including the case where the answer would be the pre-state
|
|
38
|
+
# itself, which the seam's callers read as "no widening".
|
|
39
|
+
#
|
|
40
|
+
# The block receives the refinement's BASE and answers the base with the mutator's added
|
|
41
|
+
# content joined in, or a falsey value to decline (the mutator is not in that base's table).
|
|
42
|
+
# A String base is answered here instead: it carries no content parameter, so the only
|
|
43
|
+
# question it has is the witness one.
|
|
44
|
+
def widen(difference, method_name)
|
|
45
|
+
return nil unless difference.removes_empty_witness?
|
|
46
|
+
|
|
47
|
+
base = difference.base
|
|
48
|
+
joined = base.class_name == "String" ? string_base(base, method_name) : yield(base)
|
|
49
|
+
return nil unless joined
|
|
50
|
+
|
|
51
|
+
widened = preserves_witness?(base.class_name, method_name) ? refine(joined, difference) : joined
|
|
52
|
+
widened == difference ? nil : widened
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# A `non-empty-string` survives every mutator that cannot empty the buffer, and those are
|
|
56
|
+
# exactly the ones {StringMutation} does not list as emptying — so this arm declines them
|
|
57
|
+
# and the refinement stands, rather than widening to `String` and dropping it.
|
|
58
|
+
def string_base(base, method_name)
|
|
59
|
+
StringMutation::EMPTYING_MUTATORS.include?(method_name) ? base : nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def preserves_witness?(class_name, method_name)
|
|
63
|
+
table = EMPTY_PRESERVING[class_name]
|
|
64
|
+
!!table&.include?(method_name)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def refine(joined, difference)
|
|
68
|
+
Type::Combinator.difference(joined, difference.removed)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|