rigortype 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -3
- data/docs/handbook/08-understanding-errors.md +3 -2
- data/docs/install.md +87 -15
- data/docs/manual/02-cli-reference.md +2 -2
- data/docs/manual/03-configuration.md +5 -0
- data/docs/manual/08-skills.md +4 -3
- data/docs/manual/12-caching.md +43 -4
- data/docs/manual/14-rails-quickstart.md +19 -11
- data/lib/rigor/analysis/check_rules/source_arity.rb +163 -59
- data/lib/rigor/analysis/check_rules.rb +118 -87
- data/lib/rigor/analysis/dependency_recorder.rb +200 -18
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +266 -0
- data/lib/rigor/analysis/incremental_run_slot.rb +171 -0
- data/lib/rigor/analysis/incremental_session.rb +273 -49
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +24 -13
- data/lib/rigor/analysis/reachability/scan_cache.rb +2 -1
- data/lib/rigor/analysis/run_cache_key.rb +27 -8
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +1 -1
- data/lib/rigor/analysis/runner/pool_coordinator.rb +2 -2
- data/lib/rigor/analysis/runner/project_pre_passes.rb +21 -13
- data/lib/rigor/analysis/runner.rb +337 -46
- data/lib/rigor/analysis/shadow_harness.rb +27 -0
- data/lib/rigor/analysis/source_rbs_gate.rb +157 -0
- data/lib/rigor/analysis/template_unit_paths.rb +6 -4
- data/lib/rigor/analysis/template_units.rb +15 -5
- data/lib/rigor/analysis/worker_session.rb +4 -3
- data/lib/rigor/cache/descriptor.rb +40 -1
- data/lib/rigor/cache/file_digest.rb +28 -0
- data/lib/rigor/cache/incremental_snapshot.rb +70 -8
- data/lib/rigor/cache/store.rb +63 -3
- data/lib/rigor/cache/value_digest.rb +325 -0
- data/lib/rigor/cli/check_command.rb +83 -13
- data/lib/rigor/cli/doctor_command.rb +1 -1
- data/lib/rigor/cli/effects_report.rb +2 -2
- data/lib/rigor/cli/unused_command.rb +3 -3
- data/lib/rigor/cli.rb +1 -1
- data/lib/rigor/config_audit.rb +3 -2
- data/lib/rigor/config_path.rb +29 -0
- data/lib/rigor/configuration/severity_profile.rb +5 -0
- data/lib/rigor/configuration.rb +6 -5
- data/lib/rigor/effects/plugin_facts.rb +6 -6
- data/lib/rigor/environment/bundle_sig_discovery.rb +5 -3
- data/lib/rigor/environment/lockfile_resolver.rb +10 -1
- data/lib/rigor/environment/rbs_collection_discovery.rb +10 -1
- data/lib/rigor/environment/rbs_loader.rb +1 -1
- data/lib/rigor/environment/source_rbs_synthesis.rb +147 -0
- data/lib/rigor/environment.rb +13 -70
- data/lib/rigor/inference/block_parameter_binder.rb +29 -13
- data/lib/rigor/inference/captured_locals.rb +7 -1
- data/lib/rigor/inference/declaration_walk/context.rb +195 -0
- data/lib/rigor/inference/declaration_walk/errors.rb +18 -0
- data/lib/rigor/inference/declaration_walk/shadow.rb +147 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +441 -0
- data/lib/rigor/inference/declaration_walk.rb +7 -0
- data/lib/rigor/inference/def_node_resolver.rb +3 -2
- data/lib/rigor/inference/definer_resolution.rb +266 -0
- data/lib/rigor/inference/expression_typer.rb +136 -45
- data/lib/rigor/inference/external_ancestor_resolution.rb +13 -16
- data/lib/rigor/inference/guard_rebinding.rb +53 -12
- data/lib/rigor/inference/macro_block_self_type.rb +14 -2
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +46 -26
- data/lib/rigor/inference/module_function_state.rb +213 -0
- data/lib/rigor/inference/multi_target_binder.rb +21 -16
- data/lib/rigor/inference/narrowing.rb +147 -17
- data/lib/rigor/inference/parameter_inference_collector.rb +10 -9
- data/lib/rigor/inference/scope_indexer/certainty.rb +176 -0
- data/lib/rigor/inference/scope_indexer/class_cvars_collector.rb +35 -0
- data/lib/rigor/inference/scope_indexer/def_nestings_collector.rb +47 -0
- data/lib/rigor/inference/scope_indexer/layered_def_nestings.rb +36 -0
- data/lib/rigor/inference/scope_indexer/member_layouts_collector.rb +61 -0
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +130 -0
- data/lib/rigor/inference/scope_indexer/superclasses_collector.rb +64 -0
- data/lib/rigor/inference/scope_indexer.rb +1443 -295
- data/lib/rigor/inference/singleton_hook_decline.rb +253 -0
- data/lib/rigor/inference/statement_evaluator.rb +80 -14
- data/lib/rigor/plugin/base.rb +28 -8
- data/lib/rigor/plugin/io_boundary.rb +82 -4
- data/lib/rigor/plugin/isolation.rb +1 -1
- data/lib/rigor/plugin/trust_policy.rb +3 -3
- data/lib/rigor/protection/discovery_seed.rb +18 -9
- data/lib/rigor/protection/mutation_cache.rb +3 -3
- data/lib/rigor/reflection/constant_ancestors.rb +96 -47
- data/lib/rigor/reflection/constant_path.rb +22 -7
- data/lib/rigor/reflection.rb +2 -3
- data/lib/rigor/scope/discovery_index.rb +218 -2
- data/lib/rigor/scope/resolution_chain/relevance.rb +165 -0
- data/lib/rigor/scope/resolution_chain.rb +884 -0
- data/lib/rigor/scope.rb +295 -322
- data/lib/rigor/sig_gen/alias_index.rb +1 -1
- data/lib/rigor/sig_gen/effect_annotation.rb +2 -2
- data/lib/rigor/sig_gen/generator.rb +22 -16
- data/lib/rigor/type/combinator.rb +25 -1
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +10 -0
- data/sig/rigor/environment.rbs +2 -0
- data/sig/rigor/plugin/io_boundary.rbs +1 -0
- data/sig/rigor/scope.rbs +43 -1
- data/skills/rigor-project-init/SKILL.md +37 -11
- data/skills/rigor-project-init/references/02-configure.md +7 -2
- metadata +25 -1
|
@@ -182,8 +182,8 @@ module Rigor
|
|
|
182
182
|
def relative_path(path)
|
|
183
183
|
return nil if path.nil?
|
|
184
184
|
|
|
185
|
-
expanded = File.
|
|
186
|
-
root = "#{File.
|
|
185
|
+
expanded = File.absolute_path(path.to_s)
|
|
186
|
+
root = "#{File.absolute_path(Dir.pwd)}#{File::SEPARATOR}"
|
|
187
187
|
expanded.start_with?(root) ? expanded.delete_prefix(root) : nil
|
|
188
188
|
end
|
|
189
189
|
|
|
@@ -13,6 +13,7 @@ require_relative "../source/literals"
|
|
|
13
13
|
require_relative "../source/node_children"
|
|
14
14
|
require_relative "../inference/def_return_typer"
|
|
15
15
|
require_relative "../inference/scope_indexer"
|
|
16
|
+
require_relative "../inference/module_function_state"
|
|
16
17
|
require_relative "../inference/rbs_type_translator"
|
|
17
18
|
require_relative "alias_index"
|
|
18
19
|
require_relative "meta_class_shape"
|
|
@@ -464,7 +465,7 @@ module Rigor
|
|
|
464
465
|
@class_superclasses = {}
|
|
465
466
|
@meta_layouts = collect_meta_layouts(scope_index)
|
|
466
467
|
register_meta_classes
|
|
467
|
-
defs = collect_method_definitions(parse_result.value)
|
|
468
|
+
defs = collect_method_definitions(parse_result.value, scope_index)
|
|
468
469
|
# Candidate construction freezes the per-file maps above (see {#build_candidate}), so every registration
|
|
469
470
|
# pass has to be finished before the first `build_candidate` call. Meta members lead the RETURNED order —
|
|
470
471
|
# a value class's members and constructors read first, ahead of the methods its block body defines.
|
|
@@ -497,7 +498,8 @@ module Rigor
|
|
|
497
498
|
# - `@module_function_methods` records `(class_name, method_name)` pairs where a `module_function` (no
|
|
498
499
|
# args) call preceded the `def` inside a module body. The renderer emits `def self?.name` for these, the
|
|
499
500
|
# RBS spelling that matches the dual instance + singleton dispatch the runtime produces.
|
|
500
|
-
def collect_method_definitions(root)
|
|
501
|
+
def collect_method_definitions(root, scope_index)
|
|
502
|
+
@declared_types = scope_index[root].declared_types
|
|
501
503
|
out = []
|
|
502
504
|
walk_defs(root, [], false, false, out)
|
|
503
505
|
out
|
|
@@ -542,6 +544,11 @@ module Rigor
|
|
|
542
544
|
# `prefix` stays the nesting the header is WRITTEN in for {#record_superclass}: `::` re-anchors the
|
|
543
545
|
# declaration, not the superclass expression beside it, which Ruby still evaluates in the enclosing cref.
|
|
544
546
|
def descend_into_namespace?(node, prefix, out)
|
|
547
|
+
# Issue #1518 — a `class self::X` / `module self::X` the indexer declined (`self` is opaque, as under
|
|
548
|
+
# `REGISTRY.first.class_eval`) names no class, so its body must not be written out under the lexical
|
|
549
|
+
# `X`. The indexer's identity table is the single source of that decision.
|
|
550
|
+
return true if declined_self_header?(node)
|
|
551
|
+
|
|
545
552
|
child_prefix = Source::ConstantPath.declaration_prefix(prefix, node.constant_path)
|
|
546
553
|
return false unless child_prefix
|
|
547
554
|
|
|
@@ -552,6 +559,12 @@ module Rigor
|
|
|
552
559
|
true
|
|
553
560
|
end
|
|
554
561
|
|
|
562
|
+
def declined_self_header?(node)
|
|
563
|
+
path = node.constant_path
|
|
564
|
+
path.is_a?(Prism::ConstantPathNode) && path.parent.is_a?(Prism::SelfNode) &&
|
|
565
|
+
!@declared_types.key?(path)
|
|
566
|
+
end
|
|
567
|
+
|
|
555
568
|
# ADR-14: a generated subclass declaration MUST carry its superclass, or the sidecar `sig/` misrepresents
|
|
556
569
|
# the class (inherited members vanish → receiver dispatch degrades to `Dynamic`) and, worse, a nested
|
|
557
570
|
# reference to an inherited type re-declares the class as a bare namespace on the RBS side and can
|
|
@@ -662,29 +675,22 @@ module Rigor
|
|
|
662
675
|
walk_defs(namespace_node.body, prefix, false, false, out)
|
|
663
676
|
end
|
|
664
677
|
|
|
678
|
+
# The directive's reach is {Inference::ModuleFunctionState.each_sig_gen_statement}.
|
|
665
679
|
def walk_statements(stmts_node, prefix, in_singleton_class, module_function_active, out)
|
|
666
|
-
stmts_node.body
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
next
|
|
670
|
-
end
|
|
671
|
-
walk_defs(stmt, prefix, in_singleton_class, module_function_active, out)
|
|
680
|
+
Inference::ModuleFunctionState.each_sig_gen_statement(stmts_node.body,
|
|
681
|
+
module_function_active) do |stmt, active|
|
|
682
|
+
walk_defs(stmt, prefix, in_singleton_class, active, out)
|
|
672
683
|
end
|
|
673
684
|
end
|
|
674
685
|
|
|
675
|
-
def module_function_directive?(node)
|
|
676
|
-
return false unless node.is_a?(Prism::CallNode)
|
|
677
|
-
return false unless node.name == :module_function && node.receiver.nil?
|
|
678
|
-
|
|
679
|
-
(node.arguments&.arguments || []).empty?
|
|
680
|
-
end
|
|
681
|
-
|
|
682
686
|
def collect_def_node(node, prefix, in_singleton_class, module_function_active, out)
|
|
683
687
|
return if prefix.empty?
|
|
684
688
|
|
|
685
689
|
kind = node.receiver.is_a?(Prism::SelfNode) || in_singleton_class ? :singleton : :instance
|
|
686
690
|
class_name = prefix.join("::")
|
|
687
|
-
|
|
691
|
+
if Inference::ModuleFunctionState.sig_gen_module_function?(module_function_active, kind)
|
|
692
|
+
@module_function_methods << [class_name, node.name]
|
|
693
|
+
end
|
|
688
694
|
out << [node, class_name, kind]
|
|
689
695
|
end
|
|
690
696
|
|
|
@@ -991,13 +991,37 @@ module Rigor
|
|
|
991
991
|
end
|
|
992
992
|
end
|
|
993
993
|
|
|
994
|
+
# The order a new union or intersection keeps: by each member's `describe(:short)`, which is
|
|
995
|
+
# observable in messages and in cache fingerprints, so it must not move. Two members, the common
|
|
996
|
+
# case, compare directly instead of paying `sort_by`'s work arrays; `sort_by` keeps an equal pair in
|
|
997
|
+
# place as well ([#1505](https://github.com/rigortype/rigor/issues/1505)).
|
|
994
998
|
def sort_members(members)
|
|
995
|
-
members.
|
|
999
|
+
if members.size == 2
|
|
1000
|
+
first, second = members
|
|
1001
|
+
return sort_key(second) < sort_key(first) ? [second, first] : members
|
|
1002
|
+
end
|
|
1003
|
+
|
|
1004
|
+
members.sort_by { |member| sort_key(member) }
|
|
1005
|
+
end
|
|
1006
|
+
|
|
1007
|
+
# A member's `describe(:short)`, rendered at most once per type instance between garbage collections.
|
|
1008
|
+
# No type carrier has a method that changes it once built (a built type is frozen; one `Marshal.load`
|
|
1009
|
+
# restores is not, but nothing mutates it either), so a memoised key cannot go stale. The memo is weak
|
|
1010
|
+
# in both key and value: it keeps neither the type nor the string alive, and an entry whose string
|
|
1011
|
+
# nothing else holds is dropped at the next GC. It is keyed by identity on purpose: `Constant[0.0]` and
|
|
1012
|
+
# `Constant[-0.0]` are equal and hash alike, but render differently. A non-main Ractor may not read the
|
|
1013
|
+
# module's ivar, so a pool worker renders the key every time, as every run did before.
|
|
1014
|
+
def sort_key(member)
|
|
1015
|
+
return member.describe(:short) unless Ractor.main?
|
|
1016
|
+
|
|
1017
|
+
@sort_keys[member] ||= member.describe(:short)
|
|
996
1018
|
end
|
|
997
1019
|
end
|
|
998
1020
|
|
|
999
1021
|
# Eager-allocated at load time; see `untyped` method comment above.
|
|
1000
1022
|
@untyped = Dynamic.new(Top.instance)
|
|
1023
|
+
# The main Ractor's {sort_key} memo, allocated here for the same reason.
|
|
1024
|
+
@sort_keys = ObjectSpace::WeakMap.new
|
|
1001
1025
|
|
|
1002
1026
|
NIL_CONSTANT = Constant.new(nil)
|
|
1003
1027
|
TRUE_CONSTANT = Constant.new(true)
|
data/lib/rigor/version.rb
CHANGED
|
@@ -137,6 +137,16 @@ module Rigor
|
|
|
137
137
|
@exceptions = config["exceptions"] || []
|
|
138
138
|
end
|
|
139
139
|
|
|
140
|
+
# ADR-88 channel (c) — the detected `:ffx` / `:ffi` target decides whether the `plugin.ffi.ffx.unsupported-*`
|
|
141
|
+
# rules fire, and {TargetDetector} reads `<root>/Gemfile.lock` and `ext/**/extconf.rb` directly, not the
|
|
142
|
+
# lockfile `bundler.lockfile:` resolves to — so neither the `--incremental` snapshot's gem-set digest nor an
|
|
143
|
+
# edit to an analysed file covers a change in them. Declaring the target makes a flip send the warm
|
|
144
|
+
# snapshot cold. Everything else this plugin contributes is per-file or comes from the `ffi_catalog`
|
|
145
|
+
# producer (channel b).
|
|
146
|
+
def incremental_state_fingerprint
|
|
147
|
+
"target:#{@target || :ffi}"
|
|
148
|
+
end
|
|
149
|
+
|
|
140
150
|
private
|
|
141
151
|
|
|
142
152
|
# Every discovered name in both `dynamic_return receivers:` kinds (#701), for the two rules whose
|
data/sig/rigor/environment.rbs
CHANGED
|
@@ -20,6 +20,8 @@ module Rigor
|
|
|
20
20
|
|
|
21
21
|
def self.default: () -> Environment
|
|
22
22
|
def self.for_project: (?root: String, ?libraries: Array[String], ?signature_paths: Array[String | _ToPath]?, ?cache_store: untyped?, ?plugin_registry: untyped?, ?dependency_source_index: untyped?, ?rbs_extended_reporter: untyped?, ?boundary_cross_reporter: untyped?, ?source_rbs_synthesis_reporter: untyped?, ?bundler_bundle_path: String?, ?bundler_auto_detect: bool, ?synthetic_method_index: untyped?, ?project_patched_methods: untyped?) -> Environment
|
|
23
|
+
# authored: the return is the `signature_paths:` argument's type (authored intent) or the default [Pathname]; sig-gen types the `||` fallback untyped.
|
|
24
|
+
def self.project_signature_roots: (Array[String | _ToPath]? signature_paths, ?root: String) -> Array[String | _ToPath]
|
|
23
25
|
|
|
24
26
|
def initialize: (?class_registry: ClassRegistry, ?rbs_loader: RbsLoader?, ?plugin_registry: untyped?, ?dependency_source_index: untyped?, ?rbs_extended_reporter: untyped?, ?boundary_cross_reporter: untyped?, ?source_rbs_synthesis_reporter: untyped?, ?synthetic_method_index: untyped?, ?project_patched_methods: untyped?) -> void
|
|
25
27
|
def rbs_extended_reporter: () -> untyped?
|
data/sig/rigor/scope.rbs
CHANGED
|
@@ -37,6 +37,9 @@ module Rigor
|
|
|
37
37
|
# Issue #1429 — the pre-guard type of each global or constant a guard narrowed.
|
|
38
38
|
# sig-gen gap: #1154 — a reader over an ivar `initialize` assigns from a parameter.
|
|
39
39
|
attr_reader guard_records: Hash[[Symbol, Symbol | String], Type::t]
|
|
40
|
+
# Issue #1446 — the classes a class guard narrowed a `bot` receiver to.
|
|
41
|
+
# sig-gen gap: #1154 — a reader over an ivar `initialize` assigns from a parameter.
|
|
42
|
+
attr_reader bot_guard_classes: Hash[[Symbol, Symbol | String], Array[String]]
|
|
40
43
|
|
|
41
44
|
# ADR-53 Track A — the seed-time discovery tables live on the
|
|
42
45
|
# DiscoveryIndex; Scope keeps per-table readers as delegates.
|
|
@@ -154,10 +157,38 @@ module Rigor
|
|
|
154
157
|
# `untyped`: the value is an `Inference::LastLine::SelfEvidence` (or nil), and that class carries no signature,
|
|
155
158
|
# as `Inference::MatchRebinding::Frame` carries none for `match_frame`.
|
|
156
159
|
attr_reader implicit_self_evidence: untyped
|
|
160
|
+
# sig-gen gap: #1150 — `Data.define` members carry no type, as for every other row in this class.
|
|
161
|
+
attr_reader possible_discovered_methods: Hash[String, Hash[Symbol, Symbol]]
|
|
162
|
+
# sig-gen gap: #1150 — `Data.define` members carry no type, as for every other row in this class.
|
|
163
|
+
attr_reader possible_discovered_deferred_ranges: Hash[String, Array[[Integer, Integer, Symbol?, Symbol?, String?]]]
|
|
164
|
+
# sig-gen gap: #1150 — `Data.define` members carry no type, as for every other row in this class.
|
|
165
|
+
attr_reader contested_discovered_def_nodes: Set[Array[untyped]]
|
|
166
|
+
# sig-gen gap: #1150 — `Data.define` members carry no type, as for every other row in this class.
|
|
167
|
+
attr_reader contested_discovered_singleton_def_nodes: Set[Array[untyped]]
|
|
168
|
+
# sig-gen gap: #1150 — `Data.define` members carry no type, as for every other row in this class.
|
|
169
|
+
attr_reader contested_discovered_method_visibilities: Set[Array[untyped]]
|
|
170
|
+
# sig-gen gap: #1150 — `Data.define` members carry no type, as for every other row in this class.
|
|
171
|
+
attr_reader contested_discovered_parameter_envelopes: Set[Array[untyped]]
|
|
157
172
|
|
|
158
173
|
EMPTY: DiscoveryIndex
|
|
174
|
+
# authored: ADR-119 WD1 — hand-written beside the `Data.define` rows above (#1150).
|
|
175
|
+
# authored: ADR-119 WD1 sibling pairing; no inferred signature exists for it (#1150).
|
|
176
|
+
SIBLINGS: Hash[Symbol, Symbol]
|
|
177
|
+
# authored: ADR-119 WD1 sibling pairing; no inferred signature exists for it (#1150).
|
|
178
|
+
EMPTY_SIBLINGS: Hash[Symbol, untyped]
|
|
179
|
+
|
|
180
|
+
# authored: ADR-119 WD1 sibling pairing; no inferred signature exists for it (#1150).
|
|
181
|
+
def self.empty_value: (Symbol name) -> untyped
|
|
182
|
+
# authored: ADR-119 WD1 sibling pairing; no inferred signature exists for it (#1150).
|
|
183
|
+
def self.empty_siblings: () -> Hash[Symbol, untyped]
|
|
184
|
+
# authored: ADR-119 WD1 sibling pairing; no inferred signature exists for it (#1150).
|
|
185
|
+
def self.compact_pairs: (Hash[Symbol, untyped] tables) -> Hash[Symbol, untyped]
|
|
186
|
+
# authored: ADR-119 WD1 sibling pairing; no inferred signature exists for it (#1150).
|
|
187
|
+
def self.paired?: (Symbol name) -> bool
|
|
188
|
+
# authored: ADR-119 WD1 sibling pairing; no inferred signature exists for it (#1150).
|
|
189
|
+
def sibling_tables: () -> Hash[Symbol, untyped]
|
|
159
190
|
|
|
160
|
-
def with: (?declared_types: Hash[untyped, Type::t], ?class_ivars: Hash[String, Hash[Symbol, Type::t]], ?class_cvars: Hash[String, Hash[Symbol, Type::t]], ?program_globals: Hash[Symbol, Type::t], ?program_global_seeds: Hash[Symbol, Type::t], ?discovered_classes: Hash[String, Type::Singleton], ?in_source_constants: Hash[String, Type::t], ?discovered_methods: Hash[String, Hash[Symbol, Symbol]], ?discovered_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_def_nestings: Hash[untyped, Array[String]], ?discovered_singleton_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_def_sources: Hash[String, Hash[Symbol, String]], ?discovered_singleton_def_sources: Hash[String, Hash[Symbol, String]], ?discovered_method_visibilities: Hash[String, Hash[Symbol, Symbol]], ?discovered_parameter_envelopes: Hash[String, Hash[untyped, untyped]], ?discovered_superclasses: Hash[String, String], ?discovered_includes: Hash[String, Array[String]], ?discovered_prepends: Hash[String, Array[String]], ?discovered_extends: Hash[String, Array[String]], ?discovered_class_sources: Hash[String, Set[String]], ?constant_sources: Hash[String, Set[String]], ?constant_writers: Hash[String, Array[String]], ?constant_shadowers: Hash[String, Array[String]], ?published_constant_names: Set[String], ?local_constant_names: Set[String], ?published_constant_alias_names: Set[String], ?published_constant_ivars: Hash[String, Set[Symbol]], ?data_member_layouts: Hash[String, Array[Symbol]], ?struct_member_layouts: Hash[String, { members: Array[Symbol], keyword_init: bool }], ?param_inferred_types: Hash[[String, Symbol, Symbol], Hash[Symbol, Type::t]], ?discovered_deferred_ranges: Hash[String, Array[[Integer, Integer, Symbol?, Symbol?, String?]]], ?discovered_refinements: Hash[String, Hash[Symbol, Array[String]]], ?discovered_global_write_census: Set[Array[untyped]], ?run_generation: Object?, ?patched_line_readers: Set[Symbol], ?clears_last_status: bool, ?defines_case_equality: bool, ?implicit_self_evidence: untyped) -> DiscoveryIndex
|
|
191
|
+
def with: (?declared_types: Hash[untyped, Type::t], ?class_ivars: Hash[String, Hash[Symbol, Type::t]], ?class_cvars: Hash[String, Hash[Symbol, Type::t]], ?program_globals: Hash[Symbol, Type::t], ?program_global_seeds: Hash[Symbol, Type::t], ?discovered_classes: Hash[String, Type::Singleton], ?in_source_constants: Hash[String, Type::t], ?discovered_methods: Hash[String, Hash[Symbol, Symbol]], ?discovered_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_def_nestings: Hash[untyped, Array[String]], ?discovered_singleton_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_def_sources: Hash[String, Hash[Symbol, String]], ?discovered_singleton_def_sources: Hash[String, Hash[Symbol, String]], ?discovered_method_visibilities: Hash[String, Hash[Symbol, Symbol]], ?discovered_parameter_envelopes: Hash[String, Hash[untyped, untyped]], ?discovered_superclasses: Hash[String, String], ?discovered_includes: Hash[String, Array[String]], ?discovered_prepends: Hash[String, Array[String]], ?discovered_extends: Hash[String, Array[String]], ?discovered_class_sources: Hash[String, Set[String]], ?constant_sources: Hash[String, Set[String]], ?constant_writers: Hash[String, Array[String]], ?constant_shadowers: Hash[String, Array[String]], ?published_constant_names: Set[String], ?local_constant_names: Set[String], ?published_constant_alias_names: Set[String], ?published_constant_ivars: Hash[String, Set[Symbol]], ?data_member_layouts: Hash[String, Array[Symbol]], ?struct_member_layouts: Hash[String, { members: Array[Symbol], keyword_init: bool }], ?param_inferred_types: Hash[[String, Symbol, Symbol], Hash[Symbol, Type::t]], ?discovered_deferred_ranges: Hash[String, Array[[Integer, Integer, Symbol?, Symbol?, String?]]], ?discovered_refinements: Hash[String, Hash[Symbol, Array[String]]], ?discovered_global_write_census: Set[Array[untyped]], ?run_generation: Object?, ?patched_line_readers: Set[Symbol], ?clears_last_status: bool, ?defines_case_equality: bool, ?implicit_self_evidence: untyped, ?possible_discovered_methods: Hash[String, Hash[Symbol, Symbol]], ?possible_discovered_deferred_ranges: Hash[String, Array[[Integer, Integer, Symbol?, Symbol?, String?]]], ?contested_discovered_def_nodes: Set[Array[untyped]], ?contested_discovered_singleton_def_nodes: Set[Array[untyped]], ?contested_discovered_method_visibilities: Set[Array[untyped]], ?contested_discovered_parameter_envelopes: Set[Array[untyped]]) -> DiscoveryIndex
|
|
161
192
|
end
|
|
162
193
|
|
|
163
194
|
class IndexedKey
|
|
@@ -206,6 +237,15 @@ module Rigor
|
|
|
206
237
|
# Issue #1429 — `rigor sig-gen` output; the parameters are not inferred here, as for `with_mutated_local`.
|
|
207
238
|
def with_guarded_global: (untyped name, untyped type, untyped pre_guard, ?record: untyped) -> Scope
|
|
208
239
|
def with_constant_narrowing: (untyped key, untyped type, untyped pre_guard) -> Scope
|
|
240
|
+
# Issue #1446 — `rigor sig-gen` output.
|
|
241
|
+
def with_guarded_ivar: (untyped name, untyped type, untyped pre_guard) -> Scope
|
|
242
|
+
def without_ivar_guard: (untyped name) -> Scope
|
|
243
|
+
# sig-gen gap: #1154 — the table reader over an ivar `initialize` assigns from a parameter reaches `untyped`.
|
|
244
|
+
def guard_narrowed_ivar?: (untyped name) -> bool
|
|
245
|
+
# Issue #1446 — `rigor sig-gen` output.
|
|
246
|
+
def with_bot_guard_classes: (untyped kind, untyped name, untyped class_names) -> Scope
|
|
247
|
+
# sig-gen gap: #1154 — the table reader over an ivar `initialize` assigns from a parameter reaches `untyped`.
|
|
248
|
+
def bot_guard_classes_for: (untyped kind, untyped name) -> Array[String]?
|
|
209
249
|
def without_constant_narrowing: (untyped key) -> Scope
|
|
210
250
|
def guard_narrowed?: () -> bool
|
|
211
251
|
def forget_guard_narrowings: () -> Scope
|
|
@@ -259,6 +299,8 @@ module Rigor
|
|
|
259
299
|
def class_ivars_for: (String | Symbol? class_name) -> Hash[Symbol, Type::t]
|
|
260
300
|
def class_cvars_for: (String | Symbol? class_name) -> Hash[Symbol, Type::t]
|
|
261
301
|
def discovered_method?: (String | Symbol class_name, String | Symbol method_name, Symbol kind) -> bool
|
|
302
|
+
# authored: the slot is a Prism::DefNode or a DefHandle until ADR-119 C1d/C2 decide its type.
|
|
303
|
+
def def_node_slot: (untyped class_name, untyped method_name, ?Symbol kind) -> untyped
|
|
262
304
|
def user_def_for: (String | Symbol class_name, String | Symbol method_name) -> ::Prism::DefNode?
|
|
263
305
|
def user_def_through_ancestors: (String | Symbol class_name, String | Symbol method_name, ?name_memo: Hash[untyped, untyped]) -> ([::Prism::DefNode, String] | [nil, nil])
|
|
264
306
|
def discovered_method_through_ancestors?: (String | Symbol? class_name, String | Symbol method_name, Symbol kind, ?name_memo: Hash[untyped, untyped]) -> bool
|
|
@@ -88,7 +88,7 @@ diagnostics.
|
|
|
88
88
|
| Today's diagnostics | Snapshotted into `.rigor-baseline.yml`; suppressed as long as the count does not grow. | All surfaced; every one is fixed or consciously suppressed. |
|
|
89
89
|
| Hard-to-fix diagnostics | Left in the baseline. The project **trusts its test / spec suite** to cover runtime correctness for those sites — the static `T | nil` reading is worst-case-sound, the suite proves the worst case is not hit. | Fixed, or annotated `# rigor:disable <rule>` with an author-intent reason at the specific line. No blanket suppression. |
|
|
90
90
|
| `severity_profile` | `lenient` (or `balanced` for a small project). | `strict`. |
|
|
91
|
-
| Best for |
|
|
91
|
+
| Best for | **Every project by default** — mature or brand-new, large or small. | Users fluent in both type theory and RBS who opt in and will resolve Rigor's inference gaps themselves. |
|
|
92
92
|
| New diagnostics later | Surface immediately — anything beyond the baseline envelope is a regression. | Surface immediately — there is no envelope; every diagnostic is live. |
|
|
93
93
|
|
|
94
94
|
Both modes give the same core guarantee: **a change that introduces
|
|
@@ -97,12 +97,35 @@ diagnostics that exist *today*. Acknowledge mode parenthesises them
|
|
|
97
97
|
behind a baseline and leans on the test suite; strict mode refuses to
|
|
98
98
|
parenthesise anything.
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
**Recommend acknowledge mode for every project, including new and
|
|
101
|
+
small ones.** Rigor's inference still has gaps, so even a fresh
|
|
102
|
+
project meets diagnostics on correct code. Under strict mode each one
|
|
103
|
+
needs a `sig/` fix, an RBS workaround, or a reasoned
|
|
104
|
+
`# rigor:disable` — work that takes type theory and RBS. Without that
|
|
105
|
+
knowledge, users rewrite correct code for the tool or scatter
|
|
106
|
+
suppressions. Acknowledge mode keeps the same regression guard with an
|
|
107
|
+
exit: a new diagnostic still fails the check, and once it is confirmed
|
|
108
|
+
as an inference gap, the baseline can absorb it (report the false
|
|
109
|
+
positive upstream). `rigor baseline regenerate` rewrites the baseline
|
|
110
|
+
from every live diagnostic, so run it only when a whole-project
|
|
111
|
+
`rigor check` (no path arguments) shows nothing but confirmed false
|
|
112
|
+
positives; otherwise it silences a real
|
|
113
|
+
bug alongside them.
|
|
114
|
+
|
|
115
|
+
Present strict mode as an opt-in for users who know type theory and
|
|
116
|
+
RBS, want the zero-diagnostic gate, and accept resolving inference
|
|
117
|
+
gaps themselves — never as the recommendation, and never because the
|
|
118
|
+
project is new, small, or a library. If the user picks it, tell them
|
|
119
|
+
how to move to acknowledge mode later: optionally relax
|
|
120
|
+
`severity_profile`, re-run triage, then run Phase 7 (generate a
|
|
121
|
+
baseline and wire `baseline:`). The profile change comes first because
|
|
122
|
+
it changes which rules fire.
|
|
123
|
+
|
|
124
|
+
For a large first run (more than ~100 errors), acknowledge mode also
|
|
125
|
+
suggests `severity_profile: lenient`; see Phase 4.
|
|
126
|
+
|
|
127
|
+
Note the ordering: the error count that feeds the `severity_profile`
|
|
128
|
+
choice in Phase 4 is only *measured* in
|
|
106
129
|
Phase 6's triage run. Any profile written in Phase 4 is therefore
|
|
107
130
|
**provisional** — Phase 6 revisits it against the measured count (see
|
|
108
131
|
[`references/02-configure.md`](references/02-configure.md)
|
|
@@ -111,12 +134,15 @@ Phase 6's triage run. Any profile written in Phase 4 is therefore
|
|
|
111
134
|
## Non-interactive / agent-driven runs
|
|
112
135
|
|
|
113
136
|
This skill has several ask-the-user points (the mode choice, the RBS
|
|
114
|
-
collection install, the final gitignore-and-commit confirmation).
|
|
115
|
-
the user
|
|
116
|
-
|
|
137
|
+
collection install, the final gitignore-and-commit confirmation). A
|
|
138
|
+
*delegation* is the user asking, before the run, for the onboarding to
|
|
139
|
+
proceed without these questions ("set it up, don't ask me"). An
|
|
140
|
+
ordinary request to set Rigor up is not one: ask as usual. Under a
|
|
141
|
+
delegation those points resolve without blocking:
|
|
117
142
|
|
|
118
143
|
- The **mode** the user pre-declared is settled; record it and skip the
|
|
119
|
-
Phase 2 presentation.
|
|
144
|
+
Phase 2 presentation. If the delegation names no mode, choose
|
|
145
|
+
acknowledge mode and say so in the report — never strict.
|
|
120
146
|
- Low-risk, reversible, in-repo confirmations (`rbs collection
|
|
121
147
|
install`, the `.gitignore` addition) are covered by the delegation —
|
|
122
148
|
act, and note each self-answer in your report.
|
|
@@ -138,14 +138,19 @@ entirely — including a `sig/` that `rigor sig-gen --write` created.
|
|
|
138
138
|
List only directories that contain `.rbs` files or subdirectories of
|
|
139
139
|
them. Rigor walks each path recursively.
|
|
140
140
|
|
|
141
|
-
A
|
|
141
|
+
A plain-Ruby gem is shorter. The `balanced` default needs no
|
|
142
|
+
`severity_profile:` key:
|
|
142
143
|
|
|
143
144
|
```yaml
|
|
144
145
|
paths:
|
|
145
146
|
- lib
|
|
146
147
|
test_paths:
|
|
147
148
|
- test
|
|
148
|
-
|
|
149
|
+
|
|
150
|
+
# Phase 7 (acknowledge mode) appends this line after generating the
|
|
151
|
+
# baseline. Strict mode (opt-in) sets `severity_profile: strict` and
|
|
152
|
+
# leaves it out.
|
|
153
|
+
# baseline: .rigor-baseline.yml
|
|
149
154
|
```
|
|
150
155
|
|
|
151
156
|
### Test roots — write `test_paths:` explicitly
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rigortype
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rigor contributors
|
|
@@ -460,6 +460,8 @@ files:
|
|
|
460
460
|
- lib/rigor/analysis/erb_template_detector.rb
|
|
461
461
|
- lib/rigor/analysis/fact_store.rb
|
|
462
462
|
- lib/rigor/analysis/incremental.rb
|
|
463
|
+
- lib/rigor/analysis/incremental_run_slot.rb
|
|
464
|
+
- lib/rigor/analysis/incremental_run_slot/write_guard.rb
|
|
463
465
|
- lib/rigor/analysis/incremental_session.rb
|
|
464
466
|
- lib/rigor/analysis/path_expansion.rb
|
|
465
467
|
- lib/rigor/analysis/plugin_fact_fingerprint.rb
|
|
@@ -487,6 +489,8 @@ files:
|
|
|
487
489
|
- lib/rigor/analysis/runner/run_snapshots.rb
|
|
488
490
|
- lib/rigor/analysis/self_call_resolution_recorder.rb
|
|
489
491
|
- lib/rigor/analysis/severity_stamp.rb
|
|
492
|
+
- lib/rigor/analysis/shadow_harness.rb
|
|
493
|
+
- lib/rigor/analysis/source_rbs_gate.rb
|
|
490
494
|
- lib/rigor/analysis/template_unit_collector.rb
|
|
491
495
|
- lib/rigor/analysis/template_unit_paths.rb
|
|
492
496
|
- lib/rigor/analysis/template_unit_positions.rb
|
|
@@ -514,6 +518,7 @@ files:
|
|
|
514
518
|
- lib/rigor/cache/rbs_environment_marshal_patch.rb
|
|
515
519
|
- lib/rigor/cache/rbs_known_class_names.rb
|
|
516
520
|
- lib/rigor/cache/store.rb
|
|
521
|
+
- lib/rigor/cache/value_digest.rb
|
|
517
522
|
- lib/rigor/ci_detector.rb
|
|
518
523
|
- lib/rigor/cli.rb
|
|
519
524
|
- lib/rigor/cli/annotate_command.rb
|
|
@@ -574,6 +579,7 @@ files:
|
|
|
574
579
|
- lib/rigor/cli/unused_command.rb
|
|
575
580
|
- lib/rigor/cli/upgrade_command.rb
|
|
576
581
|
- lib/rigor/config_audit.rb
|
|
582
|
+
- lib/rigor/config_path.rb
|
|
577
583
|
- lib/rigor/configuration.rb
|
|
578
584
|
- lib/rigor/configuration/dependencies.rb
|
|
579
585
|
- lib/rigor/configuration/severity_profile.rb
|
|
@@ -638,6 +644,7 @@ files:
|
|
|
638
644
|
- lib/rigor/environment/rbs_loader.rb
|
|
639
645
|
- lib/rigor/environment/reflection.rb
|
|
640
646
|
- lib/rigor/environment/reporters.rb
|
|
647
|
+
- lib/rigor/environment/source_rbs_synthesis.rb
|
|
641
648
|
- lib/rigor/flow_contribution.rb
|
|
642
649
|
- lib/rigor/flow_contribution/conflict.rb
|
|
643
650
|
- lib/rigor/flow_contribution/element.rb
|
|
@@ -677,10 +684,16 @@ files:
|
|
|
677
684
|
- lib/rigor/inference/closure_escape_analyzer.rb
|
|
678
685
|
- lib/rigor/inference/content_join.rb
|
|
679
686
|
- lib/rigor/inference/coverage_scanner.rb
|
|
687
|
+
- lib/rigor/inference/declaration_walk.rb
|
|
688
|
+
- lib/rigor/inference/declaration_walk/context.rb
|
|
689
|
+
- lib/rigor/inference/declaration_walk/errors.rb
|
|
690
|
+
- lib/rigor/inference/declaration_walk/shadow.rb
|
|
691
|
+
- lib/rigor/inference/declaration_walk/traversal.rb
|
|
680
692
|
- lib/rigor/inference/def_handle.rb
|
|
681
693
|
- lib/rigor/inference/def_node_resolver.rb
|
|
682
694
|
- lib/rigor/inference/def_return_typer.rb
|
|
683
695
|
- lib/rigor/inference/define_method_block_self.rb
|
|
696
|
+
- lib/rigor/inference/definer_resolution.rb
|
|
684
697
|
- lib/rigor/inference/dynamic_origin.rb
|
|
685
698
|
- lib/rigor/inference/element_read_widening.rb
|
|
686
699
|
- lib/rigor/inference/error_info.rb
|
|
@@ -751,6 +764,7 @@ files:
|
|
|
751
764
|
- lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb
|
|
752
765
|
- lib/rigor/inference/method_dispatcher/uri_folding.rb
|
|
753
766
|
- lib/rigor/inference/method_parameter_binder.rb
|
|
767
|
+
- lib/rigor/inference/module_function_state.rb
|
|
754
768
|
- lib/rigor/inference/multi_target_binder.rb
|
|
755
769
|
- lib/rigor/inference/mutation_rejoin.rb
|
|
756
770
|
- lib/rigor/inference/mutation_widening.rb
|
|
@@ -775,6 +789,14 @@ files:
|
|
|
775
789
|
- lib/rigor/inference/return_barrier.rb
|
|
776
790
|
- lib/rigor/inference/rewrite_mutation.rb
|
|
777
791
|
- lib/rigor/inference/scope_indexer.rb
|
|
792
|
+
- lib/rigor/inference/scope_indexer/certainty.rb
|
|
793
|
+
- lib/rigor/inference/scope_indexer/class_cvars_collector.rb
|
|
794
|
+
- lib/rigor/inference/scope_indexer/def_nestings_collector.rb
|
|
795
|
+
- lib/rigor/inference/scope_indexer/layered_def_nestings.rb
|
|
796
|
+
- lib/rigor/inference/scope_indexer/member_layouts_collector.rb
|
|
797
|
+
- lib/rigor/inference/scope_indexer/mixin_accumulator.rb
|
|
798
|
+
- lib/rigor/inference/scope_indexer/superclasses_collector.rb
|
|
799
|
+
- lib/rigor/inference/singleton_hook_decline.rb
|
|
778
800
|
- lib/rigor/inference/singleton_object_constant.rb
|
|
779
801
|
- lib/rigor/inference/statement_evaluator.rb
|
|
780
802
|
- lib/rigor/inference/stored_block_call.rb
|
|
@@ -868,6 +890,8 @@ files:
|
|
|
868
890
|
- lib/rigor/runtime/jit.rb
|
|
869
891
|
- lib/rigor/scope.rb
|
|
870
892
|
- lib/rigor/scope/discovery_index.rb
|
|
893
|
+
- lib/rigor/scope/resolution_chain.rb
|
|
894
|
+
- lib/rigor/scope/resolution_chain/relevance.rb
|
|
871
895
|
- lib/rigor/sig_gen.rb
|
|
872
896
|
- lib/rigor/sig_gen/alias_index.rb
|
|
873
897
|
- lib/rigor/sig_gen/classification.rb
|