Class: Rigor::Type::Constant

Inherits:
Object
  • Object
show all
Defined in:
lib/rigor/type/constant.rb

Overview

A literal carrier under ADR-3 OQ1 Option C (Hybrid). Wraps a Ruby literal value of one of the supported immutable-ish classes. Compound literal shapes (Tuple, HashShape, Record) get dedicated classes in later slices; Range is carried only when both static endpoints are known enough for tuple slicing.

See docs/adr/4-type-inference-engine.md for the tentative answer to the open question and docs/type-specification/rigor-extensions.md for the refinement neighbourhood this carrier lives in.

Constant Summary collapse

SCALAR_CLASSES =
[
  Integer,
  Float,
  String,
  Symbol,
  Range,
  Rational,
  Complex,
  Regexp,
  Pathname,
  ::Set,
  # `Date` covers `DateTime` (a subclass). `Time` is core.
  # Both arise only from deterministic constructor folding
  # (`Date.new` / `Time.utc`) — there is no Date / Time
  # literal node — so a `Constant` carrier is always sound.
  Date,
  Time,
  TrueClass,
  FalseClass,
  NilClass
].freeze
RBS_LITERAL_CLASSES =
{
  TrueClass => "true",
  FalseClass => "false",
  NilClass => "nil"
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value) ⇒ Constant

Returns a new instance of Constant.



48
49
50
51
52
53
54
55
# File 'lib/rigor/type/constant.rb', line 48

def initialize(value)
  unless SCALAR_CLASSES.any? { |klass| value.is_a?(klass) }
    raise ArgumentError, "Rigor::Type::Constant only carries scalar literals; got #{value.class}"
  end

  @value = freezable_carrier?(value) ? value.dup.freeze : value
  freeze
end

Instance Attribute Details

#valueObject (readonly)

Returns the value of attribute value.



46
47
48
# File 'lib/rigor/type/constant.rb', line 46

def value
  @value
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



118
119
120
# File 'lib/rigor/type/constant.rb', line 118

def ==(other)
  other.is_a?(Constant) && value.class == other.value.class && value == other.value
end

#accepts(other, mode: :gradual) ⇒ Object



114
115
116
# File 'lib/rigor/type/constant.rb', line 114

def accepts(other, mode: :gradual)
  Inference::Acceptance.accepts(self, other, mode: mode)
end

#botObject



106
107
108
# File 'lib/rigor/type/constant.rb', line 106

def bot
  Trinary.no
end

#describe(_verbosity = :short) ⇒ Object

‘Date#inspect` / `DateTime#inspect` spell out the internal astronomical-Julian-day representation, which is unreadable in a diagnostic. ISO-8601 is the compact, deterministic form. `Time#inspect` is already compact (`2026-01-01 00:00:00 UTC`), so it keeps the default.



73
74
75
76
77
78
# File 'lib/rigor/type/constant.rb', line 73

def describe(_verbosity = :short)
  case value
  when Date then value.iso8601
  else value.inspect
  end
end

#dynamicObject



110
111
112
# File 'lib/rigor/type/constant.rb', line 110

def dynamic
  Trinary.no
end

#erase_to_rbsObject

RBS supports ‘Literal` types for booleans, nil, integer literals (positive and negative), symbol literals, and string literals. Erasing to these preserves the carrier’s precision at the RBS boundary — ‘Constant<64>` round-trips as `64`, not as `Integer` — and `RbsTypeTranslator#translate_literal` already maps the parsed RBS Literal back to `Constant`. Scalar carriers without RBS Literal support (Float, Range, Rational, Complex, Regexp, Pathname) keep their pre-existing widen-to-class-name behaviour because RBS rejects their literal spellings as syntax errors.



91
92
93
94
95
96
97
98
99
100
# File 'lib/rigor/type/constant.rb', line 91

def erase_to_rbs
  case value
  when true then "true"
  when false then "false"
  when nil then "nil"
  when Integer then value.to_s
  when Symbol, String then value.inspect
  else value.class.name
  end
end

#freezable_carrier?(value) ⇒ Boolean

Mutable-ish carriers are stored as a frozen copy so a later in-place mutation cannot rewrite the literal under us. ‘Time` joins `String` / `Set` here: `Time#localtime` mutates the receiver’s zone in place, so the carrier holds a frozen copy (the catalog also blocklists the mutators). ‘Date` is already immutable, but is duped-and-frozen for symmetry.

Returns:

  • (Boolean)


63
64
65
66
# File 'lib/rigor/type/constant.rb', line 63

def freezable_carrier?(value)
  value.is_a?(String) || value.is_a?(::Set) ||
    value.is_a?(Date) || value.is_a?(Time)
end

#hashObject



123
124
125
# File 'lib/rigor/type/constant.rb', line 123

def hash
  [Constant, value.class, value].hash
end

#inspectObject



127
128
129
# File 'lib/rigor/type/constant.rb', line 127

def inspect
  "#<Rigor::Type::Constant #{describe(:short)}>"
end

#topObject



102
103
104
# File 'lib/rigor/type/constant.rb', line 102

def top
  Trinary.no
end