Class: Rigor::Inference::PrecisionScanner
- Inherits:
-
Object
- Object
- Rigor::Inference::PrecisionScanner
- Defined in:
- lib/rigor/inference/precision_scanner.rb
Overview
Measures the *type quality* of inferred expressions — not whether the engine recognises an AST node class (that is ‘CoverageScanner`’s job), but whether the type it produces carries useful static information.
Each visited node is classified into one of eight precision tiers:
:constant — Constant[T]: literal value known exactly
:nominal — Nominal/Singleton: class identity known
:shaped — Tuple/HashShape/IntegerRange/App: structure known
:refined — Refined: narrowed by a predicate/assertion
:bot — Bot: unreachable branch (definitively precise)
:dynamic_specific — Dynamic[X] where X is not Top: origin partial
:dynamic_top — Dynamic[Top]: completely opaque (the "untyped" hole)
:top — Top: universal supertype (no information)
The summary exposes ‘precision_ratio` (constant+nominal+shaped+refined+bot over total) and `opaque_ratio` (dynamic_top+top over total).
For Union types the worst member tier is used, since the union is only as precise as its least-precise constituent. Intersection uses the best member (the most specific side wins). Difference follows its base type.
Defined Under Namespace
Classes: FileResult
Constant Summary collapse
- TIERS =
%i[ constant nominal shaped refined bot dynamic_specific dynamic_top top ].freeze
Instance Method Summary collapse
-
#initialize(scope: nil) ⇒ PrecisionScanner
constructor
A new instance of PrecisionScanner.
- #scan(root) ⇒ FileResult
Constructor Details
#initialize(scope: nil) ⇒ PrecisionScanner
Returns a new instance of PrecisionScanner.
78 79 80 |
# File 'lib/rigor/inference/precision_scanner.rb', line 78 def initialize(scope: nil) @scope = scope || Scope.empty end |
Instance Method Details
#scan(root) ⇒ FileResult
84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/rigor/inference/precision_scanner.rb', line 84 def scan(root) scope_index = ScopeIndexer.index(root, default_scope: @scope) tier_counts = TIERS.to_h { |t| [t, 0] } total = 0 Source::NodeWalker.each(root) do |node| type = scope_index[node].type_of(node) tier = classify(type) tier_counts[tier] += 1 total += 1 end FileResult.new(total: total, tier_counts: tier_counts) end |