rigortype 0.4.4 → 0.4.6
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 +5 -5
- data/docs/handbook/11-sig-gen.md +100 -18
- data/docs/manual/02-cli-reference.md +85 -16
- data/docs/manual/03-configuration.md +12 -9
- data/docs/manual/04-diagnostics.md +17 -6
- data/docs/manual/05-inspecting-types.md +2 -2
- data/docs/manual/06-baseline.md +1 -1
- data/docs/manual/07-plugins.md +2 -1
- data/docs/manual/08-skills.md +7 -0
- data/docs/manual/10-mcp-server.md +17 -2
- data/docs/manual/12-caching.md +8 -1
- data/docs/manual/18-removing-dead-code.md +18 -7
- data/docs/manual/plugins/rigor-actionmailer.md +30 -0
- data/docs/manual/plugins/rigor-actionpack.md +30 -0
- data/docs/manual/plugins/rigor-devise.md +15 -0
- data/docs/manual/plugins/rigor-rspec.md +102 -1
- data/lib/rigor/analysis/buffer_binding.rb +14 -0
- data/lib/rigor/analysis/check_rules/clause_coverage.rb +134 -0
- data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +30 -9
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +142 -15
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +115 -7
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +253 -0
- data/lib/rigor/analysis/check_rules/rebinding_block_callees/dispatch.rb +112 -0
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +394 -0
- data/lib/rigor/analysis/check_rules/ruby_deprecations.rb +7 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +3 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +32 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +64 -4
- data/lib/rigor/analysis/check_rules.rb +319 -21
- data/lib/rigor/analysis/dependency_recorder.rb +11 -0
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +2 -1
- data/lib/rigor/analysis/edit_replay.rb +67 -0
- data/lib/rigor/analysis/incremental.rb +86 -0
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +36 -18
- data/lib/rigor/analysis/incremental_session.rb +336 -46
- data/lib/rigor/analysis/path_expansion.rb +44 -1
- data/lib/rigor/analysis/reachability/graph.rb +90 -13
- data/lib/rigor/analysis/reachability/scan.rb +279 -39
- data/lib/rigor/analysis/require_relative_closure.rb +100 -0
- data/lib/rigor/analysis/rule_catalog.rb +22 -5
- data/lib/rigor/analysis/run_disclosure_credit.rb +80 -0
- data/lib/rigor/analysis/run_disclosure_ledger.rb +155 -0
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +11 -3
- data/lib/rigor/analysis/runner/pool_coordinator.rb +82 -16
- data/lib/rigor/analysis/runner/project_pre_passes.rb +45 -3
- data/lib/rigor/analysis/runner/scan_environment.rb +51 -0
- data/lib/rigor/analysis/runner.rb +222 -111
- data/lib/rigor/analysis/severity_stamp.rb +11 -0
- data/lib/rigor/analysis/worker_session.rb +24 -1
- data/lib/rigor/cache/descriptor.rb +40 -7
- data/lib/rigor/cache/engine_source.rb +3 -2
- data/lib/rigor/cache/incremental_snapshot.rb +49 -8
- data/lib/rigor/cache/rbs_descriptor.rb +2 -1
- data/lib/rigor/cache/store.rb +4 -3
- data/lib/rigor/cli/check_command.rb +93 -4
- data/lib/rigor/cli/command.rb +3 -1
- data/lib/rigor/cli/diff_command.rb +2 -1
- data/lib/rigor/cli/docs_command.rb +3 -2
- data/lib/rigor/cli/doctor_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +3 -2
- data/lib/rigor/cli/lens_command.rb +5 -5
- data/lib/rigor/cli/mcp_command.rb +2 -1
- data/lib/rigor/cli/options.rb +20 -3
- data/lib/rigor/cli/plugin_command.rb +2 -1
- data/lib/rigor/cli/plugins_command.rb +7 -1
- data/lib/rigor/cli/plugins_renderer.rb +24 -2
- data/lib/rigor/cli/show_bleedingedge_command.rb +2 -1
- data/lib/rigor/cli/sig_gen_command.rb +73 -13
- data/lib/rigor/cli/skill_command.rb +2 -1
- data/lib/rigor/cli/skill_describe.rb +3 -2
- data/lib/rigor/cli/type_of_command.rb +2 -1
- data/lib/rigor/cli/type_of_project_scope.rb +27 -0
- data/lib/rigor/cli/unused_command.rb +10 -7
- data/lib/rigor/cli.rb +3 -2
- data/lib/rigor/config_audit.rb +72 -16
- data/lib/rigor/configuration/severity_profile.rb +20 -2
- data/lib/rigor/configuration.rb +43 -7
- data/lib/rigor/effects/signature_sources.rb +3 -1
- data/lib/rigor/environment/bundle_sig_discovery.rb +3 -2
- data/lib/rigor/environment/gated_signature_guard.rb +2 -1
- data/lib/rigor/environment/gated_signature_plan.rb +2 -1
- data/lib/rigor/environment/installed_gem_set.rb +2 -1
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -3
- data/lib/rigor/environment/rbs_loader.rb +136 -7
- data/lib/rigor/environment/required_features.rb +136 -29
- data/lib/rigor/environment/ruby_library_roots.rb +122 -0
- data/lib/rigor/environment.rb +4 -2
- data/lib/rigor/inference/block_call_timing.rb +7 -1
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/callee_mutation_chain.rb +115 -0
- data/lib/rigor/inference/captured_locals.rb +44 -13
- data/lib/rigor/inference/clause_widening.rb +90 -0
- data/lib/rigor/inference/deep_erasure.rb +138 -0
- data/lib/rigor/inference/def_return_typer.rb +159 -9
- data/lib/rigor/inference/definer_resolution.rb +101 -20
- data/lib/rigor/inference/error_info.rb +17 -3
- data/lib/rigor/inference/expression_typer.rb +97 -18
- data/lib/rigor/inference/global_write_census.rb +36 -1
- data/lib/rigor/inference/intervening_ivar_reset.rb +303 -0
- data/lib/rigor/inference/ivar_writer_census.rb +195 -0
- data/lib/rigor/inference/loop_value_record.rb +53 -0
- data/lib/rigor/inference/macro_block_self_type.rb +20 -6
- data/lib/rigor/inference/match_rebinding/frame.rb +19 -0
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +278 -42
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +6 -2
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +50 -2
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +53 -20
- data/lib/rigor/inference/method_dispatcher.rb +113 -19
- data/lib/rigor/inference/module_function_state/spellings.rb +64 -0
- data/lib/rigor/inference/module_function_state.rb +149 -42
- data/lib/rigor/inference/mutation_widening.rb +5 -2
- data/lib/rigor/inference/narrowing.rb +116 -11
- data/lib/rigor/inference/object_mixins.rb +13 -1
- data/lib/rigor/inference/parameter_inference_collector.rb +4 -26
- data/lib/rigor/inference/project_patched_methods.rb +168 -4
- data/lib/rigor/inference/project_patched_mixins.rb +162 -0
- data/lib/rigor/inference/project_patched_scanner.rb +51 -12
- data/lib/rigor/inference/project_patched_visibility.rb +214 -0
- data/lib/rigor/inference/project_seed_tables.rb +121 -0
- data/lib/rigor/inference/project_yielder.rb +128 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +113 -0
- data/lib/rigor/inference/refined_dispatch/own_method.rb +41 -12
- data/lib/rigor/inference/reflective_ivar_write.rb +6 -6
- data/lib/rigor/inference/return_barrier.rb +16 -0
- data/lib/rigor/inference/scope_indexer/certainty.rb +9 -0
- data/lib/rigor/inference/scope_indexer/declared_ivar_types.rb +64 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +162 -0
- data/lib/rigor/inference/scope_indexer/unseen_ivar_writers.rb +133 -0
- data/lib/rigor/inference/scope_indexer.rb +1144 -197
- data/lib/rigor/inference/self_call_ivar_writes.rb +29 -12
- data/lib/rigor/inference/singleton_external_ahead.rb +64 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +7 -0
- data/lib/rigor/inference/statement_evaluator.rb +1088 -213
- data/lib/rigor/inference/synthetic_method_index.rb +23 -0
- data/lib/rigor/inference/synthetic_method_scanner/project_members.rb +130 -0
- data/lib/rigor/inference/synthetic_method_scanner.rb +72 -12
- data/lib/rigor/inference/unthreaded_rebinds.rb +3 -1
- data/lib/rigor/language_server/buffer_table.rb +6 -0
- data/lib/rigor/language_server/diagnostic_publisher.rb +20 -6
- data/lib/rigor/language_server/project_context.rb +59 -3
- data/lib/rigor/language_server/server.rb +5 -3
- data/lib/rigor/lens/contract_reader.rb +45 -2
- data/lib/rigor/lens/document.rb +2 -1
- data/lib/rigor/lens/file_reader.rb +12 -2
- data/lib/rigor/lens/members.rb +16 -2
- data/lib/rigor/lens/run.rb +34 -7
- data/lib/rigor/mcp/server.rb +11 -3
- data/lib/rigor/plugin/base.rb +29 -13
- data/lib/rigor/plugin/io_boundary.rb +42 -6
- data/lib/rigor/plugin/isolation.rb +4 -3
- data/lib/rigor/plugin/manifest.rb +29 -3
- data/lib/rigor/plugin/registry.rb +38 -0
- data/lib/rigor/protection/discovery_seed.rb +64 -36
- data/lib/rigor/protection/mutation_cache.rb +8 -2
- data/lib/rigor/rooted_glob.rb +36 -0
- data/lib/rigor/scope/discovery_index.rb +5 -0
- data/lib/rigor/scope/resolution_chain/relevance.rb +14 -0
- data/lib/rigor/scope/resolution_chain.rb +40 -5
- data/lib/rigor/scope.rb +59 -7
- data/lib/rigor/sig_gen/alias_index.rb +2 -1
- data/lib/rigor/sig_gen/classification.rb +4 -1
- data/lib/rigor/sig_gen/generator.rb +465 -49
- data/lib/rigor/sig_gen/layout_index.rb +5 -2
- data/lib/rigor/sig_gen/observation_collector.rb +141 -12
- data/lib/rigor/sig_gen/rbs_validity.rb +1 -1
- data/lib/rigor/sig_gen/renderer.rb +16 -155
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +11 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +21 -5
- data/lib/rigor/sig_gen/write_reporter.rb +203 -0
- data/lib/rigor/sig_gen/write_result.rb +3 -1
- data/lib/rigor/sig_gen/writer.rb +5 -3
- data/lib/rigor/signature_path_audit.rb +4 -2
- data/lib/rigor/type/combinator.rb +4 -3
- data/lib/rigor/type/constant.rb +54 -3
- data/lib/rigor/type/hash_shape.rb +14 -9
- data/lib/rigor/type/struct_instance.rb +3 -2
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +61 -44
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +20 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +6 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +13 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +4 -3
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +4 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +1 -1
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +1 -1
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +5 -3
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +7 -6
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +38 -9
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/target_detector.rb +1 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +1 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +1 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +7 -2
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -5
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +18 -17
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +102 -11
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +4 -2
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +4 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +2 -2
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +2 -2
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer.rb +1 -1
- data/sig/rigor/analysis/baseline.rbs +3 -2
- data/sig/rigor/effects/file_collection.rbs +5 -6
- data/sig/rigor/effects/registry.rbs +8 -6
- data/sig/rigor/effects/summary.rbs +6 -5
- data/sig/rigor/environment.rbs +5 -3
- data/sig/rigor/inference/optimistic_origin.rbs +11 -0
- data/sig/rigor/inference.rbs +6 -0
- data/sig/rigor/plugin/additional_initializer.rbs +5 -5
- data/sig/rigor/plugin/effect_ancestry.rbs +6 -4
- data/sig/rigor/plugin/effect_attribution.rbs +25 -10
- data/sig/rigor/plugin/effect_edge.rbs +12 -5
- data/sig/rigor/plugin/effect_entry_points.rbs +8 -3
- data/sig/rigor/plugin/io_boundary.rbs +5 -2
- data/sig/rigor/plugin/manifest.rbs +16 -18
- data/sig/rigor/plugin/protocol_contract.rbs +10 -9
- data/sig/rigor/plugin/registry.rbs +1 -1
- data/sig/rigor/rooted_glob.rbs +7 -0
- data/sig/rigor/scope.rbs +34 -52
- data/sig/rigor/type.rbs +0 -6
- data/skills/rigor-doctor/references/01-checks.md +23 -11
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +2 -1
- metadata +32 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "prism"
|
|
4
4
|
|
|
5
|
+
require_relative "../analysis/dependency_recorder"
|
|
5
6
|
require_relative "../source/node_children"
|
|
6
7
|
require_relative "../source/parameter_envelope"
|
|
7
8
|
require_relative "../type"
|
|
@@ -139,10 +140,11 @@ module Rigor
|
|
|
139
140
|
# Issue #1596 — gives up when `self`'s class, a project subclass, or a project ancestor or module on either's
|
|
140
141
|
# chain defines a {PROTOCOL_NAMES} method (a `def`, `define_method`, `attr_*` or alias), rewrites its methods
|
|
141
142
|
# beyond the names it spells, or is refined on one; or when either chain holds an external ancestor, whose
|
|
142
|
-
# own definitions the read cannot see.
|
|
143
|
+
# own definitions the read cannot see. Issue #1979 — a class built on a core constructor call
|
|
144
|
+
# (`class Fact < Data.define(:a)`) cannot be `self`'s class or a subclass of it, so the walk leaves it out.
|
|
143
145
|
def no_protocol_override
|
|
144
146
|
classes = [@class_name]
|
|
145
|
-
RefinedDispatch::OwnMethod.each_subclass(@scope, @class_name) { |subclass| classes << subclass }
|
|
147
|
+
RefinedDispatch::OwnMethod.each_subclass(@scope, @class_name, possible_only: true) { |subclass| classes << subclass }
|
|
146
148
|
classes.each do |class_name|
|
|
147
149
|
chain = Scope::ResolutionChain.for(@scope, class_name.to_s, :instance, :methods)
|
|
148
150
|
unprovable! if chain.truncated? || chain.wildcard_mixin? || !settled?(chain)
|
|
@@ -185,7 +187,16 @@ module Rigor
|
|
|
185
187
|
|
|
186
188
|
# Whether a `refine` block anywhere in the project defines `name`, on any class: a `using` in effect where the
|
|
187
189
|
# read code sits may route the call to it (`refine Kernel do def warn …`), whatever the receiver.
|
|
190
|
+
#
|
|
191
|
+
# Issue #2163 — the answer reads every file's refinements whole, and a refined class off the chain (`Kernel`,
|
|
192
|
+
# `IO`, `String`) is no `mark:` the chain read files, so it records `refinement:<name>` and `refinement:*`
|
|
193
|
+
# whichever way it answers, as `InEffectRefinements` consumers do: a file that starts or stops refining the
|
|
194
|
+
# name re-checks the reader.
|
|
188
195
|
def refined?(name)
|
|
196
|
+
if Analysis::DependencyRecorder.active?
|
|
197
|
+
Analysis::DependencyRecorder.read_name(:refinement, name)
|
|
198
|
+
Analysis::DependencyRecorder.read_name(:refinement, Scope::DiscoveryIndex::REFINEMENT_WILDCARD)
|
|
199
|
+
end
|
|
189
200
|
@scope.discovered_refinements.any? { |_refined, methods| methods.key?(name) }
|
|
190
201
|
end
|
|
191
202
|
|
|
@@ -229,7 +240,7 @@ module Rigor
|
|
|
229
240
|
|
|
230
241
|
# A subclass whose superclass the tables do not know is enumerated too, and its chain ends short of the
|
|
231
242
|
# owner; one that reaches no definer of its own leaves the call to its superclass.
|
|
232
|
-
RefinedDispatch::OwnMethod.each_subclass(@scope, @class_name) do |subclass|
|
|
243
|
+
RefinedDispatch::OwnMethod.each_subclass(@scope, @class_name, possible_only: true) do |subclass|
|
|
233
244
|
unprovable! unless [owner, nil].include?(definer_ahead(subclass, name, owner))
|
|
234
245
|
end
|
|
235
246
|
def_node
|
|
@@ -239,12 +250,11 @@ module Rigor
|
|
|
239
250
|
# one file, with one `def` of the name there (a reopening or a `class_eval` body in the same file is a second
|
|
240
251
|
# one), and no `define_method`, `attr_*` or alias of it, nor a rewrite no literal names (`T.define_method`,
|
|
241
252
|
# `T.send(:define_method, …)`, `T.class_eval` with a computed name), nor a definition the walk could not prove
|
|
242
|
-
# runs (a possible or contested one, as `DefinerResolution` reads them).
|
|
243
|
-
# file.
|
|
253
|
+
# runs (a possible or contested one, as `DefinerResolution` reads them). `Scope#parameter_envelopes_of` files
|
|
254
|
+
# the class edge to every declaring file and, issue #2137, the `mark:` edge for a file that only marks it.
|
|
244
255
|
def single_definition(owner, name)
|
|
245
|
-
|
|
256
|
+
bucket = @scope.parameter_envelopes_of(owner)
|
|
246
257
|
unprovable! if possible_definition?(owner, name)
|
|
247
|
-
bucket = @scope.discovered_parameter_envelopes[owner] || {}
|
|
248
258
|
unprovable! if bucket[[:instance, name]] == Source::ParameterEnvelope::OPAQUE
|
|
249
259
|
unprovable! if (@scope.discovered_class_sources[owner]&.size || 0) > 1
|
|
250
260
|
unprovable! if definition_count(owner, name) > 1
|
|
@@ -258,9 +268,11 @@ module Rigor
|
|
|
258
268
|
end
|
|
259
269
|
|
|
260
270
|
def definition_count(owner, name)
|
|
261
|
-
|
|
262
|
-
|
|
271
|
+
count = 0
|
|
272
|
+
@scope.discovered_deferred_ranges.each_value do |rows|
|
|
273
|
+
count += rows.count { |row| row[2] == name && row[3] == :instance && row[4] == owner }
|
|
263
274
|
end
|
|
275
|
+
count
|
|
264
276
|
end
|
|
265
277
|
|
|
266
278
|
# Whether `chain`'s own order stands with no second world: no order mark and no fork. `ResolutionChain#settle`
|
|
@@ -276,9 +288,12 @@ module Rigor
|
|
|
276
288
|
end
|
|
277
289
|
|
|
278
290
|
# Whether the project rewrites `class_name`'s method table beyond the names it spells, or refines it.
|
|
291
|
+
#
|
|
292
|
+
# Issue #2137 — read through `Scope#parameter_envelopes_of`, which files the `mark:` edge: a `refine` of the
|
|
293
|
+
# class from a file whose declared classes do not change fires no class key, and adding or removing it must
|
|
294
|
+
# re-check the reader.
|
|
279
295
|
def rewritten?(class_name)
|
|
280
|
-
|
|
281
|
-
!bucket.nil? && Scope::DiscoveryIndex.rewritten_surface?(bucket)
|
|
296
|
+
Scope::DiscoveryIndex.rewritten_surface?(@scope.parameter_envelopes_of(class_name))
|
|
282
297
|
end
|
|
283
298
|
|
|
284
299
|
# The first project class or module on `class_name`'s settled instance chain that defines `name`, stopping
|
|
@@ -326,8 +341,10 @@ module Rigor
|
|
|
326
341
|
return nil if loader.nil? || !loader.core_or_stdlib_class?(type.class_name)
|
|
327
342
|
|
|
328
343
|
segment = node.name.to_s
|
|
344
|
+
suffix = "::#{segment}"
|
|
329
345
|
project = [@scope.discovered_classes, @scope.in_source_constants]
|
|
330
|
-
|
|
346
|
+
ends_with_segment = ->(name) { (name = name.to_s) == segment || name.end_with?(suffix) }
|
|
347
|
+
return nil if project.any? { |table| table.each_key.any?(&ends_with_segment) }
|
|
331
348
|
|
|
332
349
|
type
|
|
333
350
|
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Inference
|
|
5
|
+
# Issue #1572 — the singleton typing site's external-ahead decline. That site still answers from
|
|
6
|
+
# {Scope#singleton_def_through_ancestors}, which passes the chain's external entries over, so `extend M; extend
|
|
7
|
+
# Enumerable` typed `C.to_a` from `M#to_a` although Ruby calls `Enumerable#to_a` (`C.singleton_class.ancestors`
|
|
8
|
+
# starts `[#<Class:C>, Enumerable, M]`). The instance typing site reads `DefinerResolution`, which already
|
|
9
|
+
# declines there.
|
|
10
|
+
#
|
|
11
|
+
# {.withhold?} is true when the read must withhold (the call types `Dynamic`): the singleton chain holds no
|
|
12
|
+
# project entry that writes the name; the reader's `owner` has no project entry on it; or an external entry ahead
|
|
13
|
+
# of the later of the two may answer first, because RBS does not know it or declares the name in it (the test
|
|
14
|
+
# `DefinerResolution` applies, `ResolutionChain::Relevance.external_lacks_on?`). The later of the two, because
|
|
15
|
+
# where the chain does not stand the reader answers master's owner. An entry writes the name with its own `def`,
|
|
16
|
+
# never a copy the extends fold put on a class object (`RefinedDispatch::ClassObject.fold_copy?`, which also
|
|
17
|
+
# matches a copy by location where the two tables came from two parses of the file), so a folded `M#to_a`
|
|
18
|
+
# answers at `M`'s own position.
|
|
19
|
+
#
|
|
20
|
+
# ADR-46: the search files the class edge of the root and of every project entry ahead of the definer, and each
|
|
21
|
+
# tested external files the negative class edge on its spelling's last segment, as `DefinerResolution` does.
|
|
22
|
+
module SingletonExternalAhead
|
|
23
|
+
module_function
|
|
24
|
+
|
|
25
|
+
def withhold?(scope, class_name, method_name, owner)
|
|
26
|
+
chain = Scope::ResolutionChain.for(scope, class_name.to_s, :singleton, :methods)
|
|
27
|
+
definer = first_writer_index(scope, chain, method_name)
|
|
28
|
+
return true if definer.nil?
|
|
29
|
+
|
|
30
|
+
owner_index = chain.entries.index { |entry| !entry.external? && entry.name == owner.to_s }
|
|
31
|
+
return true if owner_index.nil?
|
|
32
|
+
|
|
33
|
+
external_ahead_may_answer?(scope, chain, method_name, [definer, owner_index].max)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def first_writer_index(scope, chain, method_name)
|
|
37
|
+
index = -1
|
|
38
|
+
chain.search(scope) do |entry|
|
|
39
|
+
index += 1
|
|
40
|
+
!entry.external? && writes_name?(scope, entry, method_name)
|
|
41
|
+
end && index
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def writes_name?(scope, entry, method_name)
|
|
45
|
+
return !scope.user_def_for(entry.name, method_name).nil? unless entry.side == :singleton
|
|
46
|
+
|
|
47
|
+
!scope.singleton_def_for(entry.name, method_name).nil? &&
|
|
48
|
+
!RefinedDispatch::ClassObject.fold_copy?(scope, entry.name, method_name)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def external_ahead_may_answer?(scope, chain, method_name, stop)
|
|
52
|
+
recording = Analysis::DependencyRecorder.active?
|
|
53
|
+
chain.entries.first(stop).any? do |entry|
|
|
54
|
+
next false unless entry.external?
|
|
55
|
+
|
|
56
|
+
Analysis::DependencyRecorder.read_missing(:class, entry.raw.to_s.split("::").last) if recording
|
|
57
|
+
!Scope::ResolutionChain::Relevance.external_lacks_on?(scope, entry.candidates, entry.side, method_name)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private_class_method :first_writer_index, :writes_name?, :external_ahead_may_answer?
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -109,6 +109,13 @@ module Rigor
|
|
|
109
109
|
nesting&.first
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
+
# Issue #1722 — the hook-capable test for one chain entry, asked by `call.undefined-method` of a project module
|
|
113
|
+
# mixed into a core class: a module whose `self.included(base)` hook writes `base.class_eval { def x }` gives
|
|
114
|
+
# the includer methods no table records.
|
|
115
|
+
def entry_hook_capable?(scope, entry, flavor = :methods)
|
|
116
|
+
Context.new(scope, flavor).capable?(entry)
|
|
117
|
+
end
|
|
118
|
+
|
|
112
119
|
def tested_levels(chain, from, bound)
|
|
113
120
|
starts = chain.level_starts
|
|
114
121
|
size = chain.entries.size
|