Module: Rigor::Builtins::PredefinedConstantRefinements

Defined in:
lib/rigor/builtins/predefined_constant_refinements.rb

Overview

Refined types for predefined Ruby / stdlib constants whose upstream RBS signatures are broader than the constants’ documented runtime invariants.

Resolution is two-tiered:

**Tier 1 — exact-value whitelist** (‘FOLDED_CONSTANTS`): Constants whose value is bit-for-bit identical across every Ruby version and platform are folded to `Constant`: the `Math::PI` / `Math::E` math constants (C’s ‘M_PI` / `M_E`) and the four IEEE 754 binary64 magnitude constants `Float::INFINITY` / `::MAX` / `::MIN` / `::EPSILON` (each a single format-mandated bit pattern). Add new entries only when the value is truly cross-implementation invariant AND compares reflexively under `==` — the latter is why `Float::NAN` is deliberately EXCLUDED: `NaN == NaN` is `false`, so a `Constant` would violate the `Type::Constant` `==` / `eql?` / `hash` contract (it would hash equal to itself yet compare unequal), corrupting type-equality and union dedup. The binary64 integer shape parameters (`Float::DIG` / `MANT_DIG` / `MAX_EXP` / …) are intentionally NOT folded: upstream RBS hedges them as “Usually defaults to …”, and as plain `Integer`s they fall through Tier 2 to the RBS type harmlessly. `Complex::I` is deferred (no complex-fold consumer).

**Tier 2 — runtime String inspection**: For any other constant, the module resolves it via ‘const_get` against the analyzer’s own Ruby runtime. Core / stdlib constants (e.g. ‘RUBY_VERSION`, `RUBY_PLATFORM`) are always loaded into the analyzer process; project-defined constants are not (they live only in ASTs), so their `const_get` raises `NameError` and the lookup falls through to the RBS type tier.

For a successfully resolved ‘String` value:

  • empty string → no refinement (fall through to RBS ‘String`)

  • a Ruby numeric literal → ‘numeric-string`

  • non-empty otherwise → ‘non-empty-string`

**Exclusion set** (‘RUNTIME_INSPECTION_EXCLUDED`): String constants that appear non-empty in the current runtime but are documented to be potentially empty in some build configuration or alternative implementation. Exclusions are populated by scanning Ruby’s C source (version.c, etc.) and RBS comments for any constant whose documentation says “may be empty” or “platform-specific default”. None are known today; the set exists as a safety net.

This module is consulted by ‘Environment#constant_for_name` BEFORE the RBS constant-type table (widest types) but AFTER in-source constant writes (the user’s own ‘Math::PI = 0.0` takes precedence via the lexical-candidate walk in `ExpressionTyper`).

Class Method Summary collapse

Class Method Details

.lookup(name) ⇒ Rigor::Type?

Returns refined type, or nil to fall through.

Parameters:

  • name (String)

    unqualified constant name (e.g. ‘“Math::PI”`, `“RUBY_VERSION”`, `“Ruby::ENGINE”`)

Returns:

  • (Rigor::Type, nil)

    refined type, or nil to fall through



102
103
104
# File 'lib/rigor/builtins/predefined_constant_refinements.rb', line 102

def self.lookup(name)
  FOLDED_CONSTANTS[name] || inspect_runtime_string(name)
end