rigortype 0.4.6 → 0.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/data/core_overlay/bigdecimal.rbs +33 -0
- data/data/core_overlay/resolv.rbs +30 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +45 -13
- data/data/gem_overlay/addressable/addressable.rbs +40 -0
- data/data/vendored_gem_sigs/bundler/bundler.rbs +1 -1
- data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +4 -3
- data/docs/handbook/01-getting-started.md +6 -3
- data/docs/handbook/11-sig-gen.md +85 -3
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/install.md +20 -0
- data/docs/manual/01-installation.md +67 -26
- data/docs/manual/02-cli-reference.md +455 -113
- data/docs/manual/03-configuration.md +76 -5
- data/docs/manual/04-diagnostics.md +5 -4
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/08-skills.md +11 -0
- data/docs/manual/09-editor-integration.md +21 -2
- data/docs/manual/10-mcp-server.md +38 -2
- data/docs/manual/12-caching.md +4 -3
- data/docs/manual/14-rails-quickstart.md +1 -1
- data/docs/manual/19-effect-labels.md +3 -4
- data/docs/manual/plugins/rigor-actionpack.md +32 -15
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +23 -1
- data/docs/manual/plugins/rigor-sorbet.md +17 -3
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/check_rules/always_raises_shield.rb +147 -0
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/call_facts.rb +58 -0
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +12 -4
- data/lib/rigor/analysis/check_rules/duplicate_hash_key_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +85 -13
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +16 -4
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +6 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/plugin_api_surface.rb +195 -0
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +41 -12
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +27 -1
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +3 -3
- data/lib/rigor/analysis/check_rules/replaced_singleton_defs.rb +96 -0
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/rule_ids.rb +9 -2
- data/lib/rigor/analysis/check_rules/rule_walk.rb +9 -7
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +3 -4
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +3 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules.rb +720 -141
- data/lib/rigor/analysis/crash_signature.rb +45 -3
- data/lib/rigor/analysis/dependency_recorder.rb +237 -80
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +14 -3
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/index.rb +6 -8
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/edit_replay.rb +93 -6
- data/lib/rigor/analysis/fact_store.rb +3 -3
- data/lib/rigor/analysis/incremental.rb +11 -1
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +4 -3
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +306 -53
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -3
- data/lib/rigor/analysis/rule_catalog.rb +39 -3
- data/lib/rigor/analysis/run_cache_key.rb +27 -3
- data/lib/rigor/analysis/run_disclosure_credit.rb +26 -6
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -2
- data/lib/rigor/analysis/runner/declaration_position.rb +8 -8
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +264 -112
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +4 -9
- data/lib/rigor/analysis/runner/pool_coordinator.rb +173 -328
- data/lib/rigor/analysis/runner/project_pre_passes.rb +4 -37
- data/lib/rigor/analysis/runner/run_level_facts.rb +304 -0
- data/lib/rigor/analysis/runner/run_snapshots.rb +44 -54
- data/lib/rigor/analysis/runner/worker_payload.rb +36 -0
- data/lib/rigor/analysis/runner.rb +298 -109
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +62 -23
- data/lib/rigor/analysis/template_unit_positions.rb +2 -3
- data/lib/rigor/analysis/template_units.rb +9 -1
- data/lib/rigor/analysis/worker_session.rb +65 -71
- data/lib/rigor/bleeding_edge.rb +22 -10
- data/lib/rigor/builtins/imported_refinements.rb +6 -8
- data/lib/rigor/builtins/predefined_constant_refinements.rb +1 -1
- data/lib/rigor/builtins/regex_refinement.rb +4 -6
- data/lib/rigor/cache/descriptor.rb +6 -5
- data/lib/rigor/cache/file_digest.rb +39 -31
- data/lib/rigor/cache/incremental_snapshot.rb +95 -17
- data/lib/rigor/cache/rbs_cache_producer.rb +2 -2
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +1 -1
- data/lib/rigor/cache/rbs_class_type_param_names.rb +2 -2
- data/lib/rigor/cache/rbs_constant_table.rb +1 -1
- data/lib/rigor/cache/rbs_descriptor.rb +90 -4
- data/lib/rigor/cache/rbs_environment.rb +8 -1
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +2 -2
- data/lib/rigor/cache/rbs_known_class_names.rb +1 -1
- data/lib/rigor/cache/store.rb +11 -10
- data/lib/rigor/ci_detector.rb +1 -1
- data/lib/rigor/cli/annotate_command.rb +24 -19
- data/lib/rigor/cli/baseline_command.rb +160 -57
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +112 -104
- data/lib/rigor/cli/check_runner_factory.rb +2 -2
- data/lib/rigor/cli/command.rb +15 -1
- data/lib/rigor/cli/coverage_command.rb +21 -8
- data/lib/rigor/cli/coverage_mutation.rb +5 -7
- data/lib/rigor/cli/coverage_renderer.rb +2 -1
- data/lib/rigor/cli/coverage_scan.rb +3 -5
- data/lib/rigor/cli/diff_command.rb +25 -20
- data/lib/rigor/cli/docs_command.rb +1 -2
- data/lib/rigor/cli/doctor_command.rb +12 -12
- data/lib/rigor/cli/effects_command.rb +50 -40
- data/lib/rigor/cli/effects_diff_renderer.rb +18 -17
- data/lib/rigor/cli/effects_explain_renderer.rb +13 -12
- data/lib/rigor/cli/effects_renderer.rb +2 -1
- data/lib/rigor/cli/effects_snapshot_command.rb +26 -18
- data/lib/rigor/cli/explain_command.rb +18 -8
- data/lib/rigor/cli/fused_protection_renderer.rb +2 -1
- data/lib/rigor/cli/json_document.rb +41 -0
- data/lib/rigor/cli/lens_command.rb +29 -10
- data/lib/rigor/cli/lsp_command.rb +250 -23
- data/lib/rigor/cli/mcp_command.rb +12 -7
- data/lib/rigor/cli/mutation_fork_scan.rb +1 -1
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -2
- data/lib/rigor/cli/options.rb +40 -1
- data/lib/rigor/cli/plugin_command.rb +93 -46
- data/lib/rigor/cli/plugins_command.rb +17 -18
- data/lib/rigor/cli/plugins_renderer.rb +10 -6
- data/lib/rigor/cli/protection_fork_scan.rb +2 -2
- data/lib/rigor/cli/protection_renderer.rb +2 -1
- data/lib/rigor/cli/show_bleedingedge_command.rb +21 -15
- data/lib/rigor/cli/sig_gen_command.rb +92 -27
- data/lib/rigor/cli/skill_command.rb +32 -3
- data/lib/rigor/cli/skill_deep_probe.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +2 -1
- data/lib/rigor/cli/trace_command.rb +14 -9
- data/lib/rigor/cli/triage_command.rb +10 -11
- data/lib/rigor/cli/triage_renderer.rb +2 -1
- data/lib/rigor/cli/type_of_command.rb +16 -11
- data/lib/rigor/cli/type_of_project_scope.rb +1 -4
- data/lib/rigor/cli/type_of_renderer.rb +4 -1
- data/lib/rigor/cli/type_scan_command.rb +14 -9
- data/lib/rigor/cli/type_scan_renderer.rb +2 -1
- data/lib/rigor/cli/unused_command.rb +27 -17
- data/lib/rigor/cli/upgrade_command.rb +5 -0
- data/lib/rigor/cli.rb +214 -56
- data/lib/rigor/config_audit.rb +33 -19
- data/lib/rigor/configuration/severity_profile.rb +14 -5
- data/lib/rigor/configuration.rb +104 -35
- data/lib/rigor/effects/collector.rb +53 -21
- data/lib/rigor/effects/definition_context.rb +0 -2
- data/lib/rigor/effects/envelope.rb +1 -1
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/mutation_classifier.rb +4 -7
- data/lib/rigor/effects/propagator.rb +1 -1
- data/lib/rigor/effects/registry.rb +2 -2
- data/lib/rigor/effects/snapshot.rb +1 -1
- data/lib/rigor/effects/taint_cause.rb +0 -2
- data/lib/rigor/effects/unit_scan.rb +9 -13
- data/lib/rigor/environment/bundle_sig_discovery.rb +64 -33
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/constant_type_cache_holder.rb +5 -0
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +18 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +381 -0
- data/lib/rigor/environment/gated_signature_guard.rb +1 -1
- data/lib/rigor/environment/gated_signature_plan.rb +5 -2
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -0
- data/lib/rigor/environment/lockfile_resolver.rb +28 -12
- data/lib/rigor/environment/member_consistency/comparator.rb +18 -1
- data/lib/rigor/environment/member_consistency.rb +56 -7
- data/lib/rigor/environment/missing_gem_constant_index.rb +3 -2
- data/lib/rigor/environment/project_path_gems.rb +124 -0
- data/lib/rigor/environment/rbs_collection_discovery.rb +123 -8
- data/lib/rigor/environment/rbs_coverage_report.rb +12 -11
- data/lib/rigor/environment/rbs_hierarchy.rb +12 -15
- data/lib/rigor/environment/rbs_loader.rb +772 -110
- data/lib/rigor/environment/reflection.rb +7 -7
- data/lib/rigor/environment/required_features.rb +0 -3
- data/lib/rigor/environment/ruby_library_roots.rb +1 -1
- data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
- data/lib/rigor/environment.rb +169 -42
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +136 -40
- data/lib/rigor/inference/alias_mutation_floor/foreign_locals.rb +117 -0
- data/lib/rigor/inference/alias_mutation_floor/memos.rb +85 -0
- data/lib/rigor/inference/alias_mutation_floor/reach.rb +119 -0
- data/lib/rigor/inference/alias_mutation_floor/site_collector.rb +252 -0
- data/lib/rigor/inference/alias_mutation_floor.rb +339 -0
- data/lib/rigor/inference/anonymous_meta_class.rb +18 -0
- data/lib/rigor/inference/block_auto_splat.rb +1 -1
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +185 -0
- data/lib/rigor/inference/budget_trace.rb +8 -2
- data/lib/rigor/inference/builtins/array_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/exception_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/numeric_catalog.rb +2 -5
- data/lib/rigor/inference/builtins/random_catalog.rb +2 -2
- data/lib/rigor/inference/callee_mutation_chain.rb +88 -77
- data/lib/rigor/inference/callee_write_census.rb +815 -0
- data/lib/rigor/inference/captured_locals.rb +2 -0
- data/lib/rigor/inference/census_foreign_block.rb +354 -0
- data/lib/rigor/inference/clause_widening.rb +1 -1
- data/lib/rigor/inference/closure_escape_analyzer.rb +11 -4
- data/lib/rigor/inference/construction_escape.rb +258 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- data/lib/rigor/inference/declaration_walk.rb +4 -0
- data/lib/rigor/inference/deep_erasure.rb +39 -7
- data/lib/rigor/inference/def_handle.rb +1 -1
- data/lib/rigor/inference/def_node_resolver.rb +33 -15
- data/lib/rigor/inference/def_return_typer.rb +47 -5
- data/lib/rigor/inference/definer_resolution.rb +19 -9
- data/lib/rigor/inference/definers_index.rb +162 -0
- data/lib/rigor/inference/direct_ivar_writes.rb +300 -0
- data/lib/rigor/inference/element_read_widening.rb +49 -3
- data/lib/rigor/inference/error_info.rb +16 -0
- data/lib/rigor/inference/expression_typer.rb +1559 -320
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/flow_tracer.rb +31 -14
- data/lib/rigor/inference/fork_map.rb +3 -0
- data/lib/rigor/inference/fresh_frame_blocks.rb +52 -1
- data/lib/rigor/inference/global_write_census.rb +81 -5
- data/lib/rigor/inference/global_writer_reach.rb +260 -0
- data/lib/rigor/inference/hkt_body.rb +1 -2
- data/lib/rigor/inference/hkt_body_parser.rb +3 -5
- data/lib/rigor/inference/hkt_reducer.rb +2 -2
- data/lib/rigor/inference/hkt_registry.rb +3 -5
- data/lib/rigor/inference/in_effect_refinements.rb +7 -0
- data/lib/rigor/inference/indexed_narrowing.rb +61 -15
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +154 -8
- data/lib/rigor/inference/key_presence_guard.rb +51 -24
- data/lib/rigor/inference/last_line/self_evidence.rb +30 -0
- data/lib/rigor/inference/last_line.rb +5 -2
- data/lib/rigor/inference/loop_value_record.rb +66 -14
- data/lib/rigor/inference/match_rebinding/frame.rb +57 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +101 -0
- data/lib/rigor/inference/match_rebinding.rb +28 -5
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/argument_distribution.rb +40 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +44 -30
- data/lib/rigor/inference/method_dispatcher/class_keyed_block_params.rb +65 -0
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +3 -3
- data/lib/rigor/inference/method_dispatcher/contested_overloads.rb +89 -0
- data/lib/rigor/inference/method_dispatcher/core_enumerable_receiver.rb +44 -0
- data/lib/rigor/inference/method_dispatcher/declared_constructor.rb +151 -0
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/imprecise_argument.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/interface_shape.rb +181 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/no_match_fallback.rb +54 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +51 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +606 -78
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +3 -3
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +9 -7
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +467 -84
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +0 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +50 -17
- data/lib/rigor/inference/method_dispatcher/singleton_type_params.rb +104 -0
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +4 -6
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +123 -25
- data/lib/rigor/inference/method_parameter_binder.rb +136 -56
- data/lib/rigor/inference/module_function_state/spellings.rb +2 -2
- data/lib/rigor/inference/module_function_state.rb +24 -3
- data/lib/rigor/inference/multi_target_binder.rb +2 -2
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +199 -29
- data/lib/rigor/inference/narrowing.rb +238 -50
- data/lib/rigor/inference/operand_effects.rb +43 -2
- data/lib/rigor/inference/optimistic_origin.rb +134 -9
- data/lib/rigor/inference/origin_lookup.rb +1 -1
- data/lib/rigor/inference/out_buffer_mutation.rb +72 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +1 -1
- data/lib/rigor/inference/precision_scanner.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +30 -9
- data/lib/rigor/inference/project_patched_methods.rb +65 -13
- data/lib/rigor/inference/project_patched_scanner.rb +120 -25
- data/lib/rigor/inference/project_patched_visibility.rb +39 -3
- data/lib/rigor/inference/project_yielder.rb +11 -17
- data/lib/rigor/inference/rbs_type_translator.rb +68 -15
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/receiver_writer_call.rb +67 -0
- data/lib/rigor/inference/recursion_rebinding.rb +157 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +57 -17
- data/lib/rigor/inference/refined_dispatch/own_method.rb +51 -16
- data/lib/rigor/inference/refined_dispatch.rb +13 -0
- data/lib/rigor/inference/reflective_ivar_write.rb +19 -11
- data/lib/rigor/inference/remover_holder_scan.rb +287 -0
- data/lib/rigor/inference/remover_narrowing.rb +224 -0
- data/lib/rigor/inference/rewrite_mutation.rb +53 -2
- data/lib/rigor/inference/scope_indexer/certainty.rb +0 -1
- data/lib/rigor/inference/scope_indexer/class_cvars_collector.rb +13 -6
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +70 -26
- data/lib/rigor/inference/scope_indexer/derived_param_value.rb +112 -0
- data/lib/rigor/inference/scope_indexer/empty_seed.rb +99 -0
- data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +295 -0
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +136 -9
- data/lib/rigor/inference/scope_indexer.rb +2213 -226
- data/lib/rigor/inference/self_call_ivar_writes.rb +103 -12
- data/lib/rigor/inference/self_preserving_block.rb +87 -0
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +42 -8
- data/lib/rigor/inference/singleton_object_constant.rb +32 -2
- data/lib/rigor/inference/statement_evaluator.rb +3268 -358
- data/lib/rigor/inference/string_mutation.rb +14 -0
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_scanner.rb +40 -17
- data/lib/rigor/inference/toplevel_def_census.rb +67 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/untyped_rejoin.rb +1 -1
- data/lib/rigor/inference/void_tail_summary.rb +29 -9
- data/lib/rigor/language_server/buffer_table.rb +3 -3
- data/lib/rigor/language_server/completion_provider.rb +26 -20
- data/lib/rigor/language_server/config_warning_announcer.rb +28 -0
- data/lib/rigor/language_server/diagnostic_publisher.rb +8 -3
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -2
- data/lib/rigor/language_server/hover_provider.rb +1 -7
- data/lib/rigor/language_server/hover_renderer.rb +6 -8
- data/lib/rigor/language_server/project_context.rb +39 -1
- data/lib/rigor/language_server/publish_batcher.rb +3 -4
- data/lib/rigor/language_server/selection_range_provider.rb +2 -4
- data/lib/rigor/language_server/server.rb +7 -3
- data/lib/rigor/language_server/signature_help_provider.rb +4 -4
- data/lib/rigor/lens/claims/comparison.rb +78 -0
- data/lib/rigor/lens/claims/request.rb +131 -0
- data/lib/rigor/lens/claims/type_reader.rb +216 -0
- data/lib/rigor/lens/claims.rb +208 -0
- data/lib/rigor/lens/contract_reader.rb +5 -0
- data/lib/rigor/lens/document.rb +1 -1
- data/lib/rigor/lens/file_reader.rb +21 -8
- data/lib/rigor/lens/plugins.rb +1 -1
- data/lib/rigor/lens/run.rb +8 -0
- data/lib/rigor/lens.rb +1 -1
- data/lib/rigor/library_probe.rb +68 -0
- data/lib/rigor/mcp/server.rb +73 -2
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/memo_audit.rb +282 -0
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/base.rb +15 -2
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +26 -4
- data/lib/rigor/plugin/loader.rb +25 -8
- data/lib/rigor/plugin/macro/heredoc_template.rb +7 -8
- data/lib/rigor/plugin/macro/trait_registry.rb +6 -9
- data/lib/rigor/plugin/manifest.rb +16 -16
- data/lib/rigor/plugin/registry.rb +16 -5
- data/lib/rigor/plugin/services.rb +2 -3
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -0
- data/lib/rigor/plugin/trust_policy.rb +48 -2
- data/lib/rigor/plugin/type_node_resolver.rb +2 -4
- data/lib/rigor/plugin.rb +6 -8
- data/lib/rigor/plugin_gap_advisory.rb +5 -1
- data/lib/rigor/project_environment.rb +16 -2
- data/lib/rigor/protection/analysis_guard.rb +1 -1
- data/lib/rigor/protection/discovery_seed.rb +44 -5
- data/lib/rigor/protection/mutation_cache.rb +4 -1
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/hkt_directives.rb +6 -10
- data/lib/rigor/rbs_extended/reporter.rb +27 -3
- data/lib/rigor/rbs_extended.rb +2 -3
- data/lib/rigor/reflection/constant_ancestors.rb +81 -22
- data/lib/rigor/reflection/declaration_collectors.rb +55 -0
- data/lib/rigor/reflection/declarations.rb +58 -0
- data/lib/rigor/reflection/project_method.rb +177 -0
- data/lib/rigor/reflection.rb +2 -0
- data/lib/rigor/rooted_glob.rb +32 -1
- data/lib/rigor/run_scoped_slots.rb +38 -0
- data/lib/rigor/runtime/jit.rb +1 -1
- data/lib/rigor/scope/discovery_index.rb +168 -8
- data/lib/rigor/scope/resolution_chain/relevance.rb +14 -1
- data/lib/rigor/scope/resolution_chain.rb +901 -54
- data/lib/rigor/scope.rb +644 -37
- data/lib/rigor/sig_gen/bot_proposal_guard.rb +306 -0
- data/lib/rigor/sig_gen/classification.rb +18 -1
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +588 -66
- data/lib/rigor/sig_gen/generic_header_scan.rb +189 -0
- data/lib/rigor/sig_gen/inline_declarations.rb +2 -2
- data/lib/rigor/sig_gen/layout_index.rb +3 -3
- data/lib/rigor/sig_gen/method_candidate.rb +37 -4
- data/lib/rigor/sig_gen/observation_collector.rb +14 -7
- data/lib/rigor/sig_gen/observed_call.rb +1 -1
- data/lib/rigor/sig_gen/path_mapper.rb +6 -0
- data/lib/rigor/sig_gen/platform_guarded_files.rb +184 -0
- data/lib/rigor/sig_gen/renderer.rb +15 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +62 -2
- data/lib/rigor/sig_gen/type_name_qualification.rb +69 -0
- data/lib/rigor/sig_gen/write_reporter.rb +63 -14
- data/lib/rigor/sig_gen/write_result.rb +23 -12
- data/lib/rigor/sig_gen/writer.rb +238 -37
- data/lib/rigor/sig_gen.rb +1 -0
- data/lib/rigor/source/forwardable_delegators.rb +122 -0
- data/lib/rigor/source/node_children.rb +13 -0
- data/lib/rigor/type/acceptance_router.rb +2 -2
- data/lib/rigor/type/accepts_result.rb +1 -1
- data/lib/rigor/type/app.rb +4 -6
- data/lib/rigor/type/combinator.rb +173 -21
- data/lib/rigor/type/constant.rb +4 -5
- data/lib/rigor/type/hash_shape.rb +21 -40
- data/lib/rigor/type/interface.rb +60 -0
- data/lib/rigor/type/union.rb +1 -1
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/identifier.rb +1 -2
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node/string_literal.rb +1 -2
- data/lib/rigor/type_node/symbol_literal.rb +1 -2
- data/lib/rigor/type_node/union.rb +3 -6
- data/lib/rigor/type_of_memo/serving.rb +99 -0
- data/lib/rigor/type_of_memo/stats.rb +43 -0
- data/lib/rigor/type_of_memo.rb +337 -0
- data/lib/rigor/typing_state.rb +1094 -0
- data/lib/rigor/value_semantics.rb +1 -10
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +2 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +2 -3
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +38 -36
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +6 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -5
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +2 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +3 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +115 -36
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +3 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +25 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +16 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +4 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +4 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +2 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +3 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +2 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +21 -31
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +10 -16
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +132 -33
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +20 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +7 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +54 -17
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +19 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +3 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +11 -14
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/symbolize_keys.rb +102 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +30 -9
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +55 -13
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_collector.rb +15 -21
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +1 -6
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +3 -3
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +1 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +6 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +5 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +1 -1
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/params_shape.rb +2 -3
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -8
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +10 -18
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +0 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +0 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +8 -7
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +0 -2
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +6 -7
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +12 -2
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +2 -4
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +2 -5
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +8 -2
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +6 -6
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +2 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +3 -8
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +2 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -8
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +200 -4
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +4 -11
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +4 -3
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +5 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +2 -2
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +3 -4
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +6 -8
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +3 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +6 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +210 -3
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +146 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +52 -34
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +97 -24
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_collector.rb +16 -16
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +4 -8
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +4 -4
- data/sig/rigor/analysis/baseline.rbs +0 -3
- data/sig/rigor/analysis/check_rules/rule_walk.rbs +6 -0
- data/sig/rigor/analysis/fact_store.rbs +2 -2
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- data/sig/rigor/cache/descriptor.rbs +14 -0
- data/sig/rigor/cli/diff_command.rbs +1 -1
- data/sig/rigor/cli/explain_command.rbs +1 -1
- data/sig/rigor/effects/registry.rbs +2 -2
- data/sig/rigor/environment.rbs +4 -1
- data/sig/rigor/inference.rbs +4 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +53 -18
- data/sig/rigor/plugin/effect_attribution.rbs +3 -3
- data/sig/rigor/plugin/effect_edge.rbs +1 -1
- data/sig/rigor/plugin/effect_entry_points.rbs +3 -3
- data/sig/rigor/plugin/interfaces.rbs +51 -0
- data/sig/rigor/plugin/io_boundary.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +9 -9
- data/sig/rigor/plugin/node_context.rbs +21 -0
- data/sig/rigor/plugin/protocol_contract.rbs +3 -7
- data/sig/rigor/reflection.rbs +37 -0
- data/sig/rigor/scope.rbs +43 -4
- data/sig/rigor/trinary.rbs +1 -0
- data/sig/rigor/type.rbs +9 -3
- data/sig/rigor.rbs +3 -2
- data/skills/rigor-ask/SKILL.md +1 -0
- data/skills/rigor-plugin-author/SKILL.md +4 -4
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +5 -5
- data/skills/rigor-plugin-review/SKILL.md +3 -3
- data/skills/rigor-project-init/references/01-detect.md +1 -0
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +17 -2
- data/skills/rigor-project-init/references/06-agent-contract.md +4 -4
- data/skills/rigor-rbs-contract/SKILL.md +147 -0
- data/skills/rigor-rbs-contract/references/01-finding-candidates.md +212 -0
- data/skills/rigor-rbs-contract/references/02-contract-rules.md +157 -0
- data/skills/rigor-rbs-contract/references/03-target-own-code.md +90 -0
- data/skills/rigor-rbs-contract/references/04-target-gem-rbs-collection.md +210 -0
- data/skills/rigor-rbs-contract/references/05-declaration-mutants.md +182 -0
- data/skills/rigor-rbs-setup/SKILL.md +3 -1
- data/skills/rigor-type-oracle/SKILL.md +26 -1
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +4 -3
- metadata +82 -3
|
@@ -20,7 +20,6 @@ module Rigor
|
|
|
20
20
|
#
|
|
21
21
|
# Centralising both here keeps the receiver-shape and constant-unwrap knowledge in one place: if
|
|
22
22
|
# `Type::Singleton` or `Type::Constant` ever changes shape, there is a single edit rather than nine.
|
|
23
|
-
# The per-tier fold bodies stay where they are — only the shared gate moves.
|
|
24
23
|
module SingletonFolding
|
|
25
24
|
module_function
|
|
26
25
|
|
|
@@ -20,8 +20,9 @@ module Rigor
|
|
|
20
20
|
# The rule is exact rather than heuristic — the receiver must be a `Singleton[C]` whose `C` the project
|
|
21
21
|
# pre-pass recorded as including `Singleton` — so a class that does not include the mixin is untouched,
|
|
22
22
|
# and a project that defines its own `Singleton` module is the one case that would misfire. Guarded by
|
|
23
|
-
# {
|
|
24
|
-
#
|
|
23
|
+
# {own_singleton_include?}: when the included name resolves to a project-declared class or module (a
|
|
24
|
+
# top-level `Singleton`, or `M::Singleton` inside `module M`), the tier declines, because then the name
|
|
25
|
+
# means something else entirely.
|
|
25
26
|
module SingletonMixinDispatch
|
|
26
27
|
MIXIN_NAMES = Ractor.make_shareable(Set["Singleton", "::Singleton"])
|
|
27
28
|
private_constant :MIXIN_NAMES
|
|
@@ -31,30 +32,62 @@ module Rigor
|
|
|
31
32
|
|
|
32
33
|
module_function
|
|
33
34
|
|
|
34
|
-
# @return `
|
|
35
|
+
# @return the instance type of `C` for `C.instance`, or nil to decline.
|
|
35
36
|
def try_dispatch(context)
|
|
36
|
-
return nil unless context.method_name == SELECTOR
|
|
37
|
-
return nil unless context.args.empty?
|
|
38
|
-
|
|
39
37
|
receiver = context.receiver
|
|
40
|
-
return nil unless receiver.
|
|
41
|
-
|
|
42
|
-
scope = context.scope
|
|
43
|
-
return nil if scope.nil?
|
|
44
|
-
return nil unless includes_singleton_mixin?(scope, receiver.class_name)
|
|
45
|
-
return nil if project_singleton_shadow?(scope)
|
|
38
|
+
return nil unless answers?(context.scope, receiver, context.method_name, context.args.empty?)
|
|
46
39
|
|
|
47
40
|
Type::Combinator.nominal_of(receiver.class_name)
|
|
48
41
|
end
|
|
49
42
|
|
|
43
|
+
# Issue #2438 — the one predicate behind {try_dispatch} and `CheckRules#undefined_method_diagnostic`, so the
|
|
44
|
+
# typer and the `call.undefined-method` rule cannot disagree about `C.instance`: a call this tier types is
|
|
45
|
+
# never reported as undefined, whatever a project sidecar of `C` lists.
|
|
46
|
+
def answers?(scope, receiver, method_name, no_arguments)
|
|
47
|
+
return false unless method_name == SELECTOR && no_arguments
|
|
48
|
+
return false unless receiver.is_a?(Type::Singleton)
|
|
49
|
+
return false if scope.nil?
|
|
50
|
+
|
|
51
|
+
includes_singleton_mixin?(scope, receiver.class_name)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# True when `class_name`'s instance ancestry carries the stdlib `Singleton` as an `include` written in the
|
|
55
|
+
# class itself or in a project class up its superclass chain (Ruby's `Singleton.included` also installs an
|
|
56
|
+
# `inherited` hook, so `class D < C` answers `instance` with its own instance). Read off
|
|
57
|
+
# `Scope::ResolutionChain` (the `:constants` flavor, so an empty project `module Singleton` is a project
|
|
58
|
+
# entry), where the stdlib module is an external entry. Issue #2438 — what is not the mixin:
|
|
59
|
+
#
|
|
60
|
+
# - `prepend Singleton`, which runs `prepend_features` instead of the `included` hook and so defines no
|
|
61
|
+
# `instance`; a prepended entry sits ahead of its owner on the chain;
|
|
62
|
+
# - an `include Singleton` in a MODULE the class includes: `Singleton.included` raises `TypeError` for a
|
|
63
|
+
# module, so that code never runs;
|
|
64
|
+
# - a top-level project `Singleton`, which both `Singleton` and `::Singleton` name.
|
|
65
|
+
#
|
|
66
|
+
# A NESTED project `N::Singleton` the name resolved to is read as the stdlib mixin: the discovery tables
|
|
67
|
+
# drop the leading `::` of a mixin argument, so `include ::Singleton` and `include Singleton` inside
|
|
68
|
+
# `module N` record the same name, and the stdlib reading is the one that types the rooted spelling and
|
|
69
|
+
# never reports a correct call.
|
|
50
70
|
def includes_singleton_mixin?(scope, class_name)
|
|
51
|
-
|
|
71
|
+
chain = Scope::ResolutionChain.for(scope, class_name.to_s.delete_prefix("::"), :instance, :constants)
|
|
72
|
+
chain.record(scope)
|
|
73
|
+
classes = chain.level_classes.compact
|
|
74
|
+
chain.entries.each_with_index.any? { |entry, index| singleton_include?(chain, classes, entry, index) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def singleton_include?(chain, classes, entry, index)
|
|
78
|
+
if entry.external?
|
|
79
|
+
!entry.superclass_edge && MIXIN_NAMES.include?(entry.raw.to_s) && classes.include?(entry.owner) &&
|
|
80
|
+
index > chain.index_of(entry.owner)
|
|
81
|
+
else
|
|
82
|
+
entry.name.end_with?("::Singleton") && included_by_level_class?(chain, index)
|
|
83
|
+
end
|
|
52
84
|
end
|
|
53
85
|
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
86
|
+
# The entry sits after its level's class, so it was included into that level rather than prepended.
|
|
87
|
+
def included_by_level_class?(chain, index)
|
|
88
|
+
level = chain.level_starts.rindex { |start| start <= index }
|
|
89
|
+
klass = level && chain.level_classes[level]
|
|
90
|
+
!klass.nil? && index > chain.index_of(klass)
|
|
58
91
|
end
|
|
59
92
|
end
|
|
60
93
|
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbs"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Inference
|
|
7
|
+
module MethodDispatcher
|
|
8
|
+
# Issue #2828 — how overload selection reads a parameter spelled `singleton(T)` over a method-level type
|
|
9
|
+
# variable `T`. RBS parses it as a class singleton whose name is the bare, relative `T`, and the
|
|
10
|
+
# translator reads that as a class named `T`: an unloadable class whose singleton refuses every class object
|
|
11
|
+
# the analyzer process has loaded (`Acceptance` rules a loaded class out of an unloadable target's
|
|
12
|
+
# subtypes). With `Resolv` loaded, `Resolv::DNS#getresources: [T < Resource] (dns_name, singleton(T)) ->
|
|
13
|
+
# Array[T] | ...` then lost to the base overload.
|
|
14
|
+
#
|
|
15
|
+
# Selection instead reads the parameter as "a class object" the variable admits: `singleton(X)` for a
|
|
16
|
+
# class upper bound `X`, and `Module` otherwise, which takes any class or module object and refuses an
|
|
17
|
+
# instance. Only names the overload declares in its own `type_params` are read this way; any other
|
|
18
|
+
# unresolved `singleton(X)` keeps the translator's reading.
|
|
19
|
+
#
|
|
20
|
+
# {.selecting} hands the selector the overloads rewritten where a parameter needs it and maps the selected
|
|
21
|
+
# rewrites back, so the return translation and the argument binding (`RbsDispatch#singleton_param_binding`)
|
|
22
|
+
# still read the declared `singleton(T)`.
|
|
23
|
+
module SingletonTypeParams
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
# Yields the overloads to select among and answers the block's selection, with each rewrite mapped back to
|
|
27
|
+
# its declaration. Nearly every method needs no rewrite, and then `declared` is yielded as is.
|
|
28
|
+
def selecting(declared)
|
|
29
|
+
return yield(declared) unless declared.any? { |method_type| rewrites?(method_type) }
|
|
30
|
+
|
|
31
|
+
originals = {}.compare_by_identity
|
|
32
|
+
rewritten = declared.map do |method_type|
|
|
33
|
+
next method_type unless rewrites?(method_type)
|
|
34
|
+
|
|
35
|
+
rewrite = rewrite(method_type)
|
|
36
|
+
originals[rewrite] = method_type
|
|
37
|
+
rewrite
|
|
38
|
+
end
|
|
39
|
+
yield(rewritten).map { |method_type| originals.fetch(method_type, method_type) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def rewrites?(method_type)
|
|
43
|
+
params = method_type.respond_to?(:type_params) ? method_type.type_params : nil
|
|
44
|
+
return false if params.nil? || params.empty?
|
|
45
|
+
|
|
46
|
+
fun = method_type.type
|
|
47
|
+
return false unless fun.respond_to?(:required_positionals)
|
|
48
|
+
|
|
49
|
+
any_variable_singleton?(fun.required_positionals, params) ||
|
|
50
|
+
any_variable_singleton?(fun.optional_positionals, params) ||
|
|
51
|
+
any_variable_singleton?(fun.trailing_positionals, params)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def any_variable_singleton?(list, type_params)
|
|
55
|
+
list.any? { |param| variable_singleton?(param.type, type_params) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def variable_singleton?(type, type_params)
|
|
59
|
+
return false unless type.is_a?(RBS::Types::ClassSingleton)
|
|
60
|
+
|
|
61
|
+
name = type.name
|
|
62
|
+
return false if name.absolute? || !name.namespace.empty?
|
|
63
|
+
|
|
64
|
+
type_params.any? { |type_param| type_param.name == name.name }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# One parameter of `method_type` as selection reads it: `call.argument-type-mismatch` checks a call the
|
|
68
|
+
# same way, and otherwise declines every overload with a `singleton(T)` parameter as naming a class nothing
|
|
69
|
+
# defines.
|
|
70
|
+
def selection_param(param, method_type)
|
|
71
|
+
type_params = method_type.type_params
|
|
72
|
+
return param unless variable_singleton?(param.type, type_params)
|
|
73
|
+
|
|
74
|
+
param.map_type { |type| class_object_type(type.name.name, type_params) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def rewrite(method_type)
|
|
78
|
+
type_params = method_type.type_params
|
|
79
|
+
fun = method_type.type.map_type do |type|
|
|
80
|
+
variable_singleton?(type, type_params) ? class_object_type(type.name.name, type_params) : type
|
|
81
|
+
end
|
|
82
|
+
RBS::MethodType.new(type_params: type_params, type: fun, block: method_type.block,
|
|
83
|
+
location: method_type.location)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Built per rewrite rather than held in a constant: an RBS type is not `Ractor.shareable?` (#1064), and a
|
|
87
|
+
# rewrite happens only for the few overloads that spell `singleton(T)`.
|
|
88
|
+
def module_type
|
|
89
|
+
RBS::Types::ClassInstance.new(
|
|
90
|
+
name: RBS::TypeName.new(name: :Module, namespace: RBS::Namespace.root), args: [], location: nil
|
|
91
|
+
)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def class_object_type(name, type_params)
|
|
95
|
+
type_param = type_params.find { |tp| tp.name == name }
|
|
96
|
+
bound = type_param.upper_bound
|
|
97
|
+
return module_type unless bound.is_a?(RBS::Types::ClassInstance)
|
|
98
|
+
|
|
99
|
+
RBS::Types::ClassSingleton.new(name: bound.name, location: nil)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -14,8 +14,8 @@ module Rigor
|
|
|
14
14
|
#
|
|
15
15
|
# A `Struct` instance is mutable (`s.x = v`, `s[:x] = v`, escape), so a member map bound to a
|
|
16
16
|
# variable can be invalidated by a later write. A member read folds off a **fresh** instance (the
|
|
17
|
-
# transient receiver of a `.new(...).x`
|
|
18
|
-
#
|
|
17
|
+
# transient receiver of a `.new(...).x` chain, unmutatable between materialisation and the read —
|
|
18
|
+
# slices 1+2), off a **fold-safe stored local** the {Inference::StructFoldSafety} scan
|
|
19
19
|
# proved is never mutated / aliased / escaped (slice 3), or off a **setter-mutated fold-safe local**
|
|
20
20
|
# whose bindings {#apply_setter_writeback} keeps current (slice 4). Any other stored receiver degrades
|
|
21
21
|
# to `Dynamic[top]` rather than fold a possibly-stale value.
|
|
@@ -255,8 +255,8 @@ module Rigor
|
|
|
255
255
|
end
|
|
256
256
|
|
|
257
257
|
# A member read is foldable when the receiver is either FRESH (the transient result of a
|
|
258
|
-
# `.new(...)
|
|
259
|
-
#
|
|
258
|
+
# `.new(...)` chain, which cannot have been mutated between materialisation and this read) or a
|
|
259
|
+
# FOLD-SAFE stored local (ADR-48 slice 3 — `StructFoldSafety` proved the binding is
|
|
260
260
|
# never mutated / aliased / escaped in its scope).
|
|
261
261
|
def foldable_receiver?(context)
|
|
262
262
|
fresh_receiver?(context) || fold_safe_local_receiver?(context) ||
|
|
@@ -308,7 +308,7 @@ module Rigor
|
|
|
308
308
|
end
|
|
309
309
|
|
|
310
310
|
# A fresh receiver is the result of a chained call that MATERIALISED the struct — `Point.new(1, 2).x`,
|
|
311
|
-
# `Point[1, 2].x
|
|
311
|
+
# `Point[1, 2].x`. Not merely a chained call: slices 1-2 read "chained" as
|
|
312
312
|
# "cannot have been mutated between materialisation and the read", and a method that hands back its
|
|
313
313
|
# own receiver falsifies that (issue #595):
|
|
314
314
|
#
|
|
@@ -31,12 +31,10 @@ module Rigor
|
|
|
31
31
|
# nodes; the bound exists so a pathological body cannot turn a per-call-site gate into a walk.
|
|
32
32
|
FACTORY_BODY_SCAN_BUDGET = 200
|
|
33
33
|
|
|
34
|
-
# Issue #595 / #525 — the ONE materialisation test
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# one answer. A `.with` call is never a materialisation: the composed `x.dup_self.with(indent: 9)`
|
|
39
|
-
# shape once slipped through as one, and `Struct#with` no longer exists to fold (#1335).
|
|
34
|
+
# Issue #595 / #525 — the ONE materialisation test, shared by {StructFolding#fresh_receiver?} and
|
|
35
|
+
# `ExpressionTyper`'s `:self`-grant arm so the two gates cannot fork. A `.with` call is never a
|
|
36
|
+
# materialisation: the composed `x.dup_self.with(indent: 9)` shape once slipped through as one, and
|
|
37
|
+
# `Struct#with` no longer exists (#1335).
|
|
40
38
|
#
|
|
41
39
|
# @param node — the receiver EXPRESSION.
|
|
42
40
|
# @param scope — the scope the factory and ancestor lookups resolve against.
|
|
@@ -55,7 +55,7 @@ module Rigor
|
|
|
55
55
|
|
|
56
56
|
# A form long enough to suggest generated or accumulated data rather than a literal a reader wrote;
|
|
57
57
|
# past it the folded `Constant[String]` stops being useful in a diagnostic and only costs memory.
|
|
58
|
-
#
|
|
58
|
+
# Counts pairs where `ShapeDispatch`'s `tuple_join` fold caps bytes, for the same reason.
|
|
59
59
|
FORM_PAIR_LIMIT = 64
|
|
60
60
|
private_constant :FORM_PAIR_LIMIT
|
|
61
61
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "../reflection"
|
|
4
|
+
require_relative "../typing_state"
|
|
4
5
|
require_relative "../type"
|
|
5
6
|
require_relative "../flow_contribution"
|
|
6
7
|
require_relative "../flow_contribution/merger"
|
|
@@ -18,6 +19,7 @@ require_relative "method_dispatcher/shape_dispatch"
|
|
|
18
19
|
require_relative "method_dispatcher/data_folding"
|
|
19
20
|
require_relative "method_dispatcher/struct_folding"
|
|
20
21
|
require_relative "method_dispatcher/rbs_dispatch"
|
|
22
|
+
require_relative "method_dispatcher/declared_constructor"
|
|
21
23
|
require_relative "method_dispatcher/iterator_dispatch"
|
|
22
24
|
require_relative "method_dispatcher/arithmetic_sequence_elements"
|
|
23
25
|
require_relative "method_dispatcher/reduce_folding"
|
|
@@ -41,6 +43,7 @@ require_relative "method_dispatcher/universal_object_dispatch"
|
|
|
41
43
|
require_relative "method_dispatcher/singleton_mixin_dispatch"
|
|
42
44
|
require_relative "method_dispatcher/method_folding"
|
|
43
45
|
require_relative "method_dispatcher/optional_count"
|
|
46
|
+
require_relative "../run_scoped_slots"
|
|
44
47
|
|
|
45
48
|
module Rigor
|
|
46
49
|
module Inference
|
|
@@ -194,7 +197,7 @@ module Rigor
|
|
|
194
197
|
rbs_result = RbsDispatch.try_dispatch(context)
|
|
195
198
|
if rbs_result
|
|
196
199
|
record_boundary_cross_if_applicable(receiver_type, method_name, rbs_result, environment)
|
|
197
|
-
if
|
|
200
|
+
if Type::Combinator.untyped?(rbs_result)
|
|
198
201
|
scope&.record_dynamic_origin(call_node, DynamicOrigin::EXPLICIT_UNTYPED)
|
|
199
202
|
end
|
|
200
203
|
return rbs_result
|
|
@@ -204,8 +207,8 @@ module Rigor
|
|
|
204
207
|
# user-authored RBS overrides substrate synthesis) and ABOVE the dependency-source
|
|
205
208
|
# inference tier so a plugin's declared emit table beats the generic gem-source fallback
|
|
206
209
|
# for the same class. Slice 6a-TierB (origin_module dispatch) lands precise return types
|
|
207
|
-
# for Tier B emissions; Tier C emissions
|
|
208
|
-
#
|
|
210
|
+
# for Tier B emissions; Tier C emissions return their manifest `return_type` when the environment
|
|
211
|
+
# names that class (slice 6b), and `Dynamic[T]` otherwise.
|
|
209
212
|
synthetic_result = try_synthetic_method(
|
|
210
213
|
receiver_type, method_name, arg_types, block_type, environment
|
|
211
214
|
)
|
|
@@ -825,7 +828,7 @@ module Rigor
|
|
|
825
828
|
end
|
|
826
829
|
|
|
827
830
|
def rbs_result_untyped?(rbs_result)
|
|
828
|
-
|
|
831
|
+
Type::Combinator.untyped?(rbs_result)
|
|
829
832
|
end
|
|
830
833
|
|
|
831
834
|
def rbs_display_for(rbs_result)
|
|
@@ -915,8 +918,7 @@ module Rigor
|
|
|
915
918
|
result || EMPTY_CONTRIBUTIONS
|
|
916
919
|
end
|
|
917
920
|
|
|
918
|
-
# Runs the precision tiers
|
|
919
|
-
# order and returns the first non-nil answer. Each tier owns its own receiver/argument
|
|
921
|
+
# Runs the precision tiers in order and returns the first non-nil answer. Each tier owns its own receiver/argument
|
|
920
922
|
# shape checks; a tier that does not recognise the receiver returns nil so the next tier
|
|
921
923
|
# can try. The RBS tier sits below this chain and is invoked by the outer `dispatch`
|
|
922
924
|
# method.
|
|
@@ -925,7 +927,7 @@ module Rigor
|
|
|
925
927
|
# (`try_dispatch(CallContext) -> Type?`). Order is significant: ConstantFolding's
|
|
926
928
|
# exact-value folds win first, the stdlib singleton folders sit in the middle (each
|
|
927
929
|
# gates on a distinct `Singleton` receiver, so their relative order is immaterial), and
|
|
928
|
-
# BlockFolding runs
|
|
930
|
+
# BlockFolding runs near the end because its rules only apply to block-taking calls — the cheaper
|
|
929
931
|
# arity folds above it filter the common cases first. Adding a precise tier is a one-line
|
|
930
932
|
# append here rather than another link in a hand-written `||` ladder.
|
|
931
933
|
PRECISE_TIERS_HEAD = Ractor.make_shareable([
|
|
@@ -1031,6 +1033,7 @@ module Rigor
|
|
|
1031
1033
|
fallback_receiver = user_class_fallback_receiver(receiver_type, environment)
|
|
1032
1034
|
return nil if fallback_receiver.nil?
|
|
1033
1035
|
return nil if declared_by_external_ancestor?(receiver_type, environment, context)
|
|
1036
|
+
return nil if project_singleton_definer?(receiver_type, context)
|
|
1034
1037
|
|
|
1035
1038
|
# Preserve the ORIGINAL receiver type as the `self` substitution so `Kernel#dup: () ->
|
|
1036
1039
|
# self` and other `self`-returning methods route through Object's RBS while still
|
|
@@ -1069,27 +1072,114 @@ module Rigor
|
|
|
1069
1072
|
scope = context.scope
|
|
1070
1073
|
return false if scope.nil?
|
|
1071
1074
|
|
|
1075
|
+
class_name = receiver_type.class_name
|
|
1076
|
+
method_name = context.method_name
|
|
1077
|
+
if MemoAudit.enabled? && MemoAudit.suspended?
|
|
1078
|
+
return external_ancestor_declares?(class_name, method_name, scope,
|
|
1079
|
+
environment)
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1072
1082
|
memo = external_ancestor_memo(scope, environment)
|
|
1073
|
-
key = [
|
|
1074
|
-
|
|
1083
|
+
key = [class_name, method_name]
|
|
1084
|
+
if memo.key?(key)
|
|
1085
|
+
return MemoAudit.check("user class fallback external ancestor", memo[key], class_name, method_name) do
|
|
1086
|
+
external_ancestor_declares?(class_name, method_name, scope, environment)
|
|
1087
|
+
end
|
|
1088
|
+
end
|
|
1089
|
+
|
|
1090
|
+
memo[key] = MemoAudit.key_audit("user class fallback external ancestor") do
|
|
1091
|
+
external_ancestor_declares?(class_name, method_name, scope, environment)
|
|
1092
|
+
end
|
|
1093
|
+
end
|
|
1094
|
+
|
|
1095
|
+
def external_ancestor_declares?(class_name, method_name, scope, environment)
|
|
1096
|
+
!ExternalAncestorResolution.resolve(class_name, method_name, :instance,
|
|
1097
|
+
scope: scope, environment: environment, record_dependencies: false).nil?
|
|
1098
|
+
end
|
|
1099
|
+
|
|
1100
|
+
# Issue #2284 — a class object whose singleton chain holds a project definer of the name (its own `def
|
|
1101
|
+
# self.name`, one a project superclass wrote, an `extend`ed module's `def name`) answers from that definer,
|
|
1102
|
+
# not from `Module#name` / `Class#…` on the `Singleton[Object]` fallback: Ruby's singleton ancestry puts
|
|
1103
|
+
# every project entry ahead of `Class`. The fallback declines so the typer's singleton-body inference
|
|
1104
|
+
# answers the definer's return, or `Dynamic` where the slot is contested and the def may not be the one
|
|
1105
|
+
# that runs.
|
|
1106
|
+
#
|
|
1107
|
+
# The chain walk files the class edge of every entry it passes, so it runs only for a name some project file
|
|
1108
|
+
# defines at all ({BlockCallTiming.project_defines_anywhere?}, which files the `defines:<name>` edge either way,
|
|
1109
|
+
# #1459). Without it every class-body `private` / `attr_reader` call on a project class would depend on its
|
|
1110
|
+
# whole ancestry. The by-name answer is memoised per discovery index; the edge is filed on every call.
|
|
1111
|
+
def project_singleton_definer?(receiver_type, context)
|
|
1112
|
+
return false unless receiver_type.is_a?(Type::Singleton)
|
|
1113
|
+
|
|
1114
|
+
scope = context.scope
|
|
1115
|
+
return false if scope.nil?
|
|
1116
|
+
return false unless project_defines_name?(scope, context.method_name)
|
|
1117
|
+
|
|
1118
|
+
!scope.singleton_def_through_ancestors(receiver_type.class_name, context.method_name).last.nil?
|
|
1119
|
+
end
|
|
1075
1120
|
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1121
|
+
def project_defines_name?(scope, method_name)
|
|
1122
|
+
if MemoAudit.enabled? && MemoAudit.suspended?
|
|
1123
|
+
return BlockCallTiming.project_defines_anywhere?(method_name,
|
|
1124
|
+
scope)
|
|
1125
|
+
end
|
|
1126
|
+
|
|
1127
|
+
memo = defines_name_memo(scope)
|
|
1128
|
+
if memo.key?(method_name)
|
|
1129
|
+
Analysis::DependencyRecorder.read_missing(:defines, method_name) if Analysis::DependencyRecorder.active?
|
|
1130
|
+
return MemoAudit.check("user class fallback defines name", memo[method_name], method_name) do
|
|
1131
|
+
BlockCallTiming.project_defines_anywhere?(method_name, scope)
|
|
1132
|
+
end
|
|
1133
|
+
end
|
|
1134
|
+
|
|
1135
|
+
memo[method_name] = MemoAudit.key_audit("user class fallback defines name") do
|
|
1136
|
+
BlockCallTiming.project_defines_anywhere?(method_name, scope)
|
|
1137
|
+
end
|
|
1138
|
+
end
|
|
1139
|
+
|
|
1140
|
+
# ADR-129 WD1 — a run-scoped Memo: one slot keyed on the identity of the discovery index and the environment,
|
|
1141
|
+
# the only inputs the name table's answers read.
|
|
1142
|
+
DEFINES_NAME_MEMO = TypingState.memo(
|
|
1143
|
+
:user_class_fallback_defines_name,
|
|
1144
|
+
run_scoped: true, audit: "user class fallback defines name",
|
|
1145
|
+
reason: "one [discovery, environment, names] slot keyed on the identities of the discovery " \
|
|
1146
|
+
"index and the environment; each name's answer reads only them"
|
|
1147
|
+
)
|
|
1148
|
+
private_constant :DEFINES_NAME_MEMO
|
|
1149
|
+
|
|
1150
|
+
# One slot per discovery index and environment, as {#external_ancestor_memo} keeps its own: the answer reads
|
|
1151
|
+
# only the frozen discovery tables and the environment's `pre_eval:` patches.
|
|
1152
|
+
def defines_name_memo(scope)
|
|
1153
|
+
discovery = scope.discovery
|
|
1154
|
+
environment = scope.environment
|
|
1155
|
+
state = TypingState.current
|
|
1156
|
+
slot = state[DEFINES_NAME_MEMO]
|
|
1157
|
+
unless slot && slot[0].equal?(discovery) && slot[1].equal?(environment)
|
|
1158
|
+
slot = [discovery, environment, {}]
|
|
1159
|
+
state[DEFINES_NAME_MEMO] = slot
|
|
1160
|
+
end
|
|
1161
|
+
slot[2]
|
|
1079
1162
|
end
|
|
1080
1163
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1164
|
+
# ADR-129 WD1 — a run-scoped Memo, keyed as {DEFINES_NAME_MEMO} is.
|
|
1165
|
+
EXTERNAL_ANCESTOR_MEMO = TypingState.memo(
|
|
1166
|
+
:user_class_fallback_external_ancestor,
|
|
1167
|
+
run_scoped: true, audit: "user class fallback external ancestor",
|
|
1168
|
+
reason: "one [discovery, environment, answers] slot keyed on the identities of the " \
|
|
1169
|
+
"discovery index and the RBS environment, the only inputs the walk reads"
|
|
1170
|
+
)
|
|
1171
|
+
private_constant :EXTERNAL_ANCESTOR_MEMO
|
|
1083
1172
|
|
|
1084
1173
|
# One slot per discovery index and environment, as `RbsDispatch#ancestor_memo_slot` keeps its own: the answer
|
|
1085
1174
|
# reads only the frozen discovery tables and the RBS environment, and its walk is withheld from dependency
|
|
1086
1175
|
# recording, so it may be served again for the same pair.
|
|
1087
1176
|
def external_ancestor_memo(scope, environment)
|
|
1088
1177
|
discovery = scope.discovery
|
|
1089
|
-
|
|
1178
|
+
state = TypingState.current
|
|
1179
|
+
slot = state[EXTERNAL_ANCESTOR_MEMO]
|
|
1090
1180
|
unless slot && slot[0].equal?(discovery) && slot[1].equal?(environment)
|
|
1091
1181
|
slot = [discovery, environment, {}]
|
|
1092
|
-
|
|
1182
|
+
state[EXTERNAL_ANCESTOR_MEMO] = slot
|
|
1093
1183
|
end
|
|
1094
1184
|
slot[2]
|
|
1095
1185
|
end
|
|
@@ -1138,12 +1228,14 @@ module Rigor
|
|
|
1138
1228
|
#
|
|
1139
1229
|
# `RbsDispatch` already distributes over a `Union` (and erases a `Difference` to its base, #533),
|
|
1140
1230
|
# but it does so INSIDE one tier, so a member that needs a LOWER tier — a user class with no RBS,
|
|
1141
|
-
# a discovered `def`, an opt-in gem — makes the whole union decline. That
|
|
1142
|
-
# rigor-actionpack
|
|
1143
|
-
#
|
|
1144
|
-
# `#to_s` read opaque on every Rails app. Measured by toggling this file alone: the
|
|
1145
|
-
# census
|
|
1146
|
-
# diagnostics on both arms across eight survey targets.
|
|
1231
|
+
# a discovered `def`, an opt-in gem — makes the whole union decline. That was the corpus shape before
|
|
1232
|
+
# #2430: rigor-actionpack typed `params[:k]` as the bare `ActionController::Parameters | nil` union, the
|
|
1233
|
+
# `Parameters` arm resolved only through the user-class fallback, and so `params[:k].present?` / `#==`
|
|
1234
|
+
# / `#blank?` / `#to_s` read opaque on every Rails app. Measured by toggling this file alone: the
|
|
1235
|
+
# named-pair census drained 137 sites on redmine and 56 on mastodon, and `rigor check` reported the
|
|
1236
|
+
# same diagnostics on both arms across eight survey targets. The plugin now answers a `Dynamic`
|
|
1237
|
+
# carrier, which this projection does not reach, so those off-chain calls read `Dynamic[top]` until
|
|
1238
|
+
# the carrier is projected here too (#2448).
|
|
1147
1239
|
#
|
|
1148
1240
|
# **Why the bottom and not next to `RbsDispatch`.** Sitting here, the tier can only ever replace a
|
|
1149
1241
|
# `Dynamic[top]` the typer was about to produce — the same ADR-5 argument {UniversalObjectDispatch}
|
|
@@ -1314,7 +1406,13 @@ module Rigor
|
|
|
1314
1406
|
class_new_lift = class_new_lift(receiver_type.class_name, arg_types, context)
|
|
1315
1407
|
return class_new_lift if class_new_lift
|
|
1316
1408
|
|
|
1317
|
-
|
|
1409
|
+
declared_or_nominal(receiver_type.class_name, context)
|
|
1410
|
+
end
|
|
1411
|
+
|
|
1412
|
+
# Issue #2884 — the `meta_new` tail: a declared `def self.new` ({DeclaredConstructor}), else `Nominal[X]`.
|
|
1413
|
+
def declared_or_nominal(class_name, context)
|
|
1414
|
+
declared = context && DeclaredConstructor.try_dispatch(class_name, context)
|
|
1415
|
+
declared || Type::Combinator.nominal_of(class_name)
|
|
1318
1416
|
end
|
|
1319
1417
|
|
|
1320
1418
|
# `Struct.new(:a, :b)` synthesises an anonymous Struct *subclass* (a class object), not a
|
|
@@ -1346,8 +1444,8 @@ module Rigor
|
|
|
1346
1444
|
# class is representable as the parent's singleton type — its singleton-method surface is
|
|
1347
1445
|
# the parent's (plus whatever the block defines, which we do not statically track here),
|
|
1348
1446
|
# so `Singleton[Parent]` lets downstream `klass.some_class_method` resolve. No parent →
|
|
1349
|
-
# `singleton(Object)
|
|
1350
|
-
# back to `Nominal[Class]` via the surrounding `meta_new` tail.
|
|
1447
|
+
# `singleton(Object)` (or the block's anonymous class, #319 below). Anything else (dynamic parent, more
|
|
1448
|
+
# than one positional, …) falls back to `Nominal[Class]` via the surrounding `meta_new` tail.
|
|
1351
1449
|
# #319 — a `Class.new do ... end` with no parent is NOT `Object`: the block body is a class body, so the
|
|
1352
1450
|
# class owns whatever that body defines. Answering `Singleton[Object]` handed the call site `Object`'s
|
|
1353
1451
|
# zero-arity `new` and `Object`'s method surface, so an `initialize(bucket)` written right there produced
|