rigortype 0.4.7 → 0.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/data/core_overlay/bigdecimal.rbs +33 -0
- data/data/core_overlay/resolv.rbs +30 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +29 -0
- data/data/gem_overlay/addressable/addressable.rbs +40 -0
- data/docs/handbook/01-getting-started.md +1 -1
- data/docs/handbook/11-sig-gen.md +35 -0
- data/docs/install.md +20 -0
- data/docs/manual/01-installation.md +67 -26
- data/docs/manual/02-cli-reference.md +307 -91
- data/docs/manual/03-configuration.md +41 -3
- data/docs/manual/04-diagnostics.md +5 -4
- data/docs/manual/08-skills.md +11 -0
- data/docs/manual/09-editor-integration.md +8 -0
- data/docs/manual/14-rails-quickstart.md +1 -1
- data/docs/manual/19-effect-labels.md +3 -4
- data/docs/manual/plugins/rigor-actionpack.md +15 -6
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +3 -0
- data/docs/manual/plugins/rigor-sorbet.md +17 -3
- data/lib/rigor/analysis/check_rules/always_raises_shield.rb +147 -0
- data/lib/rigor/analysis/check_rules/call_facts.rb +58 -0
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +8 -0
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +13 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +6 -0
- data/lib/rigor/analysis/check_rules/plugin_api_surface.rb +195 -0
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +40 -11
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +27 -1
- data/lib/rigor/analysis/check_rules/replaced_singleton_defs.rb +96 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +8 -1
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules.rb +598 -99
- data/lib/rigor/analysis/crash_signature.rb +43 -1
- data/lib/rigor/analysis/dependency_recorder.rb +233 -76
- data/lib/rigor/analysis/incremental.rb +11 -1
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +2 -1
- data/lib/rigor/analysis/incremental_session.rb +279 -37
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -3
- data/lib/rigor/analysis/rule_catalog.rb +37 -1
- data/lib/rigor/analysis/run_cache_key.rb +27 -3
- data/lib/rigor/analysis/run_disclosure_credit.rb +26 -6
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +4 -0
- data/lib/rigor/analysis/runner/declaration_position.rb +7 -7
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +72 -20
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +3 -8
- data/lib/rigor/analysis/runner/pool_coordinator.rb +26 -5
- data/lib/rigor/analysis/runner/project_pre_passes.rb +4 -37
- data/lib/rigor/analysis/runner.rb +222 -39
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +61 -22
- data/lib/rigor/analysis/worker_session.rb +42 -41
- data/lib/rigor/bleeding_edge.rb +19 -4
- data/lib/rigor/cache/file_digest.rb +39 -31
- data/lib/rigor/cache/incremental_snapshot.rb +66 -7
- data/lib/rigor/cache/rbs_descriptor.rb +37 -2
- data/lib/rigor/cache/rbs_environment.rb +5 -1
- data/lib/rigor/cli/baseline_command.rb +15 -2
- data/lib/rigor/cli/check_command.rb +4 -2
- data/lib/rigor/cli/effects_snapshot_command.rb +8 -1
- data/lib/rigor/cli/lens_command.rb +17 -2
- data/lib/rigor/cli/sig_gen_command.rb +8 -0
- data/lib/rigor/cli/skill_describe.rb +1 -0
- data/lib/rigor/cli.rb +5 -2
- data/lib/rigor/config_audit.rb +32 -18
- data/lib/rigor/configuration/severity_profile.rb +9 -0
- data/lib/rigor/configuration.rb +32 -5
- data/lib/rigor/effects/collector.rb +53 -21
- data/lib/rigor/environment/bundle_sig_discovery.rb +63 -28
- data/lib/rigor/environment/constant_type_cache_holder.rb +5 -0
- data/lib/rigor/environment/default_libraries.rb +17 -0
- data/lib/rigor/environment/deferred_signature_plan.rb +104 -6
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -0
- data/lib/rigor/environment/rbs_collection_discovery.rb +123 -8
- data/lib/rigor/environment/rbs_coverage_report.rb +12 -11
- data/lib/rigor/environment/rbs_hierarchy.rb +6 -0
- data/lib/rigor/environment/rbs_loader.rb +312 -63
- data/lib/rigor/environment.rb +131 -35
- data/lib/rigor/inference/acceptance.rb +50 -15
- data/lib/rigor/inference/alias_mutation_floor/foreign_locals.rb +117 -0
- data/lib/rigor/inference/alias_mutation_floor/memos.rb +85 -0
- data/lib/rigor/inference/alias_mutation_floor/reach.rb +119 -0
- data/lib/rigor/inference/alias_mutation_floor/site_collector.rb +252 -0
- data/lib/rigor/inference/alias_mutation_floor.rb +339 -0
- data/lib/rigor/inference/anonymous_meta_class.rb +18 -0
- data/lib/rigor/inference/block_auto_splat.rb +1 -1
- data/lib/rigor/inference/block_run_count.rb +9 -2
- data/lib/rigor/inference/builtins/array_catalog.rb +2 -2
- data/lib/rigor/inference/callee_mutation_chain.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +2 -0
- data/lib/rigor/inference/census_foreign_block.rb +354 -0
- data/lib/rigor/inference/clause_widening.rb +1 -1
- data/lib/rigor/inference/closure_escape_analyzer.rb +11 -4
- data/lib/rigor/inference/construction_escape.rb +56 -15
- data/lib/rigor/inference/declaration_walk.rb +4 -0
- data/lib/rigor/inference/def_node_resolver.rb +32 -14
- data/lib/rigor/inference/def_return_typer.rb +1 -1
- data/lib/rigor/inference/definer_resolution.rb +15 -7
- data/lib/rigor/inference/definers_index.rb +72 -16
- data/lib/rigor/inference/error_info.rb +16 -0
- data/lib/rigor/inference/expression_typer.rb +1459 -287
- data/lib/rigor/inference/flow_tracer.rb +31 -14
- data/lib/rigor/inference/fork_map.rb +3 -0
- data/lib/rigor/inference/fresh_frame_blocks.rb +52 -1
- data/lib/rigor/inference/global_write_census.rb +8 -6
- data/lib/rigor/inference/in_effect_refinements.rb +7 -0
- data/lib/rigor/inference/indexed_narrowing.rb +57 -8
- data/lib/rigor/inference/ivar_writer_census.rb +106 -11
- data/lib/rigor/inference/key_presence_guard.rb +51 -25
- data/lib/rigor/inference/last_line/self_evidence.rb +30 -0
- data/lib/rigor/inference/last_line.rb +5 -2
- data/lib/rigor/inference/loop_value_record.rb +63 -15
- data/lib/rigor/inference/match_rebinding/frame.rb +11 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +74 -18
- data/lib/rigor/inference/match_rebinding.rb +21 -8
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +43 -29
- data/lib/rigor/inference/method_dispatcher/class_keyed_block_params.rb +65 -0
- data/lib/rigor/inference/method_dispatcher/core_enumerable_receiver.rb +44 -0
- data/lib/rigor/inference/method_dispatcher/declared_constructor.rb +151 -0
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/imprecise_argument.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/interface_shape.rb +181 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +12 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +409 -67
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +384 -64
- data/lib/rigor/inference/method_dispatcher/singleton_type_params.rb +104 -0
- data/lib/rigor/inference/method_dispatcher.rb +66 -18
- data/lib/rigor/inference/method_parameter_binder.rb +136 -56
- data/lib/rigor/inference/module_function_state/spellings.rb +2 -2
- data/lib/rigor/inference/module_function_state.rb +13 -2
- data/lib/rigor/inference/multi_target_binder.rb +1 -1
- data/lib/rigor/inference/mutation_widening.rb +44 -4
- data/lib/rigor/inference/narrowing.rb +201 -27
- data/lib/rigor/inference/operand_effects.rb +43 -2
- data/lib/rigor/inference/optimistic_origin.rb +133 -8
- data/lib/rigor/inference/origin_lookup.rb +1 -1
- data/lib/rigor/inference/precision_scanner.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +28 -10
- data/lib/rigor/inference/project_patched_methods.rb +65 -13
- data/lib/rigor/inference/project_patched_scanner.rb +120 -25
- data/lib/rigor/inference/project_patched_visibility.rb +39 -3
- data/lib/rigor/inference/rbs_type_translator.rb +68 -15
- data/lib/rigor/inference/receiver_writer_call.rb +67 -0
- data/lib/rigor/inference/recursion_rebinding.rb +157 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +56 -18
- data/lib/rigor/inference/refined_dispatch/own_method.rb +51 -17
- data/lib/rigor/inference/refined_dispatch.rb +13 -0
- data/lib/rigor/inference/reflective_ivar_write.rb +19 -11
- data/lib/rigor/inference/remover_holder_scan.rb +76 -22
- data/lib/rigor/inference/scope_indexer/class_cvars_collector.rb +13 -6
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +12 -11
- data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +188 -28
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +136 -9
- data/lib/rigor/inference/scope_indexer.rb +2079 -183
- data/lib/rigor/inference/self_call_ivar_writes.rb +26 -7
- data/lib/rigor/inference/self_preserving_block.rb +87 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +41 -6
- data/lib/rigor/inference/singleton_object_constant.rb +32 -2
- data/lib/rigor/inference/statement_evaluator.rb +970 -250
- data/lib/rigor/inference/string_mutation.rb +14 -0
- data/lib/rigor/inference/synthetic_method_scanner.rb +35 -11
- data/lib/rigor/inference/toplevel_def_census.rb +14 -6
- data/lib/rigor/inference/unknown_store_widening.rb +1 -1
- data/lib/rigor/inference/untyped_rejoin.rb +1 -1
- data/lib/rigor/inference/void_tail_summary.rb +29 -10
- data/lib/rigor/lens/claims/comparison.rb +78 -0
- data/lib/rigor/lens/claims/request.rb +131 -0
- data/lib/rigor/lens/claims/type_reader.rb +216 -0
- data/lib/rigor/lens/claims.rb +208 -0
- data/lib/rigor/lens/contract_reader.rb +5 -0
- data/lib/rigor/lens/document.rb +1 -1
- data/lib/rigor/lens/file_reader.rb +21 -8
- data/lib/rigor/lens/run.rb +8 -0
- data/lib/rigor/lens.rb +1 -1
- data/lib/rigor/library_probe.rb +68 -0
- data/lib/rigor/memo_audit.rb +282 -0
- data/lib/rigor/plugin/base.rb +15 -2
- data/lib/rigor/plugin/io_boundary.rb +25 -3
- data/lib/rigor/plugin/manifest.rb +7 -3
- data/lib/rigor/plugin/registry.rb +13 -2
- data/lib/rigor/plugin/trust_policy.rb +46 -0
- data/lib/rigor/protection/mutation_cache.rb +4 -1
- data/lib/rigor/reflection/constant_ancestors.rb +79 -22
- data/lib/rigor/reflection/declaration_collectors.rb +55 -0
- data/lib/rigor/reflection/declarations.rb +58 -0
- data/lib/rigor/reflection/project_method.rb +177 -0
- data/lib/rigor/reflection.rb +2 -0
- data/lib/rigor/rooted_glob.rb +18 -1
- data/lib/rigor/run_scoped_slots.rb +20 -20
- data/lib/rigor/scope/discovery_index.rb +149 -2
- data/lib/rigor/scope/resolution_chain/relevance.rb +14 -1
- data/lib/rigor/scope/resolution_chain.rb +900 -55
- data/lib/rigor/scope.rb +307 -34
- data/lib/rigor/sig_gen/bot_proposal_guard.rb +306 -0
- data/lib/rigor/sig_gen/classification.rb +14 -1
- data/lib/rigor/sig_gen/generator.rb +222 -13
- data/lib/rigor/sig_gen/method_candidate.rb +14 -0
- data/lib/rigor/sig_gen/observation_collector.rb +11 -2
- data/lib/rigor/sig_gen/platform_guarded_files.rb +184 -0
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +47 -0
- data/lib/rigor/sig_gen/writer.rb +21 -0
- data/lib/rigor/sig_gen.rb +1 -0
- data/lib/rigor/source/forwardable_delegators.rb +122 -0
- data/lib/rigor/source/node_children.rb +13 -0
- data/lib/rigor/type/combinator.rb +164 -8
- data/lib/rigor/type/interface.rb +60 -0
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_of_memo/serving.rb +99 -0
- data/lib/rigor/type_of_memo/stats.rb +43 -0
- data/lib/rigor/type_of_memo.rb +337 -0
- data/lib/rigor/typing_state.rb +1094 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +2 -2
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +57 -25
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +3 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +25 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +16 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +4 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +2 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +130 -30
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +20 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +7 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +49 -13
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +19 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +4 -2
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +13 -5
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +29 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_collector.rb +15 -21
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +1 -6
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +4 -2
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +12 -2
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +6 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +199 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +3 -2
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +209 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +146 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +52 -34
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +80 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_collector.rb +16 -16
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +1 -6
- data/sig/rigor/analysis/check_rules/rule_walk.rbs +6 -0
- data/sig/rigor/analysis/fact_store.rbs +2 -3
- data/sig/rigor/cache/descriptor.rbs +14 -0
- data/sig/rigor/environment.rbs +4 -1
- data/sig/rigor/plugin/base.rbs +53 -19
- data/sig/rigor/plugin/interfaces.rbs +51 -0
- data/sig/rigor/plugin/io_boundary.rbs +2 -3
- data/sig/rigor/plugin/node_context.rbs +21 -0
- data/sig/rigor/reflection.rbs +37 -0
- data/sig/rigor/scope.rbs +22 -3
- data/sig/rigor/trinary.rbs +1 -0
- data/sig/rigor/type.rbs +9 -3
- data/sig/rigor.rbs +3 -2
- data/skills/rigor-ask/SKILL.md +1 -0
- data/skills/rigor-project-init/references/01-detect.md +1 -0
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +5 -1
- data/skills/rigor-project-init/references/06-agent-contract.md +4 -4
- data/skills/rigor-rbs-contract/SKILL.md +147 -0
- data/skills/rigor-rbs-contract/references/01-finding-candidates.md +212 -0
- data/skills/rigor-rbs-contract/references/02-contract-rules.md +157 -0
- data/skills/rigor-rbs-contract/references/03-target-own-code.md +90 -0
- data/skills/rigor-rbs-contract/references/04-target-gem-rbs-collection.md +210 -0
- data/skills/rigor-rbs-contract/references/05-declaration-mutants.md +182 -0
- data/skills/rigor-rbs-setup/SKILL.md +3 -1
- data/skills/rigor-type-oracle/SKILL.md +26 -1
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +4 -3
- metadata +48 -2
- data/lib/rigor/inference/memo_audit.rb +0 -55
|
@@ -15,6 +15,7 @@ require_relative "vendored_signature_plan"
|
|
|
15
15
|
require_relative "ruby_library_roots"
|
|
16
16
|
require_relative "core_root"
|
|
17
17
|
require_relative "../rooted_glob"
|
|
18
|
+
require_relative "../typing_state"
|
|
18
19
|
|
|
19
20
|
module Rigor
|
|
20
21
|
class Environment
|
|
@@ -35,6 +36,12 @@ module Rigor
|
|
|
35
36
|
# See docs/internal-spec/inference-engine.md for the binding contract.
|
|
36
37
|
# rubocop:disable-next Metrics/ClassLength
|
|
37
38
|
class RbsLoader
|
|
39
|
+
# ADR-129 G4 — keyed on the class name, answered from the loader's RBS environment (or, for `class_known?`, the
|
|
40
|
+
# known-name set cached for it), fixed for the loader's lifetime. `@state` is not declared: beside its lazy
|
|
41
|
+
# derivations it holds warn-once flags and failure counters.
|
|
42
|
+
TypingState.memo_field(self, :@instance_definition_cache, :@singleton_definition_cache, :@class_known_cache,
|
|
43
|
+
reason: "keyed on the class name; a function of the loader's RBS environment")
|
|
44
|
+
|
|
38
45
|
# Buffer name stamped on the `module` declarations synthesized by {.synthesize_missing_namespaces}.
|
|
39
46
|
# Re-read off the built env by {#synthesized_namespaces} so the analysis layer can surface an `:info`
|
|
40
47
|
# diagnostic naming the project's malformed-RBS namespaces — robust across the marshalled env cache,
|
|
@@ -63,13 +70,27 @@ module Rigor
|
|
|
63
70
|
.compact.map { |root| "#{root}/".freeze }.freeze
|
|
64
71
|
rescue StandardError
|
|
65
72
|
[].freeze
|
|
66
|
-
end
|
|
73
|
+
end.freeze
|
|
67
74
|
|
|
68
75
|
# Cap on how many quarantined `signature_paths:` files {#warn_about_quarantined_signatures} lists by name
|
|
69
76
|
# before collapsing the tail to "… and N more" — a broken generator can emit many, and a wall of parse
|
|
70
77
|
# errors buries the signal.
|
|
71
78
|
QUARANTINE_WARN_LIMIT = 10
|
|
72
79
|
|
|
80
|
+
# ADR-129 WD1 — a Frame: {.with_core_root} installs the core root for one environment build and restores the
|
|
81
|
+
# previous one on the way out. It changes answers (a loader built under it reads a different `core/`), and the
|
|
82
|
+
# installed value is a {CoreRoot.validate!}d frozen String or nil. Per thread (per fiber), so a concurrent build
|
|
83
|
+
# on another thread keeps its own.
|
|
84
|
+
CORE_ROOT = TypingState.frame(
|
|
85
|
+
:rbs_core_root,
|
|
86
|
+
reason: "installed per environment build by with_core_root; selects the core/ directory every loader of the " \
|
|
87
|
+
"build reads (a validated absolute path, or nil for the rbs gem's own)",
|
|
88
|
+
# G1′: the build installs the core root and reads it, and every analysing entry point builds the environment
|
|
89
|
+
# before anything types ({Environment.for_project}, `eager:`; #2883), so no `type_of` reads it.
|
|
90
|
+
typing_never_reads: true
|
|
91
|
+
)
|
|
92
|
+
private_constant :CORE_ROOT
|
|
93
|
+
|
|
73
94
|
class << self
|
|
74
95
|
# Issue #1902 — the fixed total order that picks ONE detail tuple for a class out of several: its two
|
|
75
96
|
# sides in {#report_definition_build_failure}, or a fresh and a replayed record in
|
|
@@ -105,9 +126,15 @@ module Rigor
|
|
|
105
126
|
# with it as an overload unless that source is the project's own ({DeferredSignaturePlan}).
|
|
106
127
|
# @param core_root — issue #2517 — a validated {CoreRoot} directory loaded in place of the `rbs` gem's
|
|
107
128
|
# `core/`, or nil for the default core.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
129
|
+
# @param subordinate_signature_paths — issue #2978 — the subset of `signature_paths` that loads right after
|
|
130
|
+
# the other `signature_paths` files and stands down member by member to them ({.add_project_signatures}).
|
|
131
|
+
# @param collection_signature_paths — issue #3030 — the subset of `signature_paths` that are `rbs collection`
|
|
132
|
+
# gem directories, read without their `_`-prefixed directories ({.project_sig_files}).
|
|
133
|
+
def build_env_for(libraries:, signature_paths:, virtual_rbs: [], deferred_signature_paths: [], # rubocop:disable Metrics/ParameterLists
|
|
134
|
+
project_signature_paths: [], core_root: nil, subordinate_signature_paths: [],
|
|
135
|
+
collection_signature_paths: [])
|
|
136
|
+
inputs = [signature_paths, virtual_rbs, deferred_signature_paths, project_signature_paths,
|
|
137
|
+
subordinate_signature_paths, collection_signature_paths]
|
|
111
138
|
with_core_root(core_root) { build_env_from(libraries, inputs) }
|
|
112
139
|
end
|
|
113
140
|
|
|
@@ -116,22 +143,17 @@ module Rigor
|
|
|
116
143
|
# {.build_env_from} must read the same core, and a parameter missed on one of them would build that attempt
|
|
117
144
|
# against the default core without a sign. Thread-local, so a concurrent build on another thread keeps its
|
|
118
145
|
# own.
|
|
119
|
-
def with_core_root(core_root)
|
|
120
|
-
|
|
121
|
-
Thread.current[:rigor_rbs_core_root] = core_root
|
|
122
|
-
yield
|
|
123
|
-
ensure
|
|
124
|
-
Thread.current[:rigor_rbs_core_root] = previous
|
|
146
|
+
def with_core_root(core_root, &)
|
|
147
|
+
TypingState.current.with(CORE_ROOT, core_root, &)
|
|
125
148
|
end
|
|
126
149
|
|
|
127
150
|
def build_env_from(libraries, inputs)
|
|
128
|
-
signature_paths, virtual_rbs = inputs
|
|
129
151
|
env, gated_dirs = whole_gated_attempt(libraries, inputs)
|
|
130
152
|
return env if gated_dirs.empty?
|
|
131
153
|
|
|
132
154
|
# Issue #1700 — a {RequiredFeatures}-gated directory joined; keep it whole only if it does not cost the
|
|
133
155
|
# environment anything ({.gated_failures}).
|
|
134
|
-
failed, quarantined = env ? gated_failures(env, gated_dirs,
|
|
156
|
+
failed, quarantined = env ? gated_failures(env, gated_dirs, inputs) : [[], 1]
|
|
135
157
|
return env if failed.empty? && quarantined.zero?
|
|
136
158
|
|
|
137
159
|
tokens = gated_dirs.map { |dir| RequiredFeatures.token(RequiredFeatures.feature_for_dir(dir)) }
|
|
@@ -142,7 +164,7 @@ module Rigor
|
|
|
142
164
|
trouble = failed.size + quarantined
|
|
143
165
|
return fallback if env.nil?
|
|
144
166
|
|
|
145
|
-
gated_trouble(fallback, gated_dirs,
|
|
167
|
+
gated_trouble(fallback, gated_dirs, inputs) < trouble ? fallback : env
|
|
146
168
|
end
|
|
147
169
|
|
|
148
170
|
# The first attempt, with every activated gated directory whole. rbs 3.x validates a class's generic
|
|
@@ -170,7 +192,7 @@ module Rigor
|
|
|
170
192
|
plan = GatedSignaturePlan.build(roots, fallback)
|
|
171
193
|
if plan.changed
|
|
172
194
|
env = gated_plan_attempt(libraries, inputs, plan)
|
|
173
|
-
failed, quarantined = env ? gated_failures(env, gated_dirs, inputs
|
|
195
|
+
failed, quarantined = env ? gated_failures(env, gated_dirs, inputs) : [failed, 0]
|
|
174
196
|
return env if env && failed.empty? && quarantined.zero?
|
|
175
197
|
end
|
|
176
198
|
return nil if failed.empty?
|
|
@@ -179,7 +201,7 @@ module Rigor
|
|
|
179
201
|
env = gated_plan_attempt(libraries, inputs, plan)
|
|
180
202
|
return nil if env.nil?
|
|
181
203
|
|
|
182
|
-
failed, quarantined = gated_failures(env, gated_dirs, inputs
|
|
204
|
+
failed, quarantined = gated_failures(env, gated_dirs, inputs)
|
|
183
205
|
env if failed.empty? && quarantined.zero?
|
|
184
206
|
end
|
|
185
207
|
|
|
@@ -218,8 +240,9 @@ module Rigor
|
|
|
218
240
|
# One {.build_env_attempt} round, which also returns its {VendoredSignaturePlan}.
|
|
219
241
|
#
|
|
220
242
|
# @param vendored_excluded — signature files the vendored plan is made without.
|
|
221
|
-
def planned_env_attempt(libraries, signature_paths, virtual_rbs, deferred_signature_paths,
|
|
222
|
-
project_signature_paths = [],
|
|
243
|
+
def planned_env_attempt(libraries, signature_paths, virtual_rbs, deferred_signature_paths, # rubocop:disable Metrics/ParameterLists
|
|
244
|
+
project_signature_paths = [], subordinate_signature_paths = [],
|
|
245
|
+
collection_signature_paths = [], gated_plan: nil, vendored_excluded: Set.new)
|
|
223
246
|
libraries = libraries_without_shadowed_bigdecimal_math(libraries)
|
|
224
247
|
rbs_loader, loaded_libraries = library_loader(libraries)
|
|
225
248
|
gated_dirs = loadable_gated_dirs(libraries, loaded_libraries)
|
|
@@ -229,7 +252,7 @@ module Rigor
|
|
|
229
252
|
# type-of query then degrades to `Dynamic[top]` — the "sig looks harmful" failure of the 2026-07-06
|
|
230
253
|
# mastodon coverage note). Per-file loading quarantines the broken file instead. Vendored / core-overlay
|
|
231
254
|
# sigs are Rigor-shipped and trusted, so they stay on the loader's fast batch path.
|
|
232
|
-
project_files = project_sig_files(signature_paths)
|
|
255
|
+
project_files = project_sig_files(signature_paths, collection_signature_paths)
|
|
233
256
|
undeferred_files = project_files - project_sig_files(deferred_signature_paths)
|
|
234
257
|
env, vendored_plan = bundled_env(rbs_loader, loaded_libraries, gated_plan ? [] : gated_dirs,
|
|
235
258
|
undeferred_files, vendored_excluded)
|
|
@@ -240,7 +263,9 @@ module Rigor
|
|
|
240
263
|
# inline-vs-`.rbs` consistency rule, and stand down to an inline member like to any other source.
|
|
241
264
|
consistency = member_consistency_for(undeferred_files, virtual_rbs)
|
|
242
265
|
add_project_signatures(env, signature_paths, deferred_signature_paths,
|
|
243
|
-
standdowns: consistency.signature_standdowns
|
|
266
|
+
standdowns: consistency.signature_standdowns,
|
|
267
|
+
subordinate_paths: subordinate_signature_paths,
|
|
268
|
+
collection_paths: collection_signature_paths)
|
|
244
269
|
gated_plan&.shells&.each { |source| add_parsed_decls(env, *source) }
|
|
245
270
|
# Issue #928 — the capability-role catalog goes in AFTER the project's own signatures, per
|
|
246
271
|
# declaration, so a project that already declares one of these interface names keeps its own
|
|
@@ -296,7 +321,7 @@ module Rigor
|
|
|
296
321
|
|
|
297
322
|
# An `RBS::EnvironmentLoader` with every library of `libraries` that resolves added, and those libraries.
|
|
298
323
|
def library_loader(libraries)
|
|
299
|
-
core_root =
|
|
324
|
+
core_root = TypingState.current[CORE_ROOT]
|
|
300
325
|
rbs_loader = core_root ? RBS::EnvironmentLoader.new(core_root: Pathname(core_root)) : RBS::EnvironmentLoader.new
|
|
301
326
|
# Issue #1700 — a `RequiredFeatures` token names a gated vendored directory, never an RBS library.
|
|
302
327
|
loaded_libraries = libraries.select do |library|
|
|
@@ -320,14 +345,16 @@ module Rigor
|
|
|
320
345
|
# rather than a comparison of declarations because it answers exactly what RBS itself decides — an
|
|
321
346
|
# overload continuation (`| ...`), a superclass written relative or absolute, a type parameter — with no
|
|
322
347
|
# second reading of the rules to drift. It runs only when a gated directory joined, on an env-cache miss.
|
|
323
|
-
def gated_trouble(env, dirs,
|
|
324
|
-
failed, quarantined = gated_failures(env, dirs,
|
|
348
|
+
def gated_trouble(env, dirs, inputs)
|
|
349
|
+
failed, quarantined = gated_failures(env, dirs, inputs)
|
|
325
350
|
failed.size + quarantined
|
|
326
351
|
end
|
|
327
352
|
|
|
328
353
|
# {.gated_trouble} split in two: the gated type names whose definitions fail, and the number of quarantined
|
|
329
|
-
# signature sources that declare one. Issue #1713 re-plans against the first.
|
|
330
|
-
|
|
354
|
+
# signature sources that declare one. Issue #1713 re-plans against the first. `inputs` is
|
|
355
|
+
# {.build_env_for}'s list: the signature paths, the virtual RBS, and (last) the collection directories.
|
|
356
|
+
def gated_failures(env, dirs, inputs)
|
|
357
|
+
signature_paths, virtual_rbs = inputs
|
|
331
358
|
type_names = gated_type_names(dirs)
|
|
332
359
|
builder = RBS::DefinitionBuilder.new(env: env)
|
|
333
360
|
failed = type_names.select do |type_name|
|
|
@@ -344,7 +371,8 @@ module Rigor
|
|
|
344
371
|
true
|
|
345
372
|
end
|
|
346
373
|
declares = gated_declaration_pattern(type_names)
|
|
347
|
-
|
|
374
|
+
collided = collision_quarantined_project_signatures(env, signature_paths, inputs[5] || [])
|
|
375
|
+
quarantined = collided.count do |file, _note|
|
|
348
376
|
File.read(file).match?(declares)
|
|
349
377
|
rescue SystemCallError, IOError, ArgumentError
|
|
350
378
|
false
|
|
@@ -633,12 +661,22 @@ module Rigor
|
|
|
633
661
|
# The absolute paths of every `.rbs` file under the project's `signature_paths:` (NOT vendored /
|
|
634
662
|
# stdlib RBS — those are well-formed, so attempting to build them would only waste time). Used to
|
|
635
663
|
# scope the referenced-type build sweep.
|
|
636
|
-
|
|
664
|
+
#
|
|
665
|
+
# @param collection_paths — issue #3030 — the entries of `signature_paths` that are `rbs collection` gem
|
|
666
|
+
# directories, read without the files below a `_`-prefixed directory, as rbs reads a collection gem
|
|
667
|
+
# ({RbsCollectionDiscovery.hidden_file?}). Compared by spelling, as the loader receives both lists from
|
|
668
|
+
# one `Environment.for_project` call.
|
|
669
|
+
def project_sig_files(signature_paths, collection_paths = [])
|
|
670
|
+
collection = collection_paths.to_set(&:to_s)
|
|
637
671
|
signature_paths.flat_map do |path|
|
|
638
672
|
path = Pathname(path) unless path.is_a?(Pathname)
|
|
639
673
|
next [] unless path.directory?
|
|
640
674
|
|
|
641
|
-
RootedGlob.glob(path, "**/*.rbs")
|
|
675
|
+
files = RootedGlob.glob(path, "**/*.rbs")
|
|
676
|
+
if collection.include?(path.to_s)
|
|
677
|
+
files = files.reject { |file| RbsCollectionDiscovery.hidden_file?(path, file) }
|
|
678
|
+
end
|
|
679
|
+
files.map { |p| File.expand_path(p) }
|
|
642
680
|
end.to_set
|
|
643
681
|
end
|
|
644
682
|
|
|
@@ -656,9 +694,16 @@ module Rigor
|
|
|
656
694
|
# @param standdowns — issue #1075 — `{signature_path => Set[[class, method, kind]]}`, the members an
|
|
657
695
|
# inline declaration displaced because it was the more precise side of a consistent pair
|
|
658
696
|
# ({MemberConsistency::Resolution#signature_standdowns}). They are removed before the file is added.
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
697
|
+
# @param subordinate_paths — issue #2978 — the subset loaded after the rest, planned against them as a deferred
|
|
698
|
+
# file is ({.add_deferred_signatures}) with every one of them as `own`: a member any of them declares stands
|
|
699
|
+
# down from the subordinate file instead of failing the class's definition build. A gem's `rbs collection`
|
|
700
|
+
# copy sits behind the gem's own `sig/` this way, so `Bar#a` in both binds the gem's, and `Bar#b` in the
|
|
701
|
+
# copy alone still loads.
|
|
702
|
+
def add_project_signatures(env, signature_paths, deferred_paths = [], standdowns: {}, subordinate_paths: [],
|
|
703
|
+
collection_paths: [])
|
|
704
|
+
subordinate = project_sig_files(subordinate_paths, collection_paths) - project_sig_files(deferred_paths)
|
|
705
|
+
eager = project_sig_files(signature_paths, collection_paths) - project_sig_files(deferred_paths) - subordinate
|
|
706
|
+
eager.sort.each do |file|
|
|
662
707
|
parsed = parse_signature_file(file)
|
|
663
708
|
next if parsed.nil? # quarantined (unparseable) or unreadable — skip so the env survives
|
|
664
709
|
|
|
@@ -666,6 +711,7 @@ module Rigor
|
|
|
666
711
|
strip_members!(decls, standdowns[file]) if standdowns.key?(file)
|
|
667
712
|
add_project_parsed_decls(env, buffer, directives, decls)
|
|
668
713
|
end
|
|
714
|
+
add_deferred_signatures(env, subordinate, eager, standdowns: standdowns)
|
|
669
715
|
end
|
|
670
716
|
|
|
671
717
|
# Issue #777 — add one project signature transactionally. `RBS::Environment#add_source` appends to
|
|
@@ -711,12 +757,15 @@ module Rigor
|
|
|
711
757
|
# source's `def` as an overload continuation, or stands down when the other source is the project's own
|
|
712
758
|
# (`own`, buffer names) or cannot be continued; a colliding declaration stands down on its own; the rest
|
|
713
759
|
# of the file loads. {.deferred_member_standdowns} reads what stood down back off the built env.
|
|
714
|
-
|
|
760
|
+
#
|
|
761
|
+
# @param standdowns — issue #2978 — {.add_project_signatures}' members to remove before a file is planned.
|
|
762
|
+
def add_deferred_signatures(env, deferred_files, own = Set.new, standdowns: {})
|
|
715
763
|
deferred_files.sort.each do |file|
|
|
716
764
|
parsed = parse_signature_file(file)
|
|
717
765
|
next if parsed.nil?
|
|
718
766
|
|
|
719
767
|
buffer, directives, decls = parsed
|
|
768
|
+
strip_members!(decls, standdowns[file]) if standdowns.key?(file)
|
|
720
769
|
next if generic_arity_conflict(env, decls)
|
|
721
770
|
|
|
722
771
|
add_project_parsed_decls(env, buffer, directives, DeferredSignaturePlan.plan(decls, env, own))
|
|
@@ -844,8 +893,8 @@ module Rigor
|
|
|
844
893
|
# {.add_project_signatures} so the warning fires even on a cache hit (where the env was already built
|
|
845
894
|
# with the file quarantined). Cheap: it only re-parses the user's own (usually small) `sig/` set, and
|
|
846
895
|
# returns empty immediately when there is no `signature_paths:`.
|
|
847
|
-
def quarantined_project_signatures(signature_paths)
|
|
848
|
-
project_sig_files(signature_paths).sort.filter_map do |file|
|
|
896
|
+
def quarantined_project_signatures(signature_paths, collection_paths = [])
|
|
897
|
+
project_sig_files(signature_paths, collection_paths).sort.filter_map do |file|
|
|
849
898
|
# The note carries the path itself because the warn composer prints only this element — a
|
|
850
899
|
# `ParsingError` message embeds its `path:line:` prefix, so the composer never adds one.
|
|
851
900
|
content = File.read(file, encoding: "UTF-8")
|
|
@@ -876,7 +925,7 @@ module Rigor
|
|
|
876
925
|
COLLISION_QUARANTINE_NOTE =
|
|
877
926
|
"duplicated declaration against bundled RBS — quarantined so the rest of the RBS env still loads"
|
|
878
927
|
|
|
879
|
-
def collision_quarantined_project_signatures(env, signature_paths)
|
|
928
|
+
def collision_quarantined_project_signatures(env, signature_paths, collection_paths = [])
|
|
880
929
|
return [] if env.nil?
|
|
881
930
|
|
|
882
931
|
present = env.buffers.to_set do |buffer|
|
|
@@ -888,7 +937,7 @@ module Rigor
|
|
|
888
937
|
name.to_s
|
|
889
938
|
end
|
|
890
939
|
buffers_by_basename = env.buffers.group_by { |buffer| File.basename(buffer.name.to_s) }
|
|
891
|
-
project_sig_files(signature_paths).sort.filter_map do |file|
|
|
940
|
+
project_sig_files(signature_paths, collection_paths).sort.filter_map do |file|
|
|
892
941
|
next if present.include?(file)
|
|
893
942
|
next if parse_signature_file(file).nil? # parse / encoding quarantine owns these
|
|
894
943
|
next if project_signature_loaded_under_other_path?(file, buffers_by_basename)
|
|
@@ -1536,7 +1585,8 @@ module Rigor
|
|
|
1536
1585
|
# add self-contained declarations) and stay unconditional.
|
|
1537
1586
|
LIBRARY_SUPPLEMENT_CORE_OVERLAYS = {
|
|
1538
1587
|
"resolv.rbs" => "resolv",
|
|
1539
|
-
"string_scanner.rbs" => "strscan"
|
|
1588
|
+
"string_scanner.rbs" => "strscan",
|
|
1589
|
+
"bigdecimal.rbs" => "bigdecimal"
|
|
1540
1590
|
}.freeze
|
|
1541
1591
|
private_constant :LIBRARY_SUPPLEMENT_CORE_OVERLAYS
|
|
1542
1592
|
|
|
@@ -1637,17 +1687,19 @@ module Rigor
|
|
|
1637
1687
|
end
|
|
1638
1688
|
|
|
1639
1689
|
# Rigor-owned per-gem RBS overlays (`data/gem_overlay/<gem>/`), ADR-72. Unlike the unconditional
|
|
1640
|
-
# `core_overlay`, each gem's overlay is loaded
|
|
1641
|
-
# Gemfile.lock
|
|
1642
|
-
#
|
|
1643
|
-
#
|
|
1690
|
+
# `core_overlay`, each gem's overlay is loaded only when that gem is locked in the project's
|
|
1691
|
+
# Gemfile.lock AND {Environment.for_project} finds its coverage source overlay-eligible
|
|
1692
|
+
# ({Environment::GEM_OVERLAY_COVERAGE_SOURCES} — `:missing` for every overlay but addressable's
|
|
1693
|
+
# `:rbs_collection` correction, #2857) with no reachable plugin twin; this method receives the
|
|
1694
|
+
# already-filtered gem-name set. One directory per gem name keeps the membership check a cheap
|
|
1695
|
+
# `File.directory?`.
|
|
1644
1696
|
GEM_OVERLAY_SIGS_ROOT = File.expand_path(
|
|
1645
1697
|
"../../../data/gem_overlay",
|
|
1646
1698
|
__dir__
|
|
1647
1699
|
).freeze
|
|
1648
1700
|
|
|
1649
|
-
# @param gem_names — overlay-eligible Gemfile.lock gem names (the caller filters
|
|
1650
|
-
#
|
|
1701
|
+
# @param gem_names — overlay-eligible Gemfile.lock gem names (the caller filters to the
|
|
1702
|
+
# coverage-source-eligible, no-conflicting-plugin set).
|
|
1651
1703
|
# @return the bundled overlay directory for each gem that ships one; empty when
|
|
1652
1704
|
# none match or the overlay root is absent.
|
|
1653
1705
|
def gem_overlay_sig_paths(gem_names)
|
|
@@ -1661,13 +1713,16 @@ module Rigor
|
|
|
1661
1713
|
|
|
1662
1714
|
# @param path — typically an entry from an {RbsLoader} instance's
|
|
1663
1715
|
# {#signature_paths}.
|
|
1664
|
-
# @return whether `path` sits under the bundled gem-overlay root —
|
|
1665
|
-
#
|
|
1666
|
-
#
|
|
1667
|
-
#
|
|
1668
|
-
#
|
|
1669
|
-
#
|
|
1670
|
-
#
|
|
1716
|
+
# @return whether `path` sits under the bundled gem-overlay root — the prefix half of
|
|
1717
|
+
# "this run loaded a `data/gem_overlay/` directory". Callers needing ONE gem's overlay ask
|
|
1718
|
+
# {.gem_overlay_sig_paths} for that gem's directory instead: `signature_standdowns` uses this
|
|
1719
|
+
# to recognise overlay rows across every gem, while `CheckRules#gem_overlay_loaded?` keys on
|
|
1720
|
+
# the activesupport overlay alone (#3041 — a project can load the addressable overlay without
|
|
1721
|
+
# the activesupport one, and only the latter may open `ActiveSupport::Duration` /
|
|
1722
|
+
# `ActiveSupport::Concern`). `GEM_OVERLAY_SIGS_ROOT` is defined inside this `class << self`
|
|
1723
|
+
# block, so it is reachable from here directly but NOT as `RbsLoader::GEM_OVERLAY_SIGS_ROOT`
|
|
1724
|
+
# from outside — this method is the public seam callers outside this class use instead of
|
|
1725
|
+
# reaching for the constant themselves.
|
|
1671
1726
|
def under_gem_overlay_root?(path)
|
|
1672
1727
|
path.to_s.start_with?("#{GEM_OVERLAY_SIGS_ROOT}/")
|
|
1673
1728
|
end
|
|
@@ -1783,7 +1838,7 @@ module Rigor
|
|
|
1783
1838
|
end
|
|
1784
1839
|
|
|
1785
1840
|
attr_reader :libraries, :signature_paths, :cache_store, :virtual_rbs, :deferred_signature_paths,
|
|
1786
|
-
:project_signature_paths, :core_root
|
|
1841
|
+
:project_signature_paths, :core_root, :subordinate_signature_paths, :collection_signature_paths
|
|
1787
1842
|
|
|
1788
1843
|
# @param libraries — stdlib library names to load on top of core (e.g.,
|
|
1789
1844
|
# `["pathname", "json"]`). Empty by default. Each entry MUST correspond to a directory under the
|
|
@@ -1806,17 +1861,20 @@ module Rigor
|
|
|
1806
1861
|
# a miss — a list it cannot read is a stand-down that runs only on a `--no-cache` build.
|
|
1807
1862
|
# @param core_root — issue #2517 — a directory loaded in place of the `rbs` gem's `core/`, or nil (the
|
|
1808
1863
|
# default) for that core. Validated here, so a bad selection fails at construction ({CoreRoot.validate!}).
|
|
1864
|
+
# @param subordinate_signature_paths — issue #2978 — the subset of `signature_paths:` that stands down member by
|
|
1865
|
+
# member to the rest of it (a bundle gem's `rbs collection` copy, behind the gem's own `sig/`).
|
|
1866
|
+
# @param collection_signature_paths — issue #3030 — the subset of `signature_paths:` that are `rbs collection`
|
|
1867
|
+
# gem directories, read without the files below their `_`-prefixed directories ({.project_sig_files}).
|
|
1809
1868
|
def initialize(libraries: [], signature_paths: [], cache_store: nil, virtual_rbs: [], # rubocop:disable Metrics/ParameterLists
|
|
1810
|
-
deferred_signature_paths: [], project_signature_paths: [], required_features: [], core_root: nil
|
|
1869
|
+
deferred_signature_paths: [], project_signature_paths: [], required_features: [], core_root: nil,
|
|
1870
|
+
subordinate_signature_paths: [], collection_signature_paths: [])
|
|
1811
1871
|
@core_root = core_root.nil? ? nil : CoreRoot.validate!(core_root)
|
|
1812
1872
|
CoreRoot.reject_overlap!(@core_root, project_signature_paths) if @core_root
|
|
1813
1873
|
@libraries = libraries.map(&:to_s).freeze
|
|
1814
1874
|
@signature_paths = signature_paths.map { |p| Pathname(p) }.freeze
|
|
1815
1875
|
assign_reopen_inputs(project_signature_paths, required_features)
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
# is also in `@signature_paths`, so the env cache descriptor already digests these files.
|
|
1819
|
-
@deferred_signature_paths = deferred_signature_paths.map { |p| Pathname(p) }.freeze
|
|
1876
|
+
assign_partition(deferred_signature_paths, subordinate_signature_paths)
|
|
1877
|
+
@collection_signature_paths = collection_signature_paths.map { |p| Pathname(p) }.freeze
|
|
1820
1878
|
@cache_store = cache_store
|
|
1821
1879
|
@virtual_rbs = virtual_rbs.map { |name, content| [name.to_s.dup.freeze, content.to_s.dup.freeze].freeze }.freeze
|
|
1822
1880
|
# Per-loader memoization bucket. Held as a single mutable Hash so the loader instance itself can be
|
|
@@ -1857,9 +1915,9 @@ module Rigor
|
|
|
1857
1915
|
# @return empty when every `signature_paths:` file parses.
|
|
1858
1916
|
def quarantined_signatures
|
|
1859
1917
|
@state[:quarantined] ||= begin
|
|
1860
|
-
parse_quarantined = self.class.quarantined_project_signatures(@signature_paths)
|
|
1918
|
+
parse_quarantined = self.class.quarantined_project_signatures(@signature_paths, @collection_signature_paths)
|
|
1861
1919
|
collision_quarantined = self.class.collision_quarantined_project_signatures(
|
|
1862
|
-
@state[:env], @signature_paths
|
|
1920
|
+
@state[:env], @signature_paths, @collection_signature_paths
|
|
1863
1921
|
)
|
|
1864
1922
|
parse_paths = parse_quarantined.to_set { |path, _note| path }
|
|
1865
1923
|
# Issue #610 — a deferred file that STOOD DOWN is absent from the env by design, which is exactly
|
|
@@ -1883,11 +1941,14 @@ module Rigor
|
|
|
1883
1941
|
#
|
|
1884
1942
|
# Issue #2422 — followed by the members a deferred file that did load left out because another source
|
|
1885
1943
|
# declares them ({.deferred_member_standdowns}), one row each.
|
|
1944
|
+
#
|
|
1945
|
+
# Issue #2974 — a gem overlay's rows are left out: the overlay is Rigor's own default, deferred so it stands
|
|
1946
|
+
# down to any source that declares the same thing, and that is not news to report (#2470's reasoning).
|
|
1886
1947
|
def signature_standdowns
|
|
1887
1948
|
@state[:signature_standdowns] ||= (
|
|
1888
1949
|
self.class.deferred_standdowns(env, @deferred_signature_paths) +
|
|
1889
1950
|
self.class.deferred_member_standdowns(env, @deferred_signature_paths)
|
|
1890
|
-
).freeze
|
|
1951
|
+
).reject { |row| self.class.under_gem_overlay_root?(row.first) }.freeze
|
|
1891
1952
|
end
|
|
1892
1953
|
|
|
1893
1954
|
# Issue #1713 — what stood down from each {RequiredFeatures}-gated vendored directory this loader's library
|
|
@@ -1906,7 +1967,7 @@ module Rigor
|
|
|
1906
1967
|
end
|
|
1907
1968
|
return [] if roots.empty?
|
|
1908
1969
|
|
|
1909
|
-
GatedSignaturePlan.standdowns(env, roots,
|
|
1970
|
+
GatedSignaturePlan.standdowns(env, roots, signature_files)
|
|
1910
1971
|
end
|
|
1911
1972
|
private :derive_vendored_standdowns
|
|
1912
1973
|
|
|
@@ -1942,7 +2003,7 @@ module Rigor
|
|
|
1942
2003
|
environment = env
|
|
1943
2004
|
return Set.new.freeze if environment.nil?
|
|
1944
2005
|
|
|
1945
|
-
project_files =
|
|
2006
|
+
project_files = signature_files
|
|
1946
2007
|
virtual_names = @virtual_rbs.to_set(&:first)
|
|
1947
2008
|
return Set.new.freeze if project_files.empty? && virtual_names.empty?
|
|
1948
2009
|
|
|
@@ -2012,6 +2073,22 @@ module Rigor
|
|
|
2012
2073
|
# Issue #2174 — the subset of `signature_paths:` the user configured (every entry is also in
|
|
2013
2074
|
# `@signature_paths`), and the features the project's source requires: read only by
|
|
2014
2075
|
# {#ruby_library_reopen?}.
|
|
2076
|
+
# Issue #610 — the subset of `signature_paths:` a bundled PLUGIN contributed. Loaded last and allowed to stand
|
|
2077
|
+
# down against a colliding generic arity ({.add_deferred_signatures}). Issue #2978 — and the subset that stands
|
|
2078
|
+
# down member by member to the rest. Every entry of either is also in `@signature_paths`, so the env cache
|
|
2079
|
+
# descriptor already digests these files.
|
|
2080
|
+
# Issue #3030 — every `.rbs` file this loader reads from its `signature_paths:`, the `_`-prefixed directories of
|
|
2081
|
+
# its `rbs collection` gem directories left out ({.project_sig_files}).
|
|
2082
|
+
def signature_files
|
|
2083
|
+
self.class.project_sig_files(@signature_paths, @collection_signature_paths)
|
|
2084
|
+
end
|
|
2085
|
+
private :signature_files
|
|
2086
|
+
|
|
2087
|
+
def assign_partition(deferred_signature_paths, subordinate_signature_paths)
|
|
2088
|
+
@deferred_signature_paths = deferred_signature_paths.map { |p| Pathname(p) }.freeze
|
|
2089
|
+
@subordinate_signature_paths = subordinate_signature_paths.map { |p| Pathname(p) }.freeze
|
|
2090
|
+
end
|
|
2091
|
+
|
|
2015
2092
|
def assign_reopen_inputs(project_signature_paths, required_features)
|
|
2016
2093
|
@project_signature_paths = project_signature_paths.map { |p| Pathname(p) }.freeze
|
|
2017
2094
|
@required_features = required_features.map { |feature| feature.to_s.dup.freeze }.freeze
|
|
@@ -2147,7 +2224,7 @@ module Rigor
|
|
|
2147
2224
|
[::RBS::EnvironmentLoader::DEFAULT_CORE_ROOT].compact.map { |root| "#{root}/".freeze }.freeze
|
|
2148
2225
|
rescue StandardError
|
|
2149
2226
|
[].freeze
|
|
2150
|
-
end
|
|
2227
|
+
end.freeze
|
|
2151
2228
|
private_constant :CORE_ROOTS
|
|
2152
2229
|
|
|
2153
2230
|
def build_core_stdlib_classes(roots = core_stdlib_roots)
|
|
@@ -2174,6 +2251,96 @@ module Rigor
|
|
|
2174
2251
|
core_stdlib_classes.include?(class_name.to_s.delete_prefix("::"))
|
|
2175
2252
|
end
|
|
2176
2253
|
|
|
2254
|
+
# Issue #2884 — true when every declaration of `method_definition` (an `RBS::Definition::Method`) is in a named
|
|
2255
|
+
# buffer outside the `rbs` gem's `core/` and `stdlib/` trees: a project, gem or collection signature wrote it.
|
|
2256
|
+
# Attributed by buffer name, as {#core_or_stdlib_class?} is; a declaration whose buffer name is lost (an old
|
|
2257
|
+
# environment blob's `<cached>` sentinel) answers false, which switches the caller's feature off.
|
|
2258
|
+
def declared_outside_core_stdlib?(method_definition)
|
|
2259
|
+
roots = core_stdlib_roots
|
|
2260
|
+
type_defs = method_definition.defs
|
|
2261
|
+
return false if roots.empty? || type_defs.empty?
|
|
2262
|
+
|
|
2263
|
+
type_defs.all? do |type_def|
|
|
2264
|
+
name = self.class.declaration_buffer_name(type_def.member)
|
|
2265
|
+
!name.nil? && roots.none? { |root| name.start_with?(root) }
|
|
2266
|
+
end
|
|
2267
|
+
end
|
|
2268
|
+
|
|
2269
|
+
# Issue #2884 — true when `method_definition`, a class's singleton `new`, is one `X.new` answers through: every
|
|
2270
|
+
# definition is an explicit `def self.new` (not the `new` `RBS::DefinitionBuilder` derives from `initialize`,
|
|
2271
|
+
# which returns the declaring class), written outside core / stdlib ({#declared_outside_core_stdlib?}), on a
|
|
2272
|
+
# class core / stdlib does not declare (a project signature reopening `String` does not change `String.new`).
|
|
2273
|
+
def honoured_singleton_new?(method_definition)
|
|
2274
|
+
method_definition.defs.all? { |type_def| explicit_singleton_new_member?(type_def.member) } &&
|
|
2275
|
+
declared_outside_core_stdlib?(method_definition) &&
|
|
2276
|
+
!core_or_stdlib_class?(method_definition.defined_in.to_s)
|
|
2277
|
+
end
|
|
2278
|
+
|
|
2279
|
+
def explicit_singleton_new_member?(member)
|
|
2280
|
+
member.is_a?(::RBS::AST::Members::MethodDefinition) && member.name == :new && member.kind != :instance
|
|
2281
|
+
end
|
|
2282
|
+
private :explicit_singleton_new_member?
|
|
2283
|
+
|
|
2284
|
+
# Issue #2884 — true when `method_definition`, a singleton `new`, answers what `Nominal[receiver]` answers for
|
|
2285
|
+
# every receiver that inherits it: each overload returns `instance`, untyped, `top`, `bot` or `void`, or the
|
|
2286
|
+
# declaring class itself, compared by its resolved full name. `self` is the receiver's class object, not its
|
|
2287
|
+
# instance, so it does not count. The dispatcher answers `Nominal[receiver]` for an inherited declaration this
|
|
2288
|
+
# holds of, and {#singleton_new_departs_from_instance?} is built from the same test, so the two cannot drift.
|
|
2289
|
+
def answers_instance_for_subclass?(method_definition)
|
|
2290
|
+
owner = method_definition.defined_in.to_s.delete_prefix("::")
|
|
2291
|
+
method_definition.method_types.all? do |method_type|
|
|
2292
|
+
returned = method_type.type.return_type
|
|
2293
|
+
INSTANCE_LIKE_RETURNS.any? { |base| returned.is_a?(base) } ||
|
|
2294
|
+
(returned.is_a?(::RBS::Types::ClassInstance) && returned.name.to_s.delete_prefix("::") == owner)
|
|
2295
|
+
end
|
|
2296
|
+
end
|
|
2297
|
+
|
|
2298
|
+
INSTANCE_LIKE_RETURNS = [
|
|
2299
|
+
::RBS::Types::Bases::Instance, ::RBS::Types::Bases::Any, ::RBS::Types::Bases::Top,
|
|
2300
|
+
::RBS::Types::Bases::Bottom, ::RBS::Types::Bases::Void
|
|
2301
|
+
].freeze
|
|
2302
|
+
private_constant :INSTANCE_LIKE_RETURNS
|
|
2303
|
+
|
|
2304
|
+
# Issue #2884 — true when some class declares a {#honoured_singleton_new?} `new` that is not
|
|
2305
|
+
# {#answers_instance_for_subclass?}: only such a declaration answers a Ruby subclass with something other than
|
|
2306
|
+
# the `Nominal[subclass]` the dispatcher gives without one, so the dispatcher walks a subclass's ancestry, and
|
|
2307
|
+
# files that walk's dependency edges, only when this holds. Memoised per loader: one pass over `class_decls` for
|
|
2308
|
+
# the classes whose own non-core declaration writes `def self.new`, then their definitions.
|
|
2309
|
+
def singleton_new_departs_from_instance?
|
|
2310
|
+
return @state[:singleton_new_departs] if @state.key?(:singleton_new_departs)
|
|
2311
|
+
|
|
2312
|
+
@state[:singleton_new_departs] = scan_singleton_new_departs
|
|
2313
|
+
end
|
|
2314
|
+
|
|
2315
|
+
def scan_singleton_new_departs
|
|
2316
|
+
during_internal_demand do
|
|
2317
|
+
singleton_new_declarers.any? do |class_name|
|
|
2318
|
+
definition = singleton_method(class_name: class_name, method_name: :new)
|
|
2319
|
+
definition && honoured_singleton_new?(definition) && !answers_instance_for_subclass?(definition)
|
|
2320
|
+
end
|
|
2321
|
+
end
|
|
2322
|
+
rescue ::RBS::BaseError
|
|
2323
|
+
true
|
|
2324
|
+
end
|
|
2325
|
+
private :scan_singleton_new_departs
|
|
2326
|
+
|
|
2327
|
+
def singleton_new_declarers
|
|
2328
|
+
environment = env
|
|
2329
|
+
roots = core_stdlib_roots
|
|
2330
|
+
return [] if environment.nil? || roots.empty?
|
|
2331
|
+
|
|
2332
|
+
environment.class_decls.filter_map do |type_name, entry|
|
|
2333
|
+
declares = self.class.entry_declarations(entry).any? do |decl|
|
|
2334
|
+
name = self.class.declaration_buffer_name(decl)
|
|
2335
|
+
next false if name.nil? || roots.any? { |root| name.start_with?(root) }
|
|
2336
|
+
|
|
2337
|
+
decl.members.any? { |member| explicit_singleton_new_member?(member) }
|
|
2338
|
+
end
|
|
2339
|
+
type_name.to_s if declares
|
|
2340
|
+
end
|
|
2341
|
+
end
|
|
2342
|
+
private :singleton_new_declarers
|
|
2343
|
+
|
|
2177
2344
|
# True when `class_name`'s RBS declaration is one the project wrote (see {#project_declared_classes}).
|
|
2178
2345
|
def project_declared_class?(class_name)
|
|
2179
2346
|
project_declared_classes.include?(class_name.to_s.delete_prefix("::"))
|
|
@@ -2241,6 +2408,13 @@ module Rigor
|
|
|
2241
2408
|
nil
|
|
2242
2409
|
end
|
|
2243
2410
|
|
|
2411
|
+
# Issue #2883 — builds the environment now, for the default core as {#verify_core_root!} does for a selected one,
|
|
2412
|
+
# so no `type_of` builds it lazily (ADR-129 G1': the core-root Frame the build reads is never read inside typing).
|
|
2413
|
+
def prepare_for_typing!
|
|
2414
|
+
env
|
|
2415
|
+
nil
|
|
2416
|
+
end
|
|
2417
|
+
|
|
2244
2418
|
# Issue #696 — the PER-CLASS sibling of {#env_build_failure}, one tier quieter in consequence: an
|
|
2245
2419
|
# `RBS::DefinitionBuilder` failure ({#build_instance_definition} / {#build_singleton_definition}'s
|
|
2246
2420
|
# rescue) leaves the class KNOWN but with no method surface, so every call on it — real methods and
|
|
@@ -2326,7 +2500,7 @@ module Rigor
|
|
|
2326
2500
|
def member_consistency(proof: nil)
|
|
2327
2501
|
key = proof ? :member_consistency_proven : :member_consistency
|
|
2328
2502
|
@state[key] ||= self.class.member_consistency_for(
|
|
2329
|
-
|
|
2503
|
+
signature_files - self.class.project_sig_files(@deferred_signature_paths),
|
|
2330
2504
|
@virtual_rbs, proof: proof
|
|
2331
2505
|
).records
|
|
2332
2506
|
end
|
|
@@ -2455,6 +2629,51 @@ module Rigor
|
|
|
2455
2629
|
end
|
|
2456
2630
|
private :mixin_parent
|
|
2457
2631
|
|
|
2632
|
+
# Issue #2681 — every method name declared, on either side, by `name`'s RBS declarations and by the classes and
|
|
2633
|
+
# modules they inherit, include, prepend or extend, `::`-stripped names in `skip` excepted. Read from the
|
|
2634
|
+
# declarations as {#declared_ancestry} reads them, not through the definition builder: a definition that fails to
|
|
2635
|
+
# build reports a coverage diagnostic each time it is asked for. A superset of what the built definitions hold
|
|
2636
|
+
# is harmless to the one reader, a gate in front of ADR-43's override walk. Empty when the environment is
|
|
2637
|
+
# unavailable; the walk stops at 64 owners.
|
|
2638
|
+
def declared_method_names(name, skip: [])
|
|
2639
|
+
return Set.new if env.nil?
|
|
2640
|
+
|
|
2641
|
+
names = Set.new
|
|
2642
|
+
pending = [name.to_s.delete_prefix("::")]
|
|
2643
|
+
seen = Set.new
|
|
2644
|
+
until pending.empty? || seen.size > 64
|
|
2645
|
+
owner = pending.shift
|
|
2646
|
+
next if seen.include?(owner) || skip.include?(owner)
|
|
2647
|
+
|
|
2648
|
+
seen << owner
|
|
2649
|
+
entry = env.class_decls[parse_type_name(owner)]
|
|
2650
|
+
self.class.entry_declarations(entry).each { |decl| read_declared_methods(decl, names, pending) } if entry
|
|
2651
|
+
end
|
|
2652
|
+
names
|
|
2653
|
+
rescue ::RBS::BaseError
|
|
2654
|
+
Set.new
|
|
2655
|
+
end
|
|
2656
|
+
|
|
2657
|
+
def read_declared_methods(decl, names, pending)
|
|
2658
|
+
superclass = decl.respond_to?(:super_class) ? decl.super_class : nil
|
|
2659
|
+
pending << superclass.name.to_s.delete_prefix("::") if superclass
|
|
2660
|
+
return unless decl.respond_to?(:members)
|
|
2661
|
+
|
|
2662
|
+
decl.members.each do |member|
|
|
2663
|
+
case member
|
|
2664
|
+
when ::RBS::AST::Members::MethodDefinition, ::RBS::AST::Members::AttrReader
|
|
2665
|
+
names << member.name
|
|
2666
|
+
when ::RBS::AST::Members::AttrAccessor, ::RBS::AST::Members::AttrWriter
|
|
2667
|
+
names << member.name << :"#{member.name}="
|
|
2668
|
+
when ::RBS::AST::Members::Alias
|
|
2669
|
+
names << member.new_name
|
|
2670
|
+
when ::RBS::AST::Members::Include, ::RBS::AST::Members::Prepend, ::RBS::AST::Members::Extend
|
|
2671
|
+
pending << member.name.to_s.delete_prefix("::") unless member.name.interface?
|
|
2672
|
+
end
|
|
2673
|
+
end
|
|
2674
|
+
end
|
|
2675
|
+
private :read_declared_methods
|
|
2676
|
+
|
|
2458
2677
|
# Issue #2321 — every class name an RBS class declaration names as its superclass, `::`-stripped: a class
|
|
2459
2678
|
# absent from the set has no RBS-declared subclass. `nil` when the environment is unavailable or fails to read,
|
|
2460
2679
|
# so a caller cannot mistake an unread environment for one without subclasses. Memoised per loader.
|
|
@@ -2675,6 +2894,34 @@ module Rigor
|
|
|
2675
2894
|
nil
|
|
2676
2895
|
end
|
|
2677
2896
|
|
|
2897
|
+
# #775 — the memo {Inference::RbsTypeTranslator} keeps, per loader, for the translated form of a closed alias
|
|
2898
|
+
# expansion (keyed by the expansion). It lives here because the translation reads this loader's environment
|
|
2899
|
+
# through any alias nested in the expansion ({#expand_type_alias}): another loader's `b` may differ under an
|
|
2900
|
+
# equal `a`, and the entry goes with the loader. The translator is its only reader and writer.
|
|
2901
|
+
def closed_alias_translations
|
|
2902
|
+
@state[:closed_alias_translations] ||= {}
|
|
2903
|
+
end
|
|
2904
|
+
|
|
2905
|
+
# An independent resolver for a read-only consumer. Its memo belongs to the caller, never the loader cache.
|
|
2906
|
+
def type_name_resolver
|
|
2907
|
+
environment = env
|
|
2908
|
+
return nil if environment.nil?
|
|
2909
|
+
|
|
2910
|
+
klass = ::RBS::Resolver::TypeNameResolver
|
|
2911
|
+
if klass.respond_to?(:build)
|
|
2912
|
+
klass.build(environment)
|
|
2913
|
+
else
|
|
2914
|
+
# Older RBS 3.x takes the environment instead of the current constructor's name tables.
|
|
2915
|
+
klass.new(environment) # rigor:disable call.wrong-arity
|
|
2916
|
+
end
|
|
2917
|
+
end
|
|
2918
|
+
|
|
2919
|
+
# The resolved alias declaration, without substituting type arguments or translating its AST.
|
|
2920
|
+
def type_alias_declaration(name)
|
|
2921
|
+
declarations = env&.type_alias_decls
|
|
2922
|
+
declarations&.[](name)&.decl
|
|
2923
|
+
end
|
|
2924
|
+
|
|
2678
2925
|
# @return the resolved singleton (class object) definition for `class_name`. The
|
|
2679
2926
|
# methods on this definition are the *class methods* of `class_name`, including those inherited from
|
|
2680
2927
|
# `Class` and `Module` for class types. Returns nil for unknown names and on RBS build errors
|
|
@@ -3315,7 +3562,9 @@ module Rigor
|
|
|
3315
3562
|
virtual_rbs: @virtual_rbs,
|
|
3316
3563
|
deferred_signature_paths: @deferred_signature_paths,
|
|
3317
3564
|
project_signature_paths: @project_signature_paths,
|
|
3318
|
-
core_root: @core_root
|
|
3565
|
+
core_root: @core_root,
|
|
3566
|
+
subordinate_signature_paths: @subordinate_signature_paths,
|
|
3567
|
+
collection_signature_paths: @collection_signature_paths
|
|
3319
3568
|
)
|
|
3320
3569
|
end
|
|
3321
3570
|
|