Module: Rigor::Inference::Narrowing

Defined in:
lib/rigor/inference/narrowing.rb,
sig/rigor/inference.rbs

Overview

Control-flow predicate narrowing and type-lattice narrowing primitives.

Rigor::Inference::Narrowing answers two related questions:

  1. Type-level narrowing: given a Rigor::Type value, what is its truthy fragment, its falsey fragment, its nil fragment, and its non-nil fragment? These primitives understand the value-lattice algebra (Constant, Nominal, Singleton, Tuple, HashShape, Union) and stay conservative on Top and Dynamic[T].
  2. Predicate-level narrowing: given a Prism predicate node and an entry scope, what are the truthy-edge scope and the falsey-edge scope? The catalogue covers truthiness, nil?, !, &&/||, class-membership (is_a?, kind_of?, instance_of?), trusted equality/inequality against static literals, case/when, regex match globals, string predicates (start_with? etc.), key-presence, array emptiness, numeric comparison, and respond_to?.

Consumed by Rigor::Inference::StatementEvaluator to refine then/else scopes of IfNode/UnlessNode and case/when branches.

The module is pure: every public function returns fresh values and MUST NOT mutate its inputs. Unrecognised predicate shapes degrade silently to "no narrowing" by returning nil from the internal analyser; the public predicate_scopes always returns an [truthy_scope, falsey_scope] pair (the entry scope twice when no rule matches).

See docs/internal-spec/inference-engine.md (Narrowing) and docs/type-specification/control-flow-analysis.md for the binding contract. rubocop:disable Metrics/ModuleLength

Constant Summary collapse

VALUE_EQUALITY_CLASSES =

Classes whose === is plain value equality, so a literal when pattern against a pinned Constant subject is exact in both directions. Anything else keeps custom-=== semantics and stays :maybe in value_pattern_certainty.

Returns:

  • (Array[Class])
[Integer, Float, Rational, Complex, String, Symbol,
TrueClass, FalseClass, NilClass].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.analyse(node, scope) ⇒ Object

Internal analyser. Returns [truthy_scope, falsey_scope] when the predicate shape is recognised, or nil to signal "no narrowing" so the public surface can fall back to the entry scope.



408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
# File 'lib/rigor/inference/narrowing.rb', line 408

def analyse(node, scope)
  case node
  when Prism::ParenthesesNode
    analyse_parentheses(node, scope)
  when Prism::StatementsNode
    analyse_statements(node, scope)
  when Prism::LocalVariableReadNode
    analyse_local_read(node, scope)
  when Prism::LocalVariableWriteNode
    analyse_local_write(node, scope)
  when Prism::InstanceVariableReadNode, Prism::InstanceVariableWriteNode
    analyse_ivar(node, scope)
  when Prism::ClassVariableWriteNode
    analyse_cvar_write(node, scope)
  when Prism::GlobalVariableWriteNode
    analyse_global_write(node, scope)
  when Prism::CallNode
    analyse_call(node, scope)
  when Prism::AndNode
    analyse_and(node, scope)
  when Prism::OrNode
    analyse_or(node, scope)
  when Prism::MatchWriteNode
    analyse_match_write(node, scope)
  end
end

.apply_when_regex_globals(conditions, scope) ⇒ Object

When the clause has exactly one RegularExpressionNode literal condition, narrow the match-data globals on the body edge (same rule as analyse_regex_match_predicate's truthy edge). With multiple regex conditions (when /a/, /b/) the body is reachable through any of them, so only $~/$& are safely non-nil; numbered groups whose presence differs per alternative stay String | nil. With no regex condition the entry scope passes through unchanged.



391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/rigor/inference/narrowing.rb', line 391

def apply_when_regex_globals(conditions, scope)
  regexes = conditions.grep(Prism::RegularExpressionNode)
  return scope if regexes.empty?

  unconditional =
    if regexes.size == 1
      unconditional_capture_groups(regexes.first.unescaped)
    else
      Set.new
    end
  truthy, = regex_match_predicate_scopes(scope, unconditional)
  truthy
end

.case_when_scopes(subject, conditions, scope) ⇒ Array(Rigor::Scope, Rigor::Scope)

Slice 7 phase 5 — case/when narrowing.

Given the subject of a case (the expression after the case keyword) and an array of when-clause condition nodes (when_clause.conditions), returns a pair of scopes:

  • body_scope: the scope under which the body of the when clause MUST be evaluated. The subject local is narrowed by the union of every condition's truthy edge so the body sees the most specific type compatible with "any of the conditions matched".
  • falsey_scope: the scope under which the next branch (the next when or the else) MUST be evaluated. The subject is narrowed by the conjunction of every condition's falsey edge.

The narrowing is best-effort: if the subject is not a Prism::LocalVariableReadNode or none of the condition shapes are recognised, both returned scopes equal the input scope. The catalogue mirrors case_equality_target_class: static class/module constants narrow as is_a?; integer/float-endpoint ranges narrow to Numeric; string-endpoint ranges and regexp literals narrow to String.

Parameters:

  • subject (Prism::Node, nil)

    the case subject.

  • conditions (Array<Prism::Node>)

    the when clause's conditions array.

  • scope (Rigor::Scope)

Returns:



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/rigor/inference/narrowing.rb', line 367

def case_when_scopes(subject, conditions, scope)
  # C1 — `case x when /re/` runs `/re/ === x`, which sets the regex match-data globals
  # exactly as a successful `=~` does. Narrow `$~`/`$&`/`$1..$N` on the clause body (the
  # match edge); the falsey scope keeps the entry globals because a later clause may match
  # a different regex. Applied even when the subject is not a narrowable local read.
  body_scope = apply_when_regex_globals(conditions, scope)

  return [body_scope, scope] unless subject.is_a?(Prism::LocalVariableReadNode)

  local_name = subject.name
  current = scope.local(local_name)
  return [body_scope, scope] if current.nil?

  truthy, = accumulate_case_when_scopes(body_scope, local_name, current, conditions)
  _, falsey = accumulate_case_when_scopes(scope, local_name, current, conditions)
  [truthy, falsey]
end

.class_pattern_certainty(subject_type, class_name, environment:) ⇒ Object

Three-valued certainty of C === subject for a class / module when pattern, derived from narrow_class / narrow_not_class: :no when no inhabitant of the subject matches, :yes when every inhabitant matches, :maybe otherwise. The value-side counterpart of the scope narrowing case_when_scopes performs for the same condition shape, kept here so the branch a case expression's type drops and the clause whose body scope goes dead derive from one judgment.



135
136
137
138
139
140
141
142
143
# File 'lib/rigor/inference/narrowing.rb', line 135

def class_pattern_certainty(subject_type, class_name, environment:)
  truthy_bot = narrow_class(subject_type, class_name, environment: environment).is_a?(Type::Bot)
  falsey_bot = narrow_not_class(subject_type, class_name, environment: environment).is_a?(Type::Bot)

  return :no if truthy_bot && !falsey_bot
  return :yes if !truthy_bot && falsey_bot

  :maybe
end

.narrow_class(type, class_name, exact: false, environment: Environment.default) ⇒ Object

Class-membership fragment of type: the subset whose inhabitants are instances of class_name (or its subclasses when exact: false). class_name is the qualified name of the class as it appears in source ("Integer", "Foo::Bar"). Slice 6 phase 2 sub-phase 1 narrows the if x.is_a?(C) / if x.kind_of?(C) / if x.instance_of?(C) truthy edge.

Nominal narrowing is hierarchy-aware through the analyzer environment: when the bound type is a supertype of class_name the result narrows DOWN to Nominal[class_name] (e.g., Numeric & Integer = Integer); when the bound type is already a subtype it is preserved; disjoint hierarchies collapse to Bot. Classes the environment cannot resolve fall back to the conservative answer (the type unchanged) so the analyzer never asserts narrowing it cannot prove.



257
258
259
260
# File 'lib/rigor/inference/narrowing.rb', line 257

def narrow_class(type, class_name, exact: false, environment: Environment.default)
  context = ClassNarrowingContext.new(exact: exact, polarity: :positive, environment: environment)
  narrow_class_dispatch(type, class_name, context)
end

.narrow_equal(type, literal) ⇒ Object

Equality fragment of type against a trusted literal.

String/Symbol/Integer equality narrows only when the current domain is already a finite union of trusted literals. Nil and booleans are singleton values, so they can be extracted from a mixed union such as Integer | nil without manufacturing a new positive domain from the comparison alone.



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/rigor/inference/narrowing.rb', line 168

def narrow_equal(type, literal)
  return type unless trusted_equality_literal?(literal)

  if singleton_literal?(literal)
    narrow_singleton_equal(type, literal)
  elsif finite_trusted_literal_domain?(type)
    narrow_finite_equal(type, literal)
  else
    type
  end
end

.narrow_falsey(type) ⇒ Object

Falsey fragment of type: the subset whose inhabitants are nil or false. Carriers that cannot inhabit a falsey value collapse to Bot.



70
71
72
73
74
75
76
77
# File 'lib/rigor/inference/narrowing.rb', line 70

def narrow_falsey(type)
  case type
  when Type::Constant then falsey_value?(type.value) ? type : Type::Combinator.bot
  when Type::Nominal then falsey_nominal?(type) ? type : Type::Combinator.bot
  when Type::Union then Type::Combinator.union(*type.members.map { |m| narrow_falsey(m) })
  else narrow_falsey_other(type)
  end
end

.narrow_for_fact(current, fact, environment) ⇒ Object

ADR-7 § "Slice 4-A" — public Fact-shaped narrowing entry. Distinguishes a Nominal[<class>]-typed Fact (uses narrow_class / narrow_not_class for hierarchy-aware narrowing) from a refinement-shaped Fact (refined types, IntegerRange, Difference, …). The implementation lives next to its sibling helpers narrow_class and narrow_not_refinement; consumers outside Narrowing (today: StatementEvaluator's post-return assertion path) reach for it via Rigor::Inference::Narrowing.narrow_for_fact.



318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/rigor/inference/narrowing.rb', line 318

def narrow_for_fact(current, fact, environment)
  if fact.type.is_a?(Type::Nominal) && fact.type.type_args.empty?
    class_name = fact.type.class_name
    return narrow_not_class(current, class_name, exact: false, environment: environment) if fact.negative?

    return narrow_class(current, class_name, exact: false, environment: environment)
  end

  return narrow_not_refinement(current, fact.type) if fact.negative?

  fact.type
end

.narrow_integer_comparison(type, comparator, bound) ⇒ Object

Integer-comparison fragment of type against an Integer literal bound. Narrows the receiver of x < n, x <= n, x > n, x >= n (and the reversed forms) to the subset of the existing domain that satisfies the comparison. Hooks in:

  • Constant<Integer> is preserved when it satisfies the comparison, otherwise collapsed to Bot.
  • IntegerRange[a..b] becomes the intersection with the half-line implied by the comparison; an empty intersection collapses to Bot, a single-point intersection collapses to Constant<Integer>.
  • Nominal[Integer] becomes the half-line itself (e.g. x > 0 on Nominal[Integer] is positive_int).
  • Union narrows each member independently.
  • Other carriers (Float, String, Top, Dynamic) flow through unchanged: the analyzer does not have a Float-range carrier today, and no other carrier participates in numeric ordering.


209
210
211
212
213
# File 'lib/rigor/inference/narrowing.rb', line 209

def narrow_integer_comparison(type, comparator, bound)
  return type unless bound.is_a?(Integer) && %i[< <= > >=].include?(comparator)

  narrow_integer_comparison_dispatch(type, comparator, bound)
end

.narrow_integer_equal(type, value) ⇒ Object

Equality fragment of type against an Integer value. Constant<Integer> is preserved when it equals value, otherwise collapses to Bot. IntegerRange covers? value narrows to Constant[value]; an out-of-range comparison collapses to Bot. Nominal[Integer] narrows to Constant[value]. Union narrows each member.



219
220
221
222
223
# File 'lib/rigor/inference/narrowing.rb', line 219

def narrow_integer_equal(type, value)
  return type unless value.is_a?(Integer)

  narrow_integer_equal_dispatch(type, value)
end

.narrow_integer_not_equal(type, value) ⇒ Object

Complement of narrow_integer_equal. Removes a single integer value from the domain when one endpoint of an IntegerRange is exactly that value (so the result stays a contiguous range). Domains where the value sits strictly between the endpoints stay unchanged: punching a hole would require a two-piece carrier the lattice does not yet model.



230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/rigor/inference/narrowing.rb', line 230

def narrow_integer_not_equal(type, value)
  return type unless value.is_a?(Integer)

  case type
  when Type::Constant
    type.value == value ? Type::Combinator.bot : type
  when Type::IntegerRange
    narrow_integer_range_not_equal(type, value)
  when Type::Union
    Type::Combinator.union(*type.members.map { |m| narrow_integer_not_equal(m, value) })
  else
    type
  end
end

.narrow_nil(type) ⇒ Object

Nil fragment of type: the subset whose inhabitants are nil. Used by nil? predicate narrowing. Top/Dynamic narrow to the canonical Constant[nil] so downstream dispatch resolves through NilClass; carriers that never inhabit nil (Singleton, Tuple, HashShape) collapse to Bot. Bot is its own nil fragment.



83
84
85
86
87
88
89
90
# File 'lib/rigor/inference/narrowing.rb', line 83

def narrow_nil(type)
  case type
  when Type::Constant then type.value.nil? ? type : Type::Combinator.bot
  when Type::Nominal then type.class_name == "NilClass" ? type : Type::Combinator.bot
  when Type::Union then Type::Combinator.union(*type.members.map { |m| narrow_nil(m) })
  else narrow_nil_other(type)
  end
end

.narrow_non_nil(type) ⇒ Object

Non-nil fragment of type: the subset whose inhabitants are not nil. Mirror of narrow_nil for the falsey edge of x.nil?.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/rigor/inference/narrowing.rb', line 94

def narrow_non_nil(type)
  case type
  when Type::Constant
    type.value.nil? ? Type::Combinator.bot : type
  when Type::Nominal
    type.class_name == "NilClass" ? Type::Combinator.bot : type
  when Type::Union
    Type::Combinator.union(*type.members.map { |m| narrow_non_nil(m) })
  else
    # Top, Dynamic, Singleton, Tuple, HashShape, Bot: there is no nil contribution to
    # remove, so the type is its own non-nil fragment.
    type
  end
end

.narrow_not_class(type, class_name, exact: false, environment: Environment.default) ⇒ Object

Mirror of narrow_class for the falsey edge of is_a?/kind_of?/instance_of?. Inhabitants that DO satisfy the predicate are removed; inhabitants that do not are preserved. Conservative on Top/Dynamic/Bot (preserved unchanged) because the analyzer cannot prove the negative without a richer carrier.



266
267
268
269
# File 'lib/rigor/inference/narrowing.rb', line 266

def narrow_not_class(type, class_name, exact: false, environment: Environment.default)
  context = ClassNarrowingContext.new(exact: exact, polarity: :negative, environment: environment)
  narrow_class_dispatch(type, class_name, context)
end

.narrow_not_equal(type, literal) ⇒ Object

Complement of narrow_equal. Negative facts are domain-relative: they remove a literal from an already-known domain but do not create an unbounded difference type when the domain is broad or dynamic.



183
184
185
186
187
188
189
190
191
192
193
# File 'lib/rigor/inference/narrowing.rb', line 183

def narrow_not_equal(type, literal)
  return type unless trusted_equality_literal?(literal)

  if singleton_literal?(literal)
    narrow_singleton_not_equal(type, literal)
  elsif finite_trusted_literal_domain?(type)
    narrow_finite_not_equal(type, literal)
  else
    type
  end
end

.narrow_not_refinement(current_type, refinement_type) ⇒ Object

Negation pair for assert_value is ~refinement / predicate-if-* … is ~refinement directives. Computes the complement of refinement within the current local's domain current_type.

Carrier-by-carrier rules:

  • Difference[base, Constant[v]]. Complement of base \ {v} within current_type. Walk the current type's union members, keep each part disjoint from base, and add the removed-value Constant once when any current member covers it. assert s is ~non-empty-string over s: String | nil narrows to Constant[""] | NilClass.
  • IntegerRange[a, b] (v0.0.5+ slice). Complement is the two open halves int<min, a-1> and int<b+1, max>, each intersected with the integer-domain parts of current_type. Non-integer parts (nil, String, …) of a Union receiver survive unchanged. assert n is ~int<5, 10> over n: Integer | nil narrows to int<min, 4> | int<11, max> | NilClass.
  • Type::Intersection[M1, M2, …] (v0.0.5+ slice). De Morgan: D \ (M1 ∩ M2) = (D \ M1) ∪ (D \ M2). Each member's complement is computed independently within current_type and the results are unioned. Members the algebra cannot complement (Refined, non-Constant Difference, …) contribute current_type itself, so the union widens the answer to current_type — sound but imprecise.
  • Refined[base, predicate]. Predicate complements are not reducible to a finite carrier without a richer shape (e.g. ~lowercase-string is "uppercase OR mixed-case"); current_type is returned unchanged.


294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/rigor/inference/narrowing.rb', line 294

def narrow_not_refinement(current_type, refinement_type)
  case refinement_type
  when Type::Difference
    return current_type unless refinement_type.removed.is_a?(Type::Constant)

    complement_difference(current_type, refinement_type)
  when Type::IntegerRange
    complement_integer_range(current_type, refinement_type)
  when Type::Intersection
    complement_intersection(current_type, refinement_type)
  when Type::Refined
    complement_refined(current_type, refinement_type)
  else
    current_type
  end
end

.narrow_truthy(type) ⇒ Object

Truthy fragment of type: the subset whose inhabitants are truthy in Ruby's sense (anything other than nil and false).

Top, Dynamic[T], Bot, Singleton[C], Tuple[*], and HashShape{*} flow through unchanged: Top/Dynamic stay conservative because the analyzer cannot express the difference type without a richer carrier and Dynamic must preserve its provenance under the value-lattice algebra; the remaining carriers are already truthy by inhabitance.



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rigor/inference/narrowing.rb', line 55

def narrow_truthy(type)
  case type
  when Type::Constant
    falsey_value?(type.value) ? Type::Combinator.bot : type
  when Type::Nominal
    falsey_nominal?(type) ? Type::Combinator.bot : type
  when Type::Union
    Type::Combinator.union(*type.members.map { |m| narrow_truthy(m) })
  else
    type
  end
end

.predicate_certainty(type) ⇒ Object

Three-valued truthiness certainty of a predicate's type, derived from the truthy / falsey fragments above: :truthy when no inhabitant is falsey (the falsey fragment is Bot), :falsey when no inhabitant is truthy, nil when both fragments are inhabited — or when the type itself is nil / Bot (dead code is not a certainty claim). This is the single owner of the judgment both branch-elision consumers read (ExpressionTyper#elide_or_union on the value side, StatementEvaluator#live_branch_for_if on the scope side), so the type a dead branch is elided from and the scope that stops flowing through it can never disagree.



117
118
119
120
121
122
123
124
125
126
127
# File 'lib/rigor/inference/narrowing.rb', line 117

def predicate_certainty(type)
  return nil if type.nil? || type.is_a?(Type::Bot)

  truthy_bot = narrow_truthy(type).is_a?(Type::Bot)
  falsey_bot = narrow_falsey(type).is_a?(Type::Bot)

  return :falsey if truthy_bot && !falsey_bot
  return :truthy if !truthy_bot && falsey_bot

  nil
end

.predicate_scopes(node, scope) ⇒ Array(Rigor::Scope, Rigor::Scope)

Public predicate analyser. Returns [truthy_scope, falsey_scope], always; when no narrowing rule matches the predicate node both entries are the receiver scope unchanged.

Parameters:

Returns:



337
338
339
340
341
342
# File 'lib/rigor/inference/narrowing.rb', line 337

def predicate_scopes(node, scope)
  return [scope, scope] if node.nil?

  result = analyse(node, scope)
  result || [scope, scope]
end

.value_pattern_certainty(subject_type, pattern_value) ⇒ Object

Three-valued certainty of <literal> === subject for a value-equality literal pattern: exact (:yes / :no) only when the subject is itself a pinned Constant of a value-equality class; :maybe otherwise (the runtime value isn't pinned, or === may be user-defined).



155
156
157
158
159
160
# File 'lib/rigor/inference/narrowing.rb', line 155

def value_pattern_certainty(subject_type, pattern_value)
  return :maybe unless subject_type.is_a?(Type::Constant)
  return :maybe unless VALUE_EQUALITY_CLASSES.any? { |klass| subject_type.value.is_a?(klass) }

  pattern_value == subject_type.value ? :yes : :no
end

Instance Method Details

#self?.analyseObject

Parameters:

  • node (Object)
  • scope (Scope)

Returns:

  • (Object)


117
# File 'sig/rigor/inference.rbs', line 117

def self?.analyse: (untyped node, Scope scope) -> untyped

#self?.case_when_scopes[Scope, Scope]

Parameters:

  • subject (Object)
  • conditions (Array[untyped])
  • scope (Scope)

Returns:



116
# File 'sig/rigor/inference.rbs', line 116

def self?.case_when_scopes: (untyped subject, Array[untyped] conditions, Scope scope) -> [Scope, Scope]

#self?.class_orderingSymbol

Parameters:

  • lhs (String)
  • rhs (String)
  • context (Object)

Returns:

  • (Symbol)


119
# File 'sig/rigor/inference.rbs', line 119

def self?.class_ordering: (String lhs, String rhs, untyped context) -> Symbol

#self?.class_pattern_certainty:yes, ...

Parameters:

  • subject_type (Type::t)
  • class_name (String)
  • environment: (Environment)

Returns:

  • (:yes, :no, :maybe)


113
# File 'sig/rigor/inference.rbs', line 113

def self?.class_pattern_certainty: (Type::t subject_type, String class_name, environment: Environment) -> (:yes | :no | :maybe)

#self?.falsey_nominal?Boolean

Parameters:

Returns:

  • (Boolean)


122
# File 'sig/rigor/inference.rbs', line 122

def self?.falsey_nominal?: (Type::Nominal nominal) -> bool

#self?.falsey_value?Boolean

Parameters:

  • value (Object)

Returns:

  • (Boolean)


121
# File 'sig/rigor/inference.rbs', line 121

def self?.falsey_value?: (untyped value) -> bool

#self?.narrow_classType::t

Parameters:

  • type (Type::t)
  • class_name (String)
  • exact: (Boolean)
  • environment: (Environment)

Returns:

  • (Type::t)


108
# File 'sig/rigor/inference.rbs', line 108

def self?.narrow_class: (Type::t type, String class_name, ?exact: bool, ?environment: Environment) -> Type::t

#self?.narrow_equalType::t

Parameters:

  • type (Type::t)
  • literal (Object)

Returns:

  • (Type::t)


106
# File 'sig/rigor/inference.rbs', line 106

def self?.narrow_equal: (Type::t type, untyped literal) -> Type::t

#self?.narrow_falseyType::t

Parameters:

  • type (Type::t)

Returns:

  • (Type::t)


103
# File 'sig/rigor/inference.rbs', line 103

def self?.narrow_falsey: (Type::t type) -> Type::t

#self?.narrow_for_factType::t

Parameters:

  • current (Type::t)
  • fact (Object)
  • environment (Object)

Returns:

  • (Type::t)


111
# File 'sig/rigor/inference.rbs', line 111

def self?.narrow_for_fact: (Type::t current, untyped fact, untyped environment) -> Type::t

#self?.narrow_nilType::t

Parameters:

  • type (Type::t)

Returns:

  • (Type::t)


104
# File 'sig/rigor/inference.rbs', line 104

def self?.narrow_nil: (Type::t type) -> Type::t

#self?.narrow_non_nilType::t

Parameters:

  • type (Type::t)

Returns:

  • (Type::t)


105
# File 'sig/rigor/inference.rbs', line 105

def self?.narrow_non_nil: (Type::t type) -> Type::t

#self?.narrow_not_classType::t

Parameters:

  • type (Type::t)
  • class_name (String)
  • exact: (Boolean)
  • environment: (Environment)

Returns:

  • (Type::t)


109
# File 'sig/rigor/inference.rbs', line 109

def self?.narrow_not_class: (Type::t type, String class_name, ?exact: bool, ?environment: Environment) -> Type::t

#self?.narrow_not_equalType::t

Parameters:

  • type (Type::t)
  • literal (Object)

Returns:

  • (Type::t)


107
# File 'sig/rigor/inference.rbs', line 107

def self?.narrow_not_equal: (Type::t type, untyped literal) -> Type::t

#self?.narrow_not_refinementType::t

Parameters:

  • current_type (Type::t)
  • refinement_type (Type::t)

Returns:

  • (Type::t)


110
# File 'sig/rigor/inference.rbs', line 110

def self?.narrow_not_refinement: (Type::t current_type, Type::t refinement_type) -> Type::t

#self?.narrow_truthyType::t

Parameters:

  • type (Type::t)

Returns:

  • (Type::t)


102
# File 'sig/rigor/inference.rbs', line 102

def self?.narrow_truthy: (Type::t type) -> Type::t

#self?.predicate_certainty:truthy, ...

Parameters:

  • type (Type::t, nil)

Returns:

  • (:truthy, :falsey, nil)


112
# File 'sig/rigor/inference.rbs', line 112

def self?.predicate_certainty: (Type::t? type) -> (:truthy | :falsey | nil)

#self?.predicate_scopes[Scope, Scope]

Parameters:

  • node (Object)
  • scope (Scope)

Returns:



115
# File 'sig/rigor/inference.rbs', line 115

def self?.predicate_scopes: (untyped node, Scope scope) -> [Scope, Scope]

#self?.subclass_of?Boolean

Parameters:

  • rigor_class_name (String)
  • target_class_name (String)
  • context (Object)

Returns:

  • (Boolean)


118
# File 'sig/rigor/inference.rbs', line 118

def self?.subclass_of?: (String rigor_class_name, String target_class_name, untyped context) -> bool

#self?.trusted_equality_literal?Boolean

Parameters:

  • literal (Object)

Returns:

  • (Boolean)


120
# File 'sig/rigor/inference.rbs', line 120

def self?.trusted_equality_literal?: (untyped literal) -> bool

#self?.value_pattern_certainty:yes, ...

Parameters:

  • subject_type (Type::t)
  • pattern_value (Object)

Returns:

  • (:yes, :no, :maybe)


114
# File 'sig/rigor/inference.rbs', line 114

def self?.value_pattern_certainty: (Type::t subject_type, untyped pattern_value) -> (:yes | :no | :maybe)