rigortype 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +132 -14
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +19 -1
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +525 -13
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +95 -6
- data/docs/manual/03-configuration.md +18 -0
- data/docs/manual/04-diagnostics.md +15 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/10-mcp-server.md +3 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +46 -8
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +261 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +138 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +3 -3
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
- data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +718 -79
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +15 -1
- data/lib/rigor/analysis/incremental.rb +42 -0
- data/lib/rigor/analysis/incremental_session.rb +117 -26
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +3 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +131 -1
- data/lib/rigor/analysis/run_cache_key.rb +21 -12
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +340 -33
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
- data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
- data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +407 -51
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +62 -20
- data/lib/rigor/bleeding_edge.rb +10 -24
- data/lib/rigor/builtins/hkt_builtins.rb +3 -2
- data/lib/rigor/builtins/imported_refinements.rb +159 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +21 -13
- data/lib/rigor/builtins/static_return_refinements.rb +7 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +63 -20
- data/lib/rigor/cache/engine_source.rb +33 -5
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +72 -6
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +112 -14
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +76 -32
- data/lib/rigor/ci_detector.rb +1 -0
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +4 -4
- data/lib/rigor/cli/docs_command.rb +6 -6
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +4 -4
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +1 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +212 -31
- data/lib/rigor/cli/skill_command.rb +2 -2
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +35 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +29 -11
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +89 -9
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +25 -9
- data/lib/rigor/configuration.rb +109 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +12 -5
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +15 -10
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +11 -4
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +9 -9
- data/lib/rigor/effects/envelope_index.rb +20 -8
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +5 -7
- data/lib/rigor/effects/identity.rb +20 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +22 -1
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +47 -37
- data/lib/rigor/effects/propagator.rb +297 -19
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +122 -73
- data/lib/rigor/effects/signature_sources.rb +4 -6
- data/lib/rigor/effects/snapshot.rb +12 -11
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +393 -38
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +68 -4
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +674 -79
- data/lib/rigor/environment.rb +174 -24
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +292 -17
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +75 -30
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +7 -6
- data/lib/rigor/inference/budget_trace.rb +3 -6
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +389 -18
- data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +180 -0
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +2124 -468
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +16 -7
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +168 -21
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +165 -111
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -6
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +225 -25
- data/lib/rigor/inference/method_parameter_binder.rb +12 -9
- data/lib/rigor/inference/multi_target_binder.rb +341 -55
- data/lib/rigor/inference/mutation_rejoin.rb +171 -0
- data/lib/rigor/inference/mutation_widening.rb +156 -85
- data/lib/rigor/inference/narrowing.rb +835 -162
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +153 -16
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +9 -4
- data/lib/rigor/inference/project_patched_scanner.rb +10 -6
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +93 -4
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +76 -0
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +5228 -627
- data/lib/rigor/inference/statement_evaluator.rb +3452 -595
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +97 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +4 -4
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +7 -8
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +258 -26
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +65 -11
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +33 -13
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +94 -11
- data/lib/rigor/plugin/registry.rb +76 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +14 -12
- data/lib/rigor/protection/kill_signature.rb +1 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +7 -11
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +88 -21
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +139 -0
- data/lib/rigor/reflection.rb +93 -110
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +165 -2
- data/lib/rigor/scope.rb +1041 -32
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +673 -53
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +18 -16
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +128 -14
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +189 -41
- data/lib/rigor/sig_gen.rb +3 -0
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +0 -6
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +144 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +6 -6
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +4 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +14 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +10 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +322 -41
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +290 -19
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +2 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +12 -7
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +36 -37
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +10 -17
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +2 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +10 -5
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +17 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +9 -14
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +51 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +9 -6
- data/sig/rigor/scope.rbs +148 -12
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +33 -1
- data/sig/rigor.rbs +39 -20
- data/skills/rigor-ask/SKILL.md +16 -11
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +15 -10
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +43 -14
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +226 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +133 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -4,7 +4,9 @@ require "rbs"
|
|
|
4
4
|
|
|
5
5
|
require_relative "../type"
|
|
6
6
|
require_relative "../inference/rbs_type_translator"
|
|
7
|
+
require_relative "../builtins/imported_refinements"
|
|
7
8
|
require_relative "rbs_hierarchy"
|
|
9
|
+
require_relative "member_consistency"
|
|
8
10
|
|
|
9
11
|
module Rigor
|
|
10
12
|
class Environment
|
|
@@ -42,6 +44,19 @@ module Rigor
|
|
|
42
44
|
# cache HIT. Never a real path, so it must never be reported as one (issue #696).
|
|
43
45
|
CACHED_LOCATION_BUFFER_NAME = "<cached>"
|
|
44
46
|
|
|
47
|
+
# Issue #527 — the two directory trees whose `.rbs` files ARE Ruby's own surface: the `rbs` gem's
|
|
48
|
+
# `core/` and its bundled `stdlib/` repository. {#core_stdlib_classes} tests a declaration's file
|
|
49
|
+
# against them. Resolved once at load time, on the main Ractor: reading these constants walks a
|
|
50
|
+
# chain of non-`Ractor.shareable?` module constants and raises `Ractor::IsolationError` inside a
|
|
51
|
+
# worker (see {#prewarm}). Empty when the rbs version in use does not expose them, which switches
|
|
52
|
+
# the feature off rather than widening it.
|
|
53
|
+
CORE_STDLIB_ROOTS = begin
|
|
54
|
+
[::RBS::EnvironmentLoader::DEFAULT_CORE_ROOT, ::RBS::Repository::DEFAULT_STDLIB_ROOT]
|
|
55
|
+
.compact.map { |root| "#{root}/".freeze }.freeze
|
|
56
|
+
rescue StandardError
|
|
57
|
+
[].freeze
|
|
58
|
+
end
|
|
59
|
+
|
|
45
60
|
# Cap on how many quarantined `signature_paths:` files {#warn_about_quarantined_signatures} lists by name
|
|
46
61
|
# before collapsing the tail to "… and N more" — a broken generator can emit many, and a wall of parse
|
|
47
62
|
# errors buries the signal.
|
|
@@ -83,10 +98,23 @@ module Rigor
|
|
|
83
98
|
# mastodon coverage note). Per-file loading quarantines the broken file instead. Vendored / core-overlay
|
|
84
99
|
# sigs are Rigor-shipped and trusted, so they stay on the loader's fast batch path.
|
|
85
100
|
add_bundled_signatures(rbs_loader, loaded_libraries.to_set(&:to_s))
|
|
86
|
-
env = RBS::Environment.from_loader(rbs_loader)
|
|
101
|
+
env = unload_upstream_core_shims(RBS::Environment.from_loader(rbs_loader), rbs_loader)
|
|
87
102
|
project_files = project_sig_files(signature_paths)
|
|
88
|
-
|
|
89
|
-
|
|
103
|
+
# Issue #1075 — decided from the inputs before either side enters `env`: the consistency rule may
|
|
104
|
+
# stand the `.rbs` member down, and that has to happen before its file is added.
|
|
105
|
+
consistency = member_consistency_for(project_files, virtual_rbs)
|
|
106
|
+
add_project_signatures(env, signature_paths, deferred_signature_paths,
|
|
107
|
+
standdowns: consistency.signature_standdowns)
|
|
108
|
+
# Issue #928 — the capability-role catalog goes in AFTER the project's own signatures, per
|
|
109
|
+
# declaration, so a project that already declares one of these interface names keeps its own
|
|
110
|
+
# (`add_capability_role_signatures`). The rest of the bundled RBS cannot be ordered that way (it
|
|
111
|
+
# is what `from_loader` builds the env FROM), which is why a colliding project file is quarantined
|
|
112
|
+
# instead — and losing a whole `sig/` file to a name as ordinary as `_Closable` is exactly what
|
|
113
|
+
# shipping a top-level interface catalog would otherwise cost.
|
|
114
|
+
add_capability_role_signatures(env)
|
|
115
|
+
# Issues #824 / #1075 — every member a `.rbs` file also declares was ranked above; the inline side of
|
|
116
|
+
# each pair the `.rbs` won stands down here ({.add_virtual_rbs}), so the two never collide.
|
|
117
|
+
add_virtual_rbs(env, virtual_rbs, inline_standdowns: consistency.inline_standdowns)
|
|
90
118
|
synthesize_missing_namespaces(env)
|
|
91
119
|
# Issue #777 — resolve-time backstop: also unload colliding PROJECT buffers (class-vs-module /
|
|
92
120
|
# constant redeclarations against bundled RBS). Virtual culprits are preferred when both appear.
|
|
@@ -119,8 +147,8 @@ module Rigor
|
|
|
119
147
|
BIG_MATH_SIG_BASENAME = "big_math.rbs"
|
|
120
148
|
private_constant :BIG_MATH_SIG_BASENAME
|
|
121
149
|
|
|
122
|
-
# @param libraries
|
|
123
|
-
# @return
|
|
150
|
+
# @param libraries — the resolved library list, `DEFAULT_LIBRARIES` included.
|
|
151
|
+
# @return the same list, minus `bigdecimal-math` when `bigdecimal` already brings
|
|
124
152
|
# `BigMath` in.
|
|
125
153
|
def libraries_without_shadowed_bigdecimal_math(libraries)
|
|
126
154
|
return libraries unless libraries.include?(BIGDECIMAL_LIBRARY) && libraries.include?(BIGDECIMAL_MATH_LIBRARY)
|
|
@@ -145,6 +173,55 @@ module Rigor
|
|
|
145
173
|
false
|
|
146
174
|
end
|
|
147
175
|
|
|
176
|
+
# Issue #1109 — the `rbs` gem (a `DEFAULT_LIBRARIES` entry, so in every run) ships the shims its
|
|
177
|
+
# own Steep check needs under `sig/shims/`, and one of them reopens a core module: `enumerable.rbs`
|
|
178
|
+
# prepends a `(2) -> Enumerator[[Elem, Elem], void]` overload to `Enumerable#each_slice`. That is
|
|
179
|
+
# a claim about rbs's own call sites, not about Ruby — `[1, 2, 3].each_slice(2)` yields `[3]` last
|
|
180
|
+
# — and it leaked into every analysed project: the blockless form typed as a fixed pair (so a
|
|
181
|
+
# `nil` guard on the second slot folded away) and the block form returned `void` instead of the
|
|
182
|
+
# receiver. Unloading the file leaves core's `Enumerator[Array[Elem], self]`, which agrees with the
|
|
183
|
+
# block form's `Array[Elem]`. The other shims (`bundler.rbs`, `rubygems.rbs`) only add missing
|
|
184
|
+
# declarations and stay. Fails soft to the env as built: a relocated or absent shim, or an rbs API
|
|
185
|
+
# shape this code does not recognise, keeps the pre-#1109 behaviour rather than failing the build.
|
|
186
|
+
# Because errors are rescued, the guard spec in `rbs_loader_spec.rb` is what catches a broken unload,
|
|
187
|
+
# so it must stay green on both lines of the RBS compatibility matrix.
|
|
188
|
+
RBS_LIBRARY = "rbs"
|
|
189
|
+
private_constant :RBS_LIBRARY
|
|
190
|
+
UNSOUND_CORE_SHIMS = %w[shims/enumerable.rbs].freeze
|
|
191
|
+
private_constant :UNSOUND_CORE_SHIMS
|
|
192
|
+
|
|
193
|
+
def unload_upstream_core_shims(env, rbs_loader)
|
|
194
|
+
return env unless env.respond_to?(:unload)
|
|
195
|
+
|
|
196
|
+
shim_names = upstream_core_shim_names(rbs_loader)
|
|
197
|
+
return env if shim_names.empty?
|
|
198
|
+
|
|
199
|
+
buffers = loaded_signature_buffers(env)&.select { |buffer| shim_names.include?(buffer.name.to_s) }
|
|
200
|
+
buffers.nil? || buffers.empty? ? env : env.unload(buffers)
|
|
201
|
+
rescue StandardError
|
|
202
|
+
env
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# rbs 4.x lists its sources through `each_rbs_source`; rbs 3.x keys `signatures` by `Buffer`, and its
|
|
206
|
+
# `unload` matches those very objects with `include?`, so the env's own keys are what it must receive.
|
|
207
|
+
def loaded_signature_buffers(env)
|
|
208
|
+
if env.respond_to?(:each_rbs_source)
|
|
209
|
+
env.each_rbs_source.map(&:buffer)
|
|
210
|
+
elsif env.respond_to?(:signatures)
|
|
211
|
+
env.signatures.keys
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def upstream_core_shim_names(rbs_loader)
|
|
216
|
+
names = Set.new
|
|
217
|
+
rbs_loader.each_dir do |source, dir|
|
|
218
|
+
next unless source.respond_to?(:name) && source.name == RBS_LIBRARY
|
|
219
|
+
|
|
220
|
+
UNSOUND_CORE_SHIMS.each { |relative| names << Pathname(dir).join(relative).to_s }
|
|
221
|
+
end
|
|
222
|
+
names
|
|
223
|
+
end
|
|
224
|
+
|
|
148
225
|
# True when `content` parses as an RBS signature. {#virtual_rbs_collision_quarantined} uses this to
|
|
149
226
|
# tell a collision-dropped virtual entry (parses, but absent from the env) from a parse-failed one
|
|
150
227
|
# (the synthesizer's own WD6 skip, reported separately).
|
|
@@ -323,16 +400,21 @@ module Rigor
|
|
|
323
400
|
# Buffer names are the file's absolute path (matching {.project_sig_files}) so {.project_entry?} — which
|
|
324
401
|
# attributes a `class_decls` entry to the project by buffer name — still recognises these declarations.
|
|
325
402
|
# Sorted for a deterministic add order (the env feeds the cache, ADR-54).
|
|
326
|
-
|
|
403
|
+
#
|
|
404
|
+
# @param standdowns — issue #1075 — `{signature_path => Set[[class, method, kind]]}`, the members an
|
|
405
|
+
# inline declaration displaced because it was the more precise side of a consistent pair
|
|
406
|
+
# ({MemberConsistency::Resolution#signature_standdowns}). They are removed before the file is added.
|
|
407
|
+
def add_project_signatures(env, signature_paths, deferred_paths = [], standdowns: {})
|
|
327
408
|
deferred = project_sig_files(deferred_paths)
|
|
328
409
|
(project_sig_files(signature_paths) - deferred).sort.each do |file|
|
|
329
410
|
parsed = parse_signature_file(file)
|
|
330
411
|
next if parsed.nil? # quarantined (unparseable) or unreadable — skip so the env survives
|
|
331
412
|
|
|
332
413
|
buffer, directives, decls = parsed
|
|
414
|
+
strip_members!(decls, standdowns[file]) if standdowns.key?(file)
|
|
333
415
|
add_project_parsed_decls(env, buffer, directives, decls)
|
|
334
416
|
end
|
|
335
|
-
add_deferred_signatures(env, deferred)
|
|
417
|
+
add_deferred_signatures(env, deferred, standdowns)
|
|
336
418
|
end
|
|
337
419
|
|
|
338
420
|
# Issue #777 — add one project signature transactionally. `RBS::Environment#add_source` appends to
|
|
@@ -370,7 +452,7 @@ module Rigor
|
|
|
370
452
|
# (rigor-activerecord's is `relation.rbs`, declaring exactly `Relation`), so dropping the file drops
|
|
371
453
|
# exactly the conflicting declaration. Splitting a plugin file that mixes a colliding class with
|
|
372
454
|
# innocent ones is the change to make if that ever stops being true.
|
|
373
|
-
def add_deferred_signatures(env, deferred_files)
|
|
455
|
+
def add_deferred_signatures(env, deferred_files, standdowns = {})
|
|
374
456
|
deferred_files.sort.each do |file|
|
|
375
457
|
parsed = parse_signature_file(file)
|
|
376
458
|
next if parsed.nil?
|
|
@@ -378,12 +460,13 @@ module Rigor
|
|
|
378
460
|
buffer, directives, decls = parsed
|
|
379
461
|
next if generic_arity_conflict(env, decls)
|
|
380
462
|
|
|
463
|
+
strip_members!(decls, standdowns[file]) if standdowns.key?(file)
|
|
381
464
|
add_project_parsed_decls(env, buffer, directives, decls)
|
|
382
465
|
end
|
|
383
466
|
end
|
|
384
467
|
|
|
385
468
|
# Issue #610 — which deferred (plugin-contributed) files stood down, as
|
|
386
|
-
# `[absolute_path, class_name, existing_arity, incoming_arity]`, sorted. DERIVED from a built env
|
|
469
|
+
# `[absolute_path, class_name, existing_arity, incoming_arity, existing_file]`, sorted. DERIVED from a built env
|
|
387
470
|
# rather than recorded during the build, for {RbsLoader#quarantined_signatures}' reason: a cache HIT
|
|
388
471
|
# never runs the build, and a condition only the build knew would silently disappear on the second
|
|
389
472
|
# run. Re-asking the same question of the FINAL env gives the same answer — the file's declaration is
|
|
@@ -400,21 +483,40 @@ module Rigor
|
|
|
400
483
|
end
|
|
401
484
|
end
|
|
402
485
|
|
|
403
|
-
# The first `[class_name, existing_arity, incoming_arity]` where `decls` would
|
|
404
|
-
# env already has with a DIFFERENT number of type parameters, or nil when
|
|
405
|
-
# Equal arity is not a conflict: RBS reopens the class, which is the ordinary
|
|
406
|
-
# the stand-down must not fire on it.
|
|
486
|
+
# The first `[class_name, existing_arity, incoming_arity, existing_file]` where `decls` would
|
|
487
|
+
# re-declare a class the env already has with a DIFFERENT number of type parameters, or nil when
|
|
488
|
+
# they agree everywhere. Equal arity is not a conflict: RBS reopens the class, which is the ordinary
|
|
489
|
+
# and supported case, so the stand-down must not fire on it.
|
|
490
|
+
#
|
|
491
|
+
# The existing arity is read off the entry's FIRST declaration, never through `entry.type_params`:
|
|
492
|
+
# rbs 4.x's `ClassEntry#type_params` validates every declaration against the first before answering
|
|
493
|
+
# and raises `GenericParameterMismatchError` on an entry that already disagrees with itself (rbs
|
|
494
|
+
# 3.x's does not), so the derived reader ({.deferred_standdowns}) raised on exactly the env it exists
|
|
495
|
+
# to describe — one a user's own two sources collided, or one the cache served from before the
|
|
496
|
+
# producer passed the deferred list. The first declaration is also the one rbs compares against.
|
|
497
|
+
# `existing_file` is that declaration's buffer name — the source that displaced the plugin's — or
|
|
498
|
+
# nil when it has none or carries only the cached-position sentinel.
|
|
407
499
|
def generic_arity_conflict(env, decls)
|
|
408
500
|
each_declared_class(decls) do |name, arity|
|
|
409
501
|
entry = env.class_decls[::RBS::TypeName.parse(name)]
|
|
410
|
-
next if entry.nil?
|
|
502
|
+
next if entry.nil?
|
|
411
503
|
|
|
412
|
-
|
|
413
|
-
|
|
504
|
+
first = entry_declarations(entry).first
|
|
505
|
+
existing = first.respond_to?(:type_params) ? first.type_params&.size : nil
|
|
506
|
+
return [name, existing, arity, declaration_buffer_name(first)] if existing && existing != arity
|
|
414
507
|
end
|
|
415
508
|
nil
|
|
416
509
|
end
|
|
417
510
|
|
|
511
|
+
def declaration_buffer_name(decl)
|
|
512
|
+
location = decl.respond_to?(:location) ? decl.location : nil
|
|
513
|
+
buffer = location&.buffer
|
|
514
|
+
name = buffer.nil? ? nil : buffer.name.to_s
|
|
515
|
+
return nil if name.nil? || name.empty? || name == CACHED_LOCATION_BUFFER_NAME
|
|
516
|
+
|
|
517
|
+
name
|
|
518
|
+
end
|
|
519
|
+
|
|
418
520
|
# Yields `[absolute_class_name, type_param_count]` for every class declared anywhere in `decls`,
|
|
419
521
|
# descending through modules and nested classes. Names inside a `module`/`class` body are parsed
|
|
420
522
|
# RELATIVE, so the enclosing path is accumulated here — the env is keyed by absolute name, and
|
|
@@ -798,7 +900,13 @@ module Rigor
|
|
|
798
900
|
# provenance (RBS parse errors cite it) — it is not a real file path. Per WD6 the synthesizer-emit
|
|
799
901
|
# path is responsible for catching its own parse errors and returning `nil` rather than garbage; this
|
|
800
902
|
# method assumes its input is parseable and only rescues `RBS::ParsingError` as a fail-soft.
|
|
801
|
-
|
|
903
|
+
# @param inline_standdowns — issue #1075 — the `[class, method, kind]` keys whose inline member
|
|
904
|
+
# stands down because a project `.rbs` declares the same member and ADR-112 WD5's consistency rule
|
|
905
|
+
# let the `.rbs` bind ({MemberConsistency::Resolution#inline_standdowns}). Removing them before the
|
|
906
|
+
# declaration is added keeps the two from colliding and costing the whole class its method surface.
|
|
907
|
+
# The outcome is reported, never silent: {RbsLoader#member_consistency} re-derives the same records
|
|
908
|
+
# for the run's rows.
|
|
909
|
+
def add_virtual_rbs(env, virtual_rbs, inline_standdowns: Set.new)
|
|
802
910
|
return if virtual_rbs.nil? || virtual_rbs.empty?
|
|
803
911
|
|
|
804
912
|
virtual_rbs.each do |filename, content|
|
|
@@ -809,6 +917,7 @@ module Rigor
|
|
|
809
917
|
|
|
810
918
|
buffer = ::RBS::Buffer.new(name: filename.to_s, content: content.to_s)
|
|
811
919
|
_, directives, decls = ::RBS::Parser.parse_signature(buffer)
|
|
920
|
+
strip_members!(decls, inline_standdowns) unless inline_standdowns.empty?
|
|
812
921
|
add_parsed_decls(env, buffer, directives, decls)
|
|
813
922
|
rescue ::RBS::BaseError
|
|
814
923
|
# WD6 fail-soft: a single broken virtual RBS contribution does not pull the whole env down — for
|
|
@@ -828,6 +937,204 @@ module Rigor
|
|
|
828
937
|
end
|
|
829
938
|
end
|
|
830
939
|
|
|
940
|
+
# Issue #1075 / ADR-112 WD5 — the member-level half of inline-vs-`sig/` consistency, which replaced
|
|
941
|
+
# #824's "`sig/` wins per member" (ADR-32 WD13).
|
|
942
|
+
#
|
|
943
|
+
# A method declared BOTH by a project `.rbs` and by an inline annotation in its own `.rb` lands twice
|
|
944
|
+
# in one `RBS::Environment`: rbs merges the two sources into a single `ClassEntry` and ranks neither,
|
|
945
|
+
# so `RBS::DefinitionBuilder::MethodBuilder::Methods#validate!` raises
|
|
946
|
+
# `RBS::DuplicatedMethodDefinitionError` and the WHOLE class loses its method surface — every call on
|
|
947
|
+
# it, real methods and typos alike, reads `Dynamic[top]`. Measured on Rigor's own tree while
|
|
948
|
+
# [#779](https://github.com/rigortype/rigor/pull/779) was evaluated: 17 of 234 annotated files
|
|
949
|
+
# overlapped `sig/`, and the collision took 44 classes down. Steep 2.1 / rbs 4.1 have no precedence
|
|
950
|
+
# rule to follow here (ADR-32 WD13), so exactly one of the two members has to go before the
|
|
951
|
+
# environment is built. {MemberConsistency} decides which: the more precise of two consistent
|
|
952
|
+
# declarations binds, and on a contradiction or an undecidable pair the `.rbs` does.
|
|
953
|
+
#
|
|
954
|
+
# @return a {MemberConsistency::Resolution}. {MemberConsistency::EMPTY} — and free — for a project
|
|
955
|
+
# that contributes no inline RBS, which is every project without a `source_rbs_synthesizer:` plugin.
|
|
956
|
+
#
|
|
957
|
+
# Derived from the loader's INPUTS — the synthesized sources and the project's signature files —
|
|
958
|
+
# never from a built environment, for {RbsLoader#quarantined_signatures}' reason turned inside out: a
|
|
959
|
+
# cache HIT never runs the build, and a stripped member leaves no trace in the environment to read
|
|
960
|
+
# back. The build and {RbsLoader#member_consistency} call this same function on the same two inputs,
|
|
961
|
+
# so the members they strip and the rows they report agree warm and cold.
|
|
962
|
+
def member_consistency_for(project_files, virtual_rbs, proof: nil)
|
|
963
|
+
return MemberConsistency::EMPTY if virtual_rbs.nil? || virtual_rbs.empty?
|
|
964
|
+
|
|
965
|
+
signature_members, shadowable = signature_member_index(project_files, virtual_rbs)
|
|
966
|
+
inline_members = inline_member_entries(virtual_rbs, all: !signature_members.empty?)
|
|
967
|
+
MemberConsistency.resolve(signature_members, inline_members, shadowable: shadowable, proof: proof)
|
|
968
|
+
end
|
|
969
|
+
|
|
970
|
+
# `[owners, shadowable]`. `owners` is `{[class_name, method_name, kind] => [signature_path, member,
|
|
971
|
+
# visibility]}` for every method-shaped member the project's own `signature_paths:` files declare and
|
|
972
|
+
# the inline sources also name; the first file in sorted order owns a key two `.rbs` files declare
|
|
973
|
+
# (that pair fails the definition build anyway). `shadowable` is every `::` segment of every class /
|
|
974
|
+
# module name the inline sources and the signature files declare — the names a relative reference
|
|
975
|
+
# might resolve to inside an enclosing namespace ({MemberConsistency::Comparator#faithful?}).
|
|
976
|
+
#
|
|
977
|
+
# The parse is scoped by a substring pre-filter over each file's text: a declaration has to spell its
|
|
978
|
+
# own name, so a signature file mentioning none of the names the inline sources declare cannot
|
|
979
|
+
# collide with them. The filter over-approximates (it matches a name in a comment or a type position
|
|
980
|
+
# too), so it can only cost an unnecessary parse, never miss a collision.
|
|
981
|
+
def signature_member_index(project_files, virtual_rbs)
|
|
982
|
+
names = inline_declared_name_segments(virtual_rbs)
|
|
983
|
+
return [{}, names] if project_files.nil? || project_files.empty? || names.empty?
|
|
984
|
+
|
|
985
|
+
shadowable = names.dup
|
|
986
|
+
owners = project_files.to_a.sort.each_with_object({}) do |file, index|
|
|
987
|
+
content = read_signature_text(file)
|
|
988
|
+
next if content.nil?
|
|
989
|
+
|
|
990
|
+
merge_declared_segments(content, shadowable)
|
|
991
|
+
next if names.none? { |name| content.include?(name) }
|
|
992
|
+
|
|
993
|
+
index_signature_members(index, file, parse_signature_source(file, content))
|
|
994
|
+
end
|
|
995
|
+
[owners, shadowable]
|
|
996
|
+
end
|
|
997
|
+
|
|
998
|
+
def index_signature_members(index, file, decls)
|
|
999
|
+
return if decls.nil?
|
|
1000
|
+
|
|
1001
|
+
each_declared_member(decls) do |class_name, member, visibility|
|
|
1002
|
+
member_method_keys(member).each do |method_name, kind|
|
|
1003
|
+
index[[class_name, method_name, kind]] ||= [file, member, visibility].freeze
|
|
1004
|
+
end
|
|
1005
|
+
end
|
|
1006
|
+
end
|
|
1007
|
+
|
|
1008
|
+
# The directive heads a refinement {MemberConsistency.refinement_conflicts} checks, used to skip
|
|
1009
|
+
# parsing an inline source that carries none when no `.rbs` overlaps it. Narrower than `rigor:v1:` on
|
|
1010
|
+
# purpose: rbs-inline's output marks every skeleton `%a{rigor:v1:inferred-return}`, so that prefix is
|
|
1011
|
+
# in nearly every synthesized source.
|
|
1012
|
+
REFINEMENT_DIRECTIVE_MARKS = ["rigor:v1:return:", "rigor:v1:param:"].freeze
|
|
1013
|
+
private_constant :REFINEMENT_DIRECTIVE_MARKS
|
|
1014
|
+
|
|
1015
|
+
# `[[virtual_name, class_name, member], ...]` for the inline members {MemberConsistency.resolve}
|
|
1016
|
+
# reads: every member when a `.rbs` file may overlap them (`all:`), otherwise only the members of a
|
|
1017
|
+
# source that carries a `rigor:v1:return:` / `rigor:v1:param:` refinement, which is checked against
|
|
1018
|
+
# its own declared type. Entries {.add_virtual_rbs} would skip are skipped here too.
|
|
1019
|
+
def inline_member_entries(virtual_rbs, all:)
|
|
1020
|
+
virtual_rbs.each_with_object([]) do |(name, content), entries|
|
|
1021
|
+
content = content.to_s
|
|
1022
|
+
next if content.empty? || invalid_encoding?(content)
|
|
1023
|
+
next unless all || REFINEMENT_DIRECTIVE_MARKS.any? { |mark| content.include?(mark) }
|
|
1024
|
+
|
|
1025
|
+
decls = parse_signature_source(name, content)
|
|
1026
|
+
next if decls.nil?
|
|
1027
|
+
|
|
1028
|
+
each_declared_member(decls) do |class_name, member, visibility|
|
|
1029
|
+
entries << [name.to_s, class_name, member, visibility]
|
|
1030
|
+
end
|
|
1031
|
+
end
|
|
1032
|
+
end
|
|
1033
|
+
|
|
1034
|
+
# Removes, in place, every member contributing a key in `keys` (a Set of `[class, method, kind]`).
|
|
1035
|
+
# Nested declarations are descended into after the rejection, and a declaration member contributes no
|
|
1036
|
+
# method key, so nesting is never itself removed.
|
|
1037
|
+
def strip_members!(decls, keys, prefix = [])
|
|
1038
|
+
Array(decls).each do |decl|
|
|
1039
|
+
next unless declaration_with_members?(decl)
|
|
1040
|
+
|
|
1041
|
+
inner = prefix + [decl.name.to_s.delete_prefix("::")]
|
|
1042
|
+
class_name = inner.join("::")
|
|
1043
|
+
decl.members.reject! do |member|
|
|
1044
|
+
member_method_keys(member).any? { |method_name, kind| keys.include?([class_name, method_name, kind]) }
|
|
1045
|
+
end
|
|
1046
|
+
strip_members!(decl.members, keys, inner)
|
|
1047
|
+
end
|
|
1048
|
+
end
|
|
1049
|
+
|
|
1050
|
+
# Yields `[class_name, member, visibility]` for every member of every class / module declaration in
|
|
1051
|
+
# `decls`, descending through nesting. The enclosing path is accumulated and the name rendered
|
|
1052
|
+
# `::`-stripped, so a `module Foo; class Bar` and a `class Foo::Bar` elsewhere key the same — which is
|
|
1053
|
+
# what makes a `sig/` declaration and an inline one comparable at all. `visibility` is the member's
|
|
1054
|
+
# own (`private def x`) or else the one the enclosing `private` / `public` section sets; a singleton
|
|
1055
|
+
# method takes no section, as in Ruby.
|
|
1056
|
+
def each_declared_member(decls, prefix = [], &block)
|
|
1057
|
+
Array(decls).each do |decl|
|
|
1058
|
+
next unless declaration_with_members?(decl)
|
|
1059
|
+
|
|
1060
|
+
inner = prefix + [decl.name.to_s.delete_prefix("::")]
|
|
1061
|
+
class_name = inner.join("::")
|
|
1062
|
+
section = :public
|
|
1063
|
+
decl.members.each do |member|
|
|
1064
|
+
case member
|
|
1065
|
+
when ::RBS::AST::Members::Private then section = :private
|
|
1066
|
+
when ::RBS::AST::Members::Public then section = :public
|
|
1067
|
+
else block.call(class_name, member, member_visibility(member, section))
|
|
1068
|
+
end
|
|
1069
|
+
end
|
|
1070
|
+
each_declared_member(decl.members, inner, &block)
|
|
1071
|
+
end
|
|
1072
|
+
end
|
|
1073
|
+
|
|
1074
|
+
def member_visibility(member, section)
|
|
1075
|
+
own = member.respond_to?(:visibility) ? member.visibility : nil
|
|
1076
|
+
return own if own
|
|
1077
|
+
|
|
1078
|
+
member.respond_to?(:kind) && member.kind == :singleton ? :public : section
|
|
1079
|
+
end
|
|
1080
|
+
|
|
1081
|
+
def declaration_with_members?(decl)
|
|
1082
|
+
(decl.is_a?(::RBS::AST::Declarations::Module) || decl.is_a?(::RBS::AST::Declarations::Class)) &&
|
|
1083
|
+
decl.respond_to?(:members)
|
|
1084
|
+
end
|
|
1085
|
+
|
|
1086
|
+
# {MemberConsistency.member_method_keys} — the `[method_name, kind]` pairs a member contributes to a
|
|
1087
|
+
# definition build, which is what decides whether two members collide.
|
|
1088
|
+
def member_method_keys(member)
|
|
1089
|
+
MemberConsistency.member_method_keys(member)
|
|
1090
|
+
end
|
|
1091
|
+
|
|
1092
|
+
# A class / module declaration header, as the pre-filter in {.signature_member_index} reads it out of
|
|
1093
|
+
# synthesized RBS text.
|
|
1094
|
+
INLINE_DECLARATION_NAME = /^[ \t]*(?:class|module)[ \t]+([A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*)/
|
|
1095
|
+
private_constant :INLINE_DECLARATION_NAME
|
|
1096
|
+
|
|
1097
|
+
# Every `::`-separated segment of every class / module name the inline sources declare, read off the
|
|
1098
|
+
# synthesized TEXT rather than a parse: the set only has to be a SUPERSET (it feeds the pre-filter),
|
|
1099
|
+
# and a regexp over the handful of annotated files is far cheaper than parsing them a second time.
|
|
1100
|
+
# Entries {.add_virtual_rbs} would skip are skipped here too — an empty or invalid-UTF-8 contribution
|
|
1101
|
+
# declares nothing, and `String#scan` raises `ArgumentError` on invalid bytes rather than returning
|
|
1102
|
+
# no match.
|
|
1103
|
+
def inline_declared_name_segments(virtual_rbs)
|
|
1104
|
+
virtual_rbs.each_with_object(Set.new) do |(_name, content), acc|
|
|
1105
|
+
content = content.to_s
|
|
1106
|
+
next if content.empty? || invalid_encoding?(content)
|
|
1107
|
+
|
|
1108
|
+
merge_declared_segments(content, acc)
|
|
1109
|
+
end
|
|
1110
|
+
end
|
|
1111
|
+
|
|
1112
|
+
# Adds every `::` segment of every class / module header in `content` to `segments`. The pattern has
|
|
1113
|
+
# one capture group, which every match fills.
|
|
1114
|
+
def merge_declared_segments(content, segments)
|
|
1115
|
+
content.scan(INLINE_DECLARATION_NAME) { segments.merge(Regexp.last_match(1).to_s.split("::")) }
|
|
1116
|
+
end
|
|
1117
|
+
|
|
1118
|
+
# One project signature file's text, or nil when it is unreadable or not valid UTF-8.
|
|
1119
|
+
def read_signature_text(file)
|
|
1120
|
+
content = File.read(file, encoding: "UTF-8")
|
|
1121
|
+
invalid_encoding?(content) ? nil : content
|
|
1122
|
+
rescue Errno::ENOENT, Errno::EISDIR, Errno::EACCES
|
|
1123
|
+
nil
|
|
1124
|
+
end
|
|
1125
|
+
|
|
1126
|
+
# The declarations of already-read RBS text, or nil when it does not parse. The twin of
|
|
1127
|
+
# {.parse_signature_file} for content the caller already holds (a synthesized virtual source, or a
|
|
1128
|
+
# signature file the pre-filter has just read).
|
|
1129
|
+
def parse_signature_source(name, content)
|
|
1130
|
+
_buffer, _directives, decls = ::RBS::Parser.parse_signature(
|
|
1131
|
+
::RBS::Buffer.new(name: name.to_s, content: content)
|
|
1132
|
+
)
|
|
1133
|
+
decls
|
|
1134
|
+
rescue ::RBS::BaseError
|
|
1135
|
+
nil
|
|
1136
|
+
end
|
|
1137
|
+
|
|
831
1138
|
# Per-gem `data/vendored_gem_sigs/<gem>/` directories that ship with Rigor. Each subdirectory is one
|
|
832
1139
|
# gem's RBS surface (the `<gem>.rbs` file is the typical content; `LICENSE.upstream` records
|
|
833
1140
|
# provenance). Coverage is deliberately scoped to the native-extension and "everywhere in Rails" gems
|
|
@@ -840,9 +1147,10 @@ module Rigor
|
|
|
840
1147
|
private_constant :VENDORED_GEM_SIGS_ROOT
|
|
841
1148
|
|
|
842
1149
|
# Rigor-owned core-overlay RBS (`data/core_overlay/`). Reopens Ruby core classes to add methods
|
|
843
|
-
# upstream `ruby/rbs` omits but which every concrete value answers at runtime
|
|
844
|
-
#
|
|
845
|
-
#
|
|
1150
|
+
# upstream `ruby/rbs` omits but which every concrete value answers at runtime. A direct `def` that
|
|
1151
|
+
# another source also declares is a `DuplicatedMethodDefinitionError`, not a precedence question, so a
|
|
1152
|
+
# method a project `sig/` or a later rbs is likely to declare goes on a module the class extends
|
|
1153
|
+
# (`process.rbs`). Public so the cache descriptor can digest these files into the env-blob key.
|
|
846
1154
|
CORE_OVERLAY_SIGS_ROOT = File.expand_path(
|
|
847
1155
|
"../../../data/core_overlay",
|
|
848
1156
|
__dir__
|
|
@@ -854,6 +1162,51 @@ module Rigor
|
|
|
854
1162
|
[Pathname(CORE_OVERLAY_SIGS_ROOT)]
|
|
855
1163
|
end
|
|
856
1164
|
|
|
1165
|
+
# Rigor's capability-role catalog (`data/capability_roles/`) — the structural interfaces ADR-1 and
|
|
1166
|
+
# `docs/type-specification/structural-interfaces-and-object-shapes.md` name as shipped, so a
|
|
1167
|
+
# `%a{rigor:v1:conforms-to _ClosableStream}` written by following the specification resolves in a
|
|
1168
|
+
# default run instead of failing soft to an unresolved-interface row. Public for the same reason
|
|
1169
|
+
# {.core_overlay_sig_paths} is: the cache descriptor digests these files into the env-blob key.
|
|
1170
|
+
CAPABILITY_ROLES_SIGS_ROOT = File.expand_path(
|
|
1171
|
+
"../../../data/capability_roles",
|
|
1172
|
+
__dir__
|
|
1173
|
+
).freeze
|
|
1174
|
+
|
|
1175
|
+
def capability_role_sig_paths
|
|
1176
|
+
return [] unless File.directory?(CAPABILITY_ROLES_SIGS_ROOT)
|
|
1177
|
+
|
|
1178
|
+
[Pathname(CAPABILITY_ROLES_SIGS_ROOT)]
|
|
1179
|
+
end
|
|
1180
|
+
|
|
1181
|
+
# Adds the catalog to an env that already holds the project's own signatures, one INTERFACE at a
|
|
1182
|
+
# time, skipping any name the env already declares. Granularity is the declaration rather than the
|
|
1183
|
+
# file (the #610 stand-down's unit) because this one file carries five unrelated roles: a project
|
|
1184
|
+
# declaring `_Closable` must not also lose `_ClosableStream`.
|
|
1185
|
+
def add_capability_role_signatures(env)
|
|
1186
|
+
declared = declared_interface_names(env)
|
|
1187
|
+
capability_role_sig_paths.each do |dir|
|
|
1188
|
+
dir.children.sort.each do |file|
|
|
1189
|
+
next unless file.file? && file.extname == ".rbs"
|
|
1190
|
+
|
|
1191
|
+
parsed = parse_signature_file(file.to_s)
|
|
1192
|
+
next if parsed.nil?
|
|
1193
|
+
|
|
1194
|
+
buffer, directives, decls = parsed
|
|
1195
|
+
standing = decls.reject { |decl| declared.include?(decl.name.absolute!) }
|
|
1196
|
+
next if standing.empty?
|
|
1197
|
+
|
|
1198
|
+
add_parsed_decls(env, buffer, directives, standing)
|
|
1199
|
+
end
|
|
1200
|
+
end
|
|
1201
|
+
end
|
|
1202
|
+
|
|
1203
|
+
# @param env — the environment the project's signatures are already in.
|
|
1204
|
+
def declared_interface_names(env)
|
|
1205
|
+
return Set.new unless env.respond_to?(:interface_decls)
|
|
1206
|
+
|
|
1207
|
+
env.interface_decls.keys.to_set
|
|
1208
|
+
end
|
|
1209
|
+
|
|
857
1210
|
# Bundled signature sources that SUPPLEMENT a stdlib library's own declarations rather than stand
|
|
858
1211
|
# alone: each re-opens a class the named `RBS::EnvironmentLoader` library declares with a mixin
|
|
859
1212
|
# (`CGI::QueryExtension`), a superclass (`Prism::Result`), or an `| ...` overload continuation
|
|
@@ -867,6 +1220,10 @@ module Rigor
|
|
|
867
1220
|
# `core_overlay/pathname.rbs` also carries an `| ...` continuation but is deliberately NOT listed:
|
|
868
1221
|
# its base (`Pathname#expand_path`) lives in rbs's `core/pathname.rbs` on every supported rbs
|
|
869
1222
|
# release (3.10 / 4.0 / 4.1), so the continuation is safe — and applicable — with no library loaded.
|
|
1223
|
+
# `core_overlay/string_io.rbs` re-opens a class the `stringio` library declares yet is NOT listed
|
|
1224
|
+
# either: `RBS::EnvironmentLoader#load` adds that library itself whenever it loads core (rbs 3.7+),
|
|
1225
|
+
# and earlier releases declare `StringIO` in core, so gating would only drop its `Enumerable` mixin
|
|
1226
|
+
# where `StringIO` is present anyway.
|
|
870
1227
|
#
|
|
871
1228
|
# Keyed by `data/vendored_gem_sigs/` directory basename.
|
|
872
1229
|
LIBRARY_SUPPLEMENT_VENDORED_DIRS = {
|
|
@@ -883,14 +1240,25 @@ module Rigor
|
|
|
883
1240
|
}.freeze
|
|
884
1241
|
private_constant :LIBRARY_SUPPLEMENT_CORE_OVERLAYS
|
|
885
1242
|
|
|
1243
|
+
# `data/core_overlay/` files that fill a hole only one `rbs` release line has, keyed by file basename
|
|
1244
|
+
# to the `rbs` version requirement they load under. Each carries an `| ...` continuation of overloads a
|
|
1245
|
+
# later line declares upstream, so loading it there would add a second copy of them. The env-cache key
|
|
1246
|
+
# already carries `RBS::VERSION` ({Cache::RbsDescriptor.rbs_gem_entry}), so switching lines re-keys.
|
|
1247
|
+
# The requirement is a String, not a `Gem::Requirement`, so the constant stays `Ractor.shareable?`.
|
|
1248
|
+
RBS_LINE_CORE_OVERLAYS = {
|
|
1249
|
+
"hash_rbs3.rbs" => "< 4.0"
|
|
1250
|
+
}.freeze
|
|
1251
|
+
private_constant :RBS_LINE_CORE_OVERLAYS
|
|
1252
|
+
|
|
886
1253
|
# Adds the Rigor-shipped signature sources to `rbs_loader`: every `data/vendored_gem_sigs/<gem>/`
|
|
887
|
-
# directory, then the `data/core_overlay/` files
|
|
888
|
-
#
|
|
889
|
-
#
|
|
890
|
-
#
|
|
891
|
-
# per-directory, because the `LIBRARY_SUPPLEMENT_CORE_OVERLAYS`
|
|
1254
|
+
# directory, then the `data/core_overlay/` files, which fill genuine holes only (e.g. `Numeric#to_f`/
|
|
1255
|
+
# `to_i`/`to_r`, which upstream RBS declares on the concrete subclasses but not on the abstract `Numeric`
|
|
1256
|
+
# that Rigor's arithmetic-chain widening produces). Load order does not settle a conflict: a method
|
|
1257
|
+
# both sides declare directly raises `DuplicatedMethodDefinitionError` for the whole class. The
|
|
1258
|
+
# overlay is added per-file, not per-directory, because the `LIBRARY_SUPPLEMENT_CORE_OVERLAYS` and
|
|
1259
|
+
# `RBS_LINE_CORE_OVERLAYS` files must be gated individually.
|
|
892
1260
|
#
|
|
893
|
-
# @param loaded_library_names
|
|
1261
|
+
# @param loaded_library_names — libraries that actually resolved on this loader.
|
|
894
1262
|
def add_bundled_signatures(rbs_loader, loaded_library_names)
|
|
895
1263
|
vendored_gem_sig_paths.each do |path|
|
|
896
1264
|
next unless path.directory?
|
|
@@ -904,21 +1272,29 @@ module Rigor
|
|
|
904
1272
|
dir.children.sort.each do |file|
|
|
905
1273
|
next unless file.file? && file.extname == ".rbs"
|
|
906
1274
|
next unless supplement_dependency_loaded?(LIBRARY_SUPPLEMENT_CORE_OVERLAYS, file, loaded_library_names)
|
|
1275
|
+
next unless rbs_line_matches?(file)
|
|
907
1276
|
|
|
908
1277
|
rbs_loader.add(path: file)
|
|
909
1278
|
end
|
|
910
1279
|
end
|
|
911
1280
|
end
|
|
912
1281
|
|
|
913
|
-
# @param supplements
|
|
914
|
-
# @param path
|
|
915
|
-
# @param loaded_library_names
|
|
916
|
-
# @return
|
|
1282
|
+
# @param supplements — basename → gating library map.
|
|
1283
|
+
# @param path — the vendored directory or overlay file to test.
|
|
1284
|
+
# @param loaded_library_names — libraries that actually resolved on this loader.
|
|
1285
|
+
# @return true when `path` carries no library dependency, or its library loaded.
|
|
917
1286
|
def supplement_dependency_loaded?(supplements, path, loaded_library_names)
|
|
918
1287
|
library = supplements[path.basename.to_s]
|
|
919
1288
|
library.nil? || loaded_library_names.include?(library)
|
|
920
1289
|
end
|
|
921
1290
|
|
|
1291
|
+
# @param path — a `data/core_overlay/` file.
|
|
1292
|
+
# @return true when `path` is not tied to an `rbs` release line, or the running `rbs` is on its line.
|
|
1293
|
+
def rbs_line_matches?(path)
|
|
1294
|
+
requirement = RBS_LINE_CORE_OVERLAYS[path.basename.to_s]
|
|
1295
|
+
requirement.nil? || Gem::Requirement.new(requirement).satisfied_by?(Gem::Version.new(::RBS::VERSION))
|
|
1296
|
+
end
|
|
1297
|
+
|
|
922
1298
|
# Rigor-owned per-gem RBS overlays (`data/gem_overlay/<gem>/`), ADR-72. Unlike the unconditional
|
|
923
1299
|
# `core_overlay`, each gem's overlay is loaded ONLY when that gem is locked in the project's
|
|
924
1300
|
# Gemfile.lock but ships no RBS of its own — {Environment.for_project} decides eligibility and passes
|
|
@@ -929,9 +1305,9 @@ module Rigor
|
|
|
929
1305
|
__dir__
|
|
930
1306
|
).freeze
|
|
931
1307
|
|
|
932
|
-
# @param gem_names
|
|
1308
|
+
# @param gem_names — overlay-eligible Gemfile.lock gem names (the caller filters
|
|
933
1309
|
# to the `:missing`-coverage, no-conflicting-plugin set).
|
|
934
|
-
# @return
|
|
1310
|
+
# @return the bundled overlay directory for each gem that ships one; empty when
|
|
935
1311
|
# none match or the overlay root is absent.
|
|
936
1312
|
def gem_overlay_sig_paths(gem_names)
|
|
937
1313
|
return [] unless File.directory?(GEM_OVERLAY_SIGS_ROOT)
|
|
@@ -942,9 +1318,9 @@ module Rigor
|
|
|
942
1318
|
end
|
|
943
1319
|
end
|
|
944
1320
|
|
|
945
|
-
# @param path
|
|
1321
|
+
# @param path — typically an entry from an {RbsLoader} instance's
|
|
946
1322
|
# {#signature_paths}.
|
|
947
|
-
# @return
|
|
1323
|
+
# @return whether `path` sits under the bundled gem-overlay root — what
|
|
948
1324
|
# `CheckRules::GEM_OVERLAY_OPEN_RECEIVERS`'s gate consults so that a class name's membership in
|
|
949
1325
|
# that list alone never grants the open-receiver exemption; the overlay directory that made the
|
|
950
1326
|
# entry true must have actually loaded THIS run too (issue #632, tracked further by #660).
|
|
@@ -982,7 +1358,7 @@ module Rigor
|
|
|
982
1358
|
# answer to the very same question, on the class that already owns the overlay's layout
|
|
983
1359
|
# ({GEM_OVERLAY_SIGS_ROOT}, {.gem_overlay_sig_paths}).
|
|
984
1360
|
#
|
|
985
|
-
# @param signature_paths
|
|
1361
|
+
# @param signature_paths — typically an {RbsLoader} instance's
|
|
986
1362
|
# {#signature_paths}. Takes the whole list rather than one entry so the twin's file set resolves
|
|
987
1363
|
# once per question — `CheckRules` asks it per `ActiveSupport::Duration` receiver.
|
|
988
1364
|
def gem_overlay_twin_signatures_loaded?(signature_paths)
|
|
@@ -997,7 +1373,7 @@ module Rigor
|
|
|
997
1373
|
# id mapping and passes the id; this resolves the id to the engine's own bundled `sig/` and answers
|
|
998
1374
|
# the filesystem question.
|
|
999
1375
|
#
|
|
1000
|
-
# @param plugin_id
|
|
1376
|
+
# @param plugin_id — a manifest id, e.g. `"activesupport-core-ext"`.
|
|
1001
1377
|
def bundled_overlay_twin_signatures_loaded?(plugin_id, signature_paths)
|
|
1002
1378
|
return false if signature_paths.nil? || signature_paths.empty?
|
|
1003
1379
|
|
|
@@ -1065,23 +1441,27 @@ module Rigor
|
|
|
1065
1441
|
end
|
|
1066
1442
|
end
|
|
1067
1443
|
|
|
1068
|
-
attr_reader :libraries, :signature_paths, :cache_store, :virtual_rbs
|
|
1444
|
+
attr_reader :libraries, :signature_paths, :cache_store, :virtual_rbs, :deferred_signature_paths
|
|
1069
1445
|
|
|
1070
|
-
# @param libraries
|
|
1446
|
+
# @param libraries — stdlib library names to load on top of core (e.g.,
|
|
1071
1447
|
# `["pathname", "json"]`). Empty by default. Each entry MUST correspond to a directory under the
|
|
1072
1448
|
# `rbs` gem's `stdlib/` tree; unknown names are silently dropped on environment build (the underlying
|
|
1073
1449
|
# `RBS::EnvironmentLoader` raises and we fail-soft).
|
|
1074
|
-
# @param signature_paths
|
|
1450
|
+
# @param signature_paths — additional directories of `.rbs` files to load
|
|
1075
1451
|
# (typically the project's `sig/` tree). Non-existent or non-directory paths are filtered out at
|
|
1076
1452
|
# build time so the loader stays robust to fixtures and bare repositories.
|
|
1077
|
-
# @param cache_store
|
|
1453
|
+
# @param cache_store — the persistent cache the loader threads through to
|
|
1078
1454
|
# `RbsEnvironment`, `RbsKnownClassNames`, `RbsConstantTable`, `RbsClassAncestorTable`, and
|
|
1079
1455
|
# `RbsClassTypeParamNames` producers. Pass `nil` (the default) to skip caching; the runner threads
|
|
1080
1456
|
# its own Store through here when enabled.
|
|
1081
|
-
# @param virtual_rbs
|
|
1457
|
+
# @param virtual_rbs — >] ADR-32 WD4 — `[virtual_filename, rbs_source]` pairs
|
|
1082
1458
|
# synthesised from project source by a plugin's `Manifest#source_rbs_synthesizer`. Merged into the
|
|
1083
1459
|
# env after `signature_paths:` and the vendored stubs. Pass `[]` (the default) when no
|
|
1084
1460
|
# synthesizer-emitting plugin is loaded.
|
|
1461
|
+
# @param deferred_signature_paths — the subset of `signature_paths:` a bundled plugin
|
|
1462
|
+
# contributed (issue #610): loaded last and allowed to stand down against a colliding generic
|
|
1463
|
+
# arity. Read back by the env-cache producer, which rebuilds the env from the loader's readers on
|
|
1464
|
+
# a miss — a list it cannot read is a stand-down that runs only on a `--no-cache` build.
|
|
1085
1465
|
def initialize(libraries: [], signature_paths: [], cache_store: nil, virtual_rbs: [],
|
|
1086
1466
|
deferred_signature_paths: [])
|
|
1087
1467
|
@libraries = libraries.map(&:to_s).freeze
|
|
@@ -1097,8 +1477,8 @@ module Rigor
|
|
|
1097
1477
|
# names currently consulted: `:env`, `:env_loaded`, `:env_build_warned`, `:definition_build_warned`,
|
|
1098
1478
|
# `:definition_build_details`, `:definition_build_reported`, `:definition_build_failures`,
|
|
1099
1479
|
# `:definition_build_deferred_count`, `:definition_build_deferred_first`,
|
|
1100
|
-
# `:definition_build_summary_warned`, `:
|
|
1101
|
-
# `:reflection`,
|
|
1480
|
+
# `:definition_build_summary_warned`, `:member_consistency`, `:member_consistency_proven`, `:internal_demand`,
|
|
1481
|
+
# `:internal_demand_status`, `:builder`, `:reflection`,
|
|
1102
1482
|
# `:instance_definitions_table`, `:singleton_definitions_table`.
|
|
1103
1483
|
# Constructed via `Hash.new` (NOT a `{ ... }` literal) so Rigor's `HashShape` narrowing doesn't
|
|
1104
1484
|
# infer a fixed key set from the initial state and fold post-initial slot reads (e.g.
|
|
@@ -1127,7 +1507,7 @@ module Rigor
|
|
|
1127
1507
|
# the stderr banner) reads it, and a cache HIT reaches it too — the env was built with the file already
|
|
1128
1508
|
# quarantined, so the condition is invisible in the cached env itself.
|
|
1129
1509
|
#
|
|
1130
|
-
# @return
|
|
1510
|
+
# @return empty when every `signature_paths:` file parses.
|
|
1131
1511
|
def quarantined_signatures
|
|
1132
1512
|
@state[:quarantined] ||= begin
|
|
1133
1513
|
parse_quarantined = self.class.quarantined_project_signatures(@signature_paths)
|
|
@@ -1135,17 +1515,24 @@ module Rigor
|
|
|
1135
1515
|
@state[:env], @signature_paths
|
|
1136
1516
|
)
|
|
1137
1517
|
parse_paths = parse_quarantined.to_set { |path, _note| path }
|
|
1518
|
+
# Issue #610 — a deferred file that STOOD DOWN is absent from the env by design, which is exactly
|
|
1519
|
+
# what the collision derivation reads as "quarantined". Derived from the same env, so a cache HIT
|
|
1520
|
+
# excludes it too; {#signature_standdowns} is where it is reported instead.
|
|
1521
|
+
stood_down = self.class.deferred_standdowns(@state[:env], @deferred_signature_paths).to_set(&:first)
|
|
1138
1522
|
(
|
|
1139
1523
|
parse_quarantined +
|
|
1140
|
-
collision_quarantined.reject
|
|
1524
|
+
collision_quarantined.reject do |entry|
|
|
1525
|
+
parse_paths.include?(entry[0]) || stood_down.include?(entry[0])
|
|
1526
|
+
end
|
|
1141
1527
|
).freeze
|
|
1142
1528
|
end
|
|
1143
1529
|
end
|
|
1144
1530
|
|
|
1145
1531
|
# Issue #610 — plugin-contributed signature files that stood down against a colliding generic arity,
|
|
1146
|
-
# as `[absolute_path, class_name, existing_arity, incoming_arity]`. Empty whenever no
|
|
1147
|
-
# collides, which is every project that has not run `rbs collection install` for a gem a
|
|
1148
|
-
# plugin also declares.
|
|
1532
|
+
# as `[absolute_path, class_name, existing_arity, incoming_arity, existing_file]`. Empty whenever no
|
|
1533
|
+
# plugin sig collides, which is every project that has not run `rbs collection install` for a gem a
|
|
1534
|
+
# bundled plugin also declares. Reported as `rbs.coverage.plugin-signature-stood-down` (`:info`); the
|
|
1535
|
+
# same file MUST NOT also appear in {#quarantined_signatures}.
|
|
1149
1536
|
def signature_standdowns
|
|
1150
1537
|
@state[:signature_standdowns] ||= self.class.deferred_standdowns(env, @deferred_signature_paths).freeze
|
|
1151
1538
|
end
|
|
@@ -1185,11 +1572,94 @@ module Rigor
|
|
|
1185
1572
|
end
|
|
1186
1573
|
private :build_project_declared_classes
|
|
1187
1574
|
|
|
1575
|
+
# Issue #527 — the class / module names whose PRIMARY declaration lives in the `rbs` gem's own
|
|
1576
|
+
# `core/` or `stdlib/` tree, top-level prefix stripped.
|
|
1577
|
+
#
|
|
1578
|
+
# The distinction it draws is narrower than {#project_declared_classes}'s: not "who wrote this
|
|
1579
|
+
# signature" but "is this Ruby's own documented surface". A core / stdlib signature is the method
|
|
1580
|
+
# set every negative check rule already trusts for a direct receiver of the class, which is what
|
|
1581
|
+
# lets a Ruby-source SUBCLASS of one resolve its inherited calls there (`RbsDispatch`'s
|
|
1582
|
+
# `core_stdlib_ancestor_method`). A GEM's RBS is a different claim — routinely partial, which is
|
|
1583
|
+
# ADR-43's whole reason for declining blanket inherited resolution — so it is deliberately outside
|
|
1584
|
+
# this set even when the gem ships signatures and even when it is one of {DEFAULT_LIBRARIES}
|
|
1585
|
+
# (`prism`, `rbs` are gems whose signatures ship with the gem, not entries of rbs's `stdlib/`).
|
|
1586
|
+
#
|
|
1587
|
+
# Attribution is by buffer NAME, the same mechanism and the same limits as
|
|
1588
|
+
# {#project_declared_classes}: it survives the ADR-54 environment cache, and an old blob's
|
|
1589
|
+
# `<cached>` sentinel lands every class OUTSIDE the set — the feature switches off rather than
|
|
1590
|
+
# widening, which is the direction ADR-5 wants. Memoised per loader; one pass over `class_decls`.
|
|
1591
|
+
def core_stdlib_classes
|
|
1592
|
+
@state[:core_stdlib_classes] ||= build_core_stdlib_classes
|
|
1593
|
+
end
|
|
1594
|
+
|
|
1595
|
+
def build_core_stdlib_classes
|
|
1596
|
+
environment = env
|
|
1597
|
+
return Set.new.freeze if environment.nil? || CORE_STDLIB_ROOTS.empty?
|
|
1598
|
+
|
|
1599
|
+
names = environment.class_decls.each_with_object(Set.new) do |(rbs_name, entry), acc|
|
|
1600
|
+
decl = self.class.primary_decl_for(entry)
|
|
1601
|
+
next if decl.nil?
|
|
1602
|
+
|
|
1603
|
+
path = self.class.declaration_buffer_name(decl)
|
|
1604
|
+
next if path.nil?
|
|
1605
|
+
|
|
1606
|
+
acc << rbs_name.to_s.delete_prefix("::") if CORE_STDLIB_ROOTS.any? { |root| path.start_with?(root) }
|
|
1607
|
+
end
|
|
1608
|
+
names.freeze
|
|
1609
|
+
rescue ::RBS::BaseError
|
|
1610
|
+
Set.new.freeze
|
|
1611
|
+
end
|
|
1612
|
+
private :build_core_stdlib_classes
|
|
1613
|
+
|
|
1614
|
+
# True when `class_name` is declared by Ruby core or a stdlib library (see {#core_stdlib_classes}).
|
|
1615
|
+
def core_or_stdlib_class?(class_name)
|
|
1616
|
+
core_stdlib_classes.include?(class_name.to_s.delete_prefix("::"))
|
|
1617
|
+
end
|
|
1618
|
+
|
|
1188
1619
|
# True when `class_name`'s RBS declaration is one the project wrote (see {#project_declared_classes}).
|
|
1189
1620
|
def project_declared_class?(class_name)
|
|
1190
1621
|
project_declared_classes.include?(class_name.to_s.delete_prefix("::"))
|
|
1191
1622
|
end
|
|
1192
1623
|
|
|
1624
|
+
# Issue #1362 — the translated type of the RBS declaration of the global variable `name` (`:$stdout`, declared
|
|
1625
|
+
# `IO` by the core signatures), or nil when no loaded signature declares it. Translated without an alias
|
|
1626
|
+
# expander, as {#constant_type} translates a constant, so `$DEBUG: boolish` reads `Dynamic[top]` rather than
|
|
1627
|
+
# `top`.
|
|
1628
|
+
def global_type(name)
|
|
1629
|
+
global_declarations[name.to_sym]&.first
|
|
1630
|
+
end
|
|
1631
|
+
|
|
1632
|
+
# True when `name`'s RBS declaration lives in the `rbs` gem's own `core/` or `stdlib/` tree: a global the
|
|
1633
|
+
# interpreter or a default library sets. Attributed by buffer name, as {#core_or_stdlib_class?} is, with the
|
|
1634
|
+
# same limit: an environment blob without buffer names answers false for every global.
|
|
1635
|
+
def core_or_stdlib_global?(name)
|
|
1636
|
+
global_declarations[name.to_sym]&.last || false
|
|
1637
|
+
end
|
|
1638
|
+
|
|
1639
|
+
# `name => [type, core_or_stdlib]` for every global the environment declares; a declaration whose type
|
|
1640
|
+
# translates to `bot` is left out. Memoised per loader: the core signatures declare about fifty.
|
|
1641
|
+
def global_declarations
|
|
1642
|
+
@state[:global_declarations] ||= build_global_declarations
|
|
1643
|
+
end
|
|
1644
|
+
private :global_declarations
|
|
1645
|
+
|
|
1646
|
+
def build_global_declarations
|
|
1647
|
+
environment = env
|
|
1648
|
+
return {}.freeze if environment.nil?
|
|
1649
|
+
|
|
1650
|
+
table = environment.global_decls.each_with_object({}) do |(name, entry), acc|
|
|
1651
|
+
type = Inference::RbsTypeTranslator.translate(entry.decl.type)
|
|
1652
|
+
next if type.is_a?(Type::Bot)
|
|
1653
|
+
|
|
1654
|
+
path = self.class.declaration_buffer_name(entry.decl)
|
|
1655
|
+
acc[name.to_sym] = [type, !path.nil? && CORE_STDLIB_ROOTS.any? { |root| path.start_with?(root) }].freeze
|
|
1656
|
+
end
|
|
1657
|
+
table.freeze
|
|
1658
|
+
rescue ::RBS::BaseError
|
|
1659
|
+
{}.freeze
|
|
1660
|
+
end
|
|
1661
|
+
private :build_global_declarations
|
|
1662
|
+
|
|
1193
1663
|
# The total RBS-environment build failure captured this run, or nil when the env built. Unlike
|
|
1194
1664
|
# {#quarantined_signatures} — which the env survives, one file lighter, and which is re-derived so a
|
|
1195
1665
|
# cache HIT reports it too — a total failure collapses the WHOLE env to nil. Project-vs-bundled
|
|
@@ -1199,7 +1669,7 @@ module Rigor
|
|
|
1199
1669
|
# persisted, so every run re-attempts and re-raises), so this is captured directly in {#env}'s rescue
|
|
1200
1670
|
# rather than re-derived. Forcing `env` (any query does) populates it.
|
|
1201
1671
|
#
|
|
1202
|
-
# @return
|
|
1672
|
+
# @return `[error_class_name, first_error_line,
|
|
1203
1673
|
# conflicting_buffer_names]`, or nil when the environment built successfully.
|
|
1204
1674
|
def env_build_failure
|
|
1205
1675
|
env unless @state[:env_loaded]
|
|
@@ -1223,9 +1693,10 @@ module Rigor
|
|
|
1223
1693
|
# definition-build failure leaves no trace in the env at all — the env is fine; it is the BUILD over it
|
|
1224
1694
|
# that raised — so the rescue is the only place that ever knows.
|
|
1225
1695
|
#
|
|
1226
|
-
# @return [
|
|
1227
|
-
#
|
|
1228
|
-
#
|
|
1696
|
+
# @return `[class_name, error_class_name, member, conflicting_buffer_names,
|
|
1697
|
+
# unresolved_type_name_detail]`, one per class, in first-failure order (issue #997 added the fifth
|
|
1698
|
+
# slot; see {#unresolved_type_name_detail} — `nil` there for every failure kind but an unresolvable
|
|
1699
|
+
# type name). Empty for a healthy sig set, which is the common case.
|
|
1229
1700
|
def definition_build_failures
|
|
1230
1701
|
(@state[:definition_build_failures] || []).dup.freeze
|
|
1231
1702
|
end
|
|
@@ -1237,7 +1708,7 @@ module Rigor
|
|
|
1237
1708
|
# the {#quarantined_signatures} trick — so a cache HIT, which never runs the build, reports the same
|
|
1238
1709
|
# condition: the marshalled env simply lacks the dropped buffers.
|
|
1239
1710
|
#
|
|
1240
|
-
# @return
|
|
1711
|
+
# @return virtual buffer names (source-file paths) whose contribution was dropped.
|
|
1241
1712
|
def virtual_rbs_collision_quarantined
|
|
1242
1713
|
@state[:virtual_rbs_collisions] ||= begin
|
|
1243
1714
|
built = @state[:env]
|
|
@@ -1252,6 +1723,29 @@ module Rigor
|
|
|
1252
1723
|
end
|
|
1253
1724
|
end
|
|
1254
1725
|
|
|
1726
|
+
# Issue #1075 / ADR-112 WD5 — one {MemberConsistency::Record} per `(class, method, kind)` the project's
|
|
1727
|
+
# own `signature_paths:` and an inline (rbs-inline) source both declare, saying which side bound and
|
|
1728
|
+
# why, plus one per `rigor:v1:return:` / `rigor:v1:param:` refinement that exceeds its member's own
|
|
1729
|
+
# declared type. The rest of the file's annotations still bind either way, and the class keeps its
|
|
1730
|
+
# method surface instead of failing its definition build.
|
|
1731
|
+
#
|
|
1732
|
+
# The sibling of {#virtual_rbs_collision_quarantined} one granularity finer: that one names a whole
|
|
1733
|
+
# inline FILE dropped for a class-level duplicate, this one names a single member. Both are derived
|
|
1734
|
+
# rather than recorded, so a cache HIT — where no build ran — reports the same condition; here the
|
|
1735
|
+
# derivation reads the loader's inputs rather than the built env, because a stripped member leaves no
|
|
1736
|
+
# trace in the env at all.
|
|
1737
|
+
#
|
|
1738
|
+
# @return the records, sorted. Empty (and free) whenever the project contributes no inline RBS.
|
|
1739
|
+
#
|
|
1740
|
+
# @param proof — a {MemberConsistency::RbsProof} over this loader, without which no pair is reported
|
|
1741
|
+
# as a contradiction (only the severity of a row depends on it, never which declaration binds).
|
|
1742
|
+
def member_consistency(proof: nil)
|
|
1743
|
+
key = proof ? :member_consistency_proven : :member_consistency
|
|
1744
|
+
@state[key] ||= self.class.member_consistency_for(
|
|
1745
|
+
self.class.project_sig_files(@signature_paths), @virtual_rbs, proof: proof
|
|
1746
|
+
).records
|
|
1747
|
+
end
|
|
1748
|
+
|
|
1255
1749
|
# The referenced-but-undeclared types {.stub_missing_referenced_types} stubbed so the project classes
|
|
1256
1750
|
# that mention them could build (e.g. an unavailable `DRb::DRbServer`, or a stale
|
|
1257
1751
|
# `Textbringer::EditorError`). Recovered off the built env like {#synthesized_namespaces}, so it
|
|
@@ -1415,7 +1909,7 @@ module Rigor
|
|
|
1415
1909
|
{}.freeze
|
|
1416
1910
|
end
|
|
1417
1911
|
|
|
1418
|
-
# @return
|
|
1912
|
+
# @return the resolved instance definition for `class_name`, or nil when the
|
|
1419
1913
|
# class is unknown or its definition cannot be built (RBS may raise on broken hierarchies; we
|
|
1420
1914
|
# fail-soft and return nil so the caller can fall back).
|
|
1421
1915
|
#
|
|
@@ -1441,7 +1935,6 @@ module Rigor
|
|
|
1441
1935
|
definition
|
|
1442
1936
|
end
|
|
1443
1937
|
|
|
1444
|
-
# @return [RBS::Definition::Method, nil]
|
|
1445
1938
|
def instance_method(class_name:, method_name:)
|
|
1446
1939
|
definition = instance_definition(class_name)
|
|
1447
1940
|
return nil unless definition
|
|
@@ -1449,7 +1942,7 @@ module Rigor
|
|
|
1449
1942
|
definition.methods[method_name.to_sym]
|
|
1450
1943
|
end
|
|
1451
1944
|
|
|
1452
|
-
# @return
|
|
1945
|
+
# @return every instance-method name on `class_name` — own, inherited, and
|
|
1453
1946
|
# included — as resolved by `RBS::DefinitionBuilder`. Returns `nil` (NOT `[]`) when the class
|
|
1454
1947
|
# definition cannot be built so callers can tell "no methods" apart from "unknown class". Used by the
|
|
1455
1948
|
# `rigor:v1:conforms-to` presence check ({Rigor::RbsExtended::ConformanceChecker}).
|
|
@@ -1460,7 +1953,7 @@ module Rigor
|
|
|
1460
1953
|
definition.methods.keys
|
|
1461
1954
|
end
|
|
1462
1955
|
|
|
1463
|
-
# @return
|
|
1956
|
+
# @return the built definition for the RBS interface `interface_name`
|
|
1464
1957
|
# (`_RewindableStream`), whose `.methods` are the required members (including interface-ancestor
|
|
1465
1958
|
# members). Returns `nil` when the name does not resolve to a loaded interface (a typo, or the
|
|
1466
1959
|
# defining library / sig set is not on the load path). Fail-soft on RBS build errors.
|
|
@@ -1475,15 +1968,15 @@ module Rigor
|
|
|
1475
1968
|
nil
|
|
1476
1969
|
end
|
|
1477
1970
|
|
|
1478
|
-
# @return
|
|
1971
|
+
# @return every method name required by the RBS interface `interface_name`, or nil
|
|
1479
1972
|
# when it does not resolve. Thin accessor over {#interface_definition} for the presence check.
|
|
1480
1973
|
def interface_method_names(interface_name)
|
|
1481
1974
|
interface_definition(interface_name)&.methods&.keys
|
|
1482
1975
|
end
|
|
1483
1976
|
|
|
1484
|
-
# @param rbs_alias
|
|
1977
|
+
# @param rbs_alias — a type-alias reference (`string`, `int`, `range[int?]`, …)
|
|
1485
1978
|
# appearing in a method signature.
|
|
1486
|
-
# @return
|
|
1979
|
+
# @return the alias's aliased type one level out, with type arguments substituted
|
|
1487
1980
|
# for a generic alias (`string` → `::String | ::_ToStr`; `range[int?]` → `::Range[int?] |
|
|
1488
1981
|
# ::_Range[int?]`), or nil for an unresolved name. Lets a caller see through the alias that
|
|
1489
1982
|
# {Inference::RbsTypeTranslator} otherwise degrades to `untyped`, which is why an interface/alias
|
|
@@ -1508,7 +2001,7 @@ module Rigor
|
|
|
1508
2001
|
nil
|
|
1509
2002
|
end
|
|
1510
2003
|
|
|
1511
|
-
# @return
|
|
2004
|
+
# @return the resolved singleton (class object) definition for `class_name`. The
|
|
1512
2005
|
# methods on this definition are the *class methods* of `class_name`, including those inherited from
|
|
1513
2006
|
# `Class` and `Module` for class types. Returns nil for unknown names and on RBS build errors
|
|
1514
2007
|
# (fail-soft).
|
|
@@ -1529,7 +2022,37 @@ module Rigor
|
|
|
1529
2022
|
definition
|
|
1530
2023
|
end
|
|
1531
2024
|
|
|
1532
|
-
#
|
|
2025
|
+
# Issue #915 — the MODULE names in `class_name`'s singleton ancestry, as RBS declares it. A
|
|
2026
|
+
# `class C; extend M; end` written in a project's own `sig/` puts `M` there and nothing else in the
|
|
2027
|
+
# environment surface exposes it: {#ancestor_names_for} answers the instance side only.
|
|
2028
|
+
#
|
|
2029
|
+
# Modules only, deliberately. `RBS::DefinitionBuilder#build_singleton` mixes the extended modules in
|
|
2030
|
+
# with the singleton's class chain (`Class`, `Module`, `Object`, `BasicObject`), and the classes there
|
|
2031
|
+
# are already what the `Class` approximation in `Inference::Narrowing` reasons through. The modules
|
|
2032
|
+
# that survive the filter — the declared `extend` targets, plus `Kernel` through `Object` — are each a
|
|
2033
|
+
# true answer to `C.is_a?(M)`.
|
|
2034
|
+
#
|
|
2035
|
+
# Marked as an internal demand for the same reason {#ancestor_names_for} is (issue #696): asking
|
|
2036
|
+
# whether a module sits in an ancestry is not asking whether the class's method surface resolves, and
|
|
2037
|
+
# letting it report would make the reported class list depend on the cache state.
|
|
2038
|
+
#
|
|
2039
|
+
# @return `::`-stripped module names, or `[]` for an unknown class and on any RBS build error.
|
|
2040
|
+
def singleton_extended_module_names(class_name)
|
|
2041
|
+
key = class_name.to_s.delete_prefix("::")
|
|
2042
|
+
during_internal_demand do
|
|
2043
|
+
definition = singleton_definition(key)
|
|
2044
|
+
next [].freeze if definition.nil?
|
|
2045
|
+
|
|
2046
|
+
definition.ancestors.ancestors.filter_map do |ancestor|
|
|
2047
|
+
name = ancestor.name.to_s.delete_prefix("::")
|
|
2048
|
+
name if ancestor.is_a?(::RBS::Definition::Ancestor::Instance) && rbs_module?(name)
|
|
2049
|
+
end.uniq.freeze
|
|
2050
|
+
end
|
|
2051
|
+
rescue ::RBS::BaseError, StandardError
|
|
2052
|
+
[].freeze
|
|
2053
|
+
end
|
|
2054
|
+
|
|
2055
|
+
# @return the class method on `class_name`. For example,
|
|
1533
2056
|
# `singleton_method(class_name: "Integer", method_name: :sqrt)` returns the definition for
|
|
1534
2057
|
# `Integer.sqrt`, while `singleton_method(class_name: "Foo", method_name: :new)` returns Class#new
|
|
1535
2058
|
# for any class type.
|
|
@@ -1553,18 +2076,29 @@ module Rigor
|
|
|
1553
2076
|
# process) through {Cache::RbsClassTypeParamNames.fetch} and answers point lookups from it. Cold runs
|
|
1554
2077
|
# build the table once and persist it; warm runs (and a separate loader sharing the same Store) skip
|
|
1555
2078
|
# the env walk entirely.
|
|
2079
|
+
#
|
|
2080
|
+
# #775 — memoised per class name and answered as a frozen list. `RBS::Definition#type_params` is not
|
|
2081
|
+
# an accessor: it re-derives the names through the entry's type-param declarations (a substitution
|
|
2082
|
+
# per call), and generic dispatch asks for the receiver class's names on every call (~110k times on
|
|
2083
|
+
# the lib self-check, the largest remaining rbs-side allocation). The env is immutable for the
|
|
2084
|
+
# loader's lifetime, so the answer never changes; every consumer only reads it.
|
|
1556
2085
|
def class_type_param_names(class_name)
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
end
|
|
1561
|
-
|
|
1562
|
-
definition = instance_definition(class_name)
|
|
1563
|
-
return [] unless definition
|
|
2086
|
+
memo = (@state[:type_param_names] ||= {})
|
|
2087
|
+
key = class_name.to_s
|
|
2088
|
+
return memo[key] if memo.key?(key)
|
|
1564
2089
|
|
|
1565
|
-
|
|
2090
|
+
memo[key] =
|
|
2091
|
+
if cache_store
|
|
2092
|
+
type_param_names_table.fetch(key.delete_prefix("::"), NO_TYPE_PARAMS).freeze
|
|
2093
|
+
else
|
|
2094
|
+
definition = instance_definition(class_name)
|
|
2095
|
+
definition ? definition.type_params.freeze : NO_TYPE_PARAMS
|
|
2096
|
+
end
|
|
1566
2097
|
end
|
|
1567
2098
|
|
|
2099
|
+
NO_TYPE_PARAMS = [].freeze
|
|
2100
|
+
private_constant :NO_TYPE_PARAMS
|
|
2101
|
+
|
|
1568
2102
|
def class_ordering(lhs, rhs)
|
|
1569
2103
|
@hierarchy.class_ordering(lhs, rhs)
|
|
1570
2104
|
end
|
|
@@ -1595,7 +2129,7 @@ module Rigor
|
|
|
1595
2129
|
# way, and both yield `[]` for an unknown or unbuildable class. Pinned by spec across all three cache
|
|
1596
2130
|
# states.
|
|
1597
2131
|
#
|
|
1598
|
-
# @return
|
|
2132
|
+
# @return `::`-stripped ancestor names, or `[]` for an unknown or unbuildable class.
|
|
1599
2133
|
def ancestor_names_for(class_name)
|
|
1600
2134
|
key = class_name.to_s.delete_prefix("::")
|
|
1601
2135
|
during_internal_demand do
|
|
@@ -1610,7 +2144,7 @@ module Rigor
|
|
|
1610
2144
|
[].freeze
|
|
1611
2145
|
end
|
|
1612
2146
|
|
|
1613
|
-
# @return
|
|
2147
|
+
# @return every RBS-declared constant name (top-level prefixed, e.g., `"::Math::PI"`)
|
|
1614
2148
|
# currently loaded into the environment. Used by the cache producer that materialises the
|
|
1615
2149
|
# constant-type table; ordinary callers should keep using {#constant_type} for point lookups.
|
|
1616
2150
|
def constant_names
|
|
@@ -1694,11 +2228,21 @@ module Rigor
|
|
|
1694
2228
|
# Building it digests every `.rbs` file under `signature_paths` + the vendored gem sigs, and the
|
|
1695
2229
|
# result is identical across producers, so one build is memoised per loader (on `@state`, alongside
|
|
1696
2230
|
# `:env` — the env itself is loader-lifetime-memoised, so this adds no new staleness class).
|
|
2231
|
+
#
|
|
2232
|
+
# Issue #1014 — nil when the engine's source cannot be digested ({Cache::EngineSource::Unavailable});
|
|
2233
|
+
# {Cache::RbsCacheProducer.fetch} then computes uncached. Memoised through `key?` rather than `||=` so
|
|
2234
|
+
# that answer is reached once: rebuilding it would re-digest the whole signature tree per producer to
|
|
2235
|
+
# arrive at the same nil.
|
|
1697
2236
|
def rbs_cache_descriptor
|
|
1698
|
-
@state[:rbs_cache_descriptor]
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
2237
|
+
return @state[:rbs_cache_descriptor] if @state.key?(:rbs_cache_descriptor)
|
|
2238
|
+
|
|
2239
|
+
require_relative "../cache/rbs_descriptor"
|
|
2240
|
+
@state[:rbs_cache_descriptor] =
|
|
2241
|
+
begin
|
|
2242
|
+
Cache::RbsDescriptor.build(self)
|
|
2243
|
+
rescue Cache::EngineSource::Unavailable
|
|
2244
|
+
nil
|
|
2245
|
+
end
|
|
1702
2246
|
end
|
|
1703
2247
|
|
|
1704
2248
|
# ADR-15 Phase 2b — return the loader's read-only query surface as a frozen, `Ractor.shareable?`
|
|
@@ -2066,7 +2610,60 @@ module Rigor
|
|
|
2066
2610
|
return if details.key?(key)
|
|
2067
2611
|
|
|
2068
2612
|
details[key] = [key, error.class.name.to_s, definition_build_member(error),
|
|
2069
|
-
definition_build_conflict_buffers(error)].freeze
|
|
2613
|
+
definition_build_conflict_buffers(error), unresolved_type_name_detail(error)].freeze
|
|
2614
|
+
end
|
|
2615
|
+
|
|
2616
|
+
# Issue #997 — the `RBS::NoTypeFoundError` twin of {#definition_build_member}: `nil` for every other
|
|
2617
|
+
# error class, so the cached tuple gains a populated fifth slot only for the failure kind it
|
|
2618
|
+
# distinguishes — "one declaration names a type that does not exist" from "two declarations collide"
|
|
2619
|
+
# ({DiagnosticAggregator#definition_build_advice}, which folds this in).
|
|
2620
|
+
#
|
|
2621
|
+
# Computed once, at RAISE time, and frozen into the cached detail rather than re-derived when a warm
|
|
2622
|
+
# run replays the tuple from {IncrementalSnapshot} — there is no live `RBS::NoTypeFoundError` to
|
|
2623
|
+
# re-inspect on that path, only the plain strings this method already reduced it to.
|
|
2624
|
+
#
|
|
2625
|
+
# `[token, location, refinement_hint]`:
|
|
2626
|
+
# - `token` is the unresolved name exactly as `RBS::NoTypeFoundError#type_name` carries it — the ONLY
|
|
2627
|
+
# name that ever reaches RBS. A hyphenated payload (`finite-float`) is truncated to its first
|
|
2628
|
+
# segment by rbs-inline's own tolerant type parse (`RBS::Parser.parse_type(..., require_eof: false)`
|
|
2629
|
+
# stops at the first complete type and silently discards the rest), so `-float` never becomes a
|
|
2630
|
+
# token RBS itself can name or complain about.
|
|
2631
|
+
# - `location` is `error.location.to_s` verbatim (`"virtual:rbs-inline:<path>:line:col...line:col"`)
|
|
2632
|
+
# — the position the error already carries, per issue #997, named rather than re-derived. It is a
|
|
2633
|
+
# position in the SYNTHESIZED buffer for an inline annotation, not necessarily the `.rb` line the
|
|
2634
|
+
# author wrote: {Effects::InlineAnchor} maps a known `%a{...}` spelling back by ordinal, which does
|
|
2635
|
+
# not apply to an arbitrary broken type token, so no such mapping is attempted here.
|
|
2636
|
+
# - `refinement_hint` is the full compound name (`"finite-float"`) when the SAME synthesized buffer —
|
|
2637
|
+
# rbs-inline re-emits the author's original `# @rbs name: TYPE` comment verbatim above the member it
|
|
2638
|
+
# generates — carries `token` immediately followed by a hyphenated continuation that is ITSELF a
|
|
2639
|
+
# registered {Builtins::ImportedRefinements} name; `nil` otherwise. Exact-match only: a near-miss
|
|
2640
|
+
# compound name says nothing, so a coincidental `token-suffix` that is not a real refinement can
|
|
2641
|
+
# never manufacture a misleading "did you mean" (false positives outrank worst-case reading).
|
|
2642
|
+
def unresolved_type_name_detail(error)
|
|
2643
|
+
return nil unless error.is_a?(::RBS::NoTypeFoundError)
|
|
2644
|
+
|
|
2645
|
+
token = error.type_name.to_s.delete_prefix("::")
|
|
2646
|
+
[token, error.location&.to_s, refinement_hint_for(token, error)].freeze
|
|
2647
|
+
rescue ::RBS::BaseError, StandardError
|
|
2648
|
+
nil
|
|
2649
|
+
end
|
|
2650
|
+
|
|
2651
|
+
# The buffer rbs-inline synthesized still carries the author's own comment line verbatim (the
|
|
2652
|
+
# "annotation echo" {Effects::InlineAnchor} documents), so a hyphenated refinement name truncated out
|
|
2653
|
+
# of the parsed type ({#unresolved_type_name_detail}) is still readable a few characters further along
|
|
2654
|
+
# the SAME text the error's own location already points into.
|
|
2655
|
+
def refinement_hint_for(token, error)
|
|
2656
|
+
return nil if token.empty?
|
|
2657
|
+
|
|
2658
|
+
content = error.location&.buffer&.content
|
|
2659
|
+
return nil if content.nil?
|
|
2660
|
+
|
|
2661
|
+
candidate = content[/\b#{Regexp.escape(token)}-[A-Za-z0-9][\w-]*/]
|
|
2662
|
+
return nil if candidate.nil?
|
|
2663
|
+
|
|
2664
|
+
Builtins::ImportedRefinements.known?(candidate) ? candidate : nil
|
|
2665
|
+
rescue ::RBS::BaseError, StandardError
|
|
2666
|
+
nil
|
|
2070
2667
|
end
|
|
2071
2668
|
|
|
2072
2669
|
# Issue #696 — the REPORTING half: promote a remembered detail into {#definition_build_failures}
|
|
@@ -2276,8 +2873,6 @@ module Rigor
|
|
|
2276
2873
|
# `#method_name`; `UnknownMethodAliasError` and `NoSuperclassFoundError` have `#type_name`;
|
|
2277
2874
|
# `SuperclassMismatchError` has `#name`. `RecursiveAncestorError` has none of them and yields nil, and
|
|
2278
2875
|
# the diagnostic then omits the clause rather than inventing one.
|
|
2279
|
-
#
|
|
2280
|
-
# @return [String, nil]
|
|
2281
2876
|
def definition_build_member(error)
|
|
2282
2877
|
return error.qualified_method_name.to_s if error.respond_to?(:qualified_method_name)
|
|
2283
2878
|
|