rigortype 0.0.2 → 0.0.3

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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/data/builtins/ruby_core/array.yml +1470 -0
  3. data/data/builtins/ruby_core/file.yml +501 -0
  4. data/data/builtins/ruby_core/io.yml +1594 -0
  5. data/data/builtins/ruby_core/numeric.yml +1809 -0
  6. data/data/builtins/ruby_core/string.yml +1850 -0
  7. data/lib/rigor/analysis/check_rules.rb +86 -1
  8. data/lib/rigor/analysis/runner.rb +4 -0
  9. data/lib/rigor/builtins/imported_refinements.rb +69 -0
  10. data/lib/rigor/configuration.rb +6 -1
  11. data/lib/rigor/inference/acceptance.rb +149 -0
  12. data/lib/rigor/inference/builtins/array_catalog.rb +46 -0
  13. data/lib/rigor/inference/builtins/method_catalog.rb +90 -0
  14. data/lib/rigor/inference/builtins/numeric_catalog.rb +93 -0
  15. data/lib/rigor/inference/builtins/string_catalog.rb +39 -0
  16. data/lib/rigor/inference/expression_typer.rb +48 -1
  17. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +650 -16
  18. data/lib/rigor/inference/method_dispatcher/file_folding.rb +144 -0
  19. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +113 -0
  20. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +4 -0
  21. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +107 -0
  22. data/lib/rigor/inference/method_dispatcher.rb +28 -21
  23. data/lib/rigor/inference/narrowing.rb +374 -4
  24. data/lib/rigor/inference/scope_indexer.rb +10 -2
  25. data/lib/rigor/inference/statement_evaluator.rb +211 -2
  26. data/lib/rigor/rbs_extended.rb +65 -1
  27. data/lib/rigor/scope.rb +14 -0
  28. data/lib/rigor/type/combinator.rb +69 -1
  29. data/lib/rigor/type/difference.rb +155 -0
  30. data/lib/rigor/type/integer_range.rb +137 -0
  31. data/lib/rigor/type.rb +2 -0
  32. data/lib/rigor/version.rb +1 -1
  33. data/sig/rigor/rbs_extended.rbs +3 -0
  34. data/sig/rigor/scope.rbs +1 -0
  35. data/sig/rigor/type.rbs +51 -1
  36. metadata +15 -1
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "type"
4
+ require_relative "builtins/imported_refinements"
4
5
 
5
6
  module Rigor
6
7
  # Slice 7 phase 15 — first-preview reader for the
@@ -40,7 +41,7 @@ module Rigor
40
41
  # `::Foo::Bar` style constant path. Negative refinements
41
42
  # (`~T`), intersections, and unions are deferred to the
42
43
  # next iteration.
43
- module RbsExtended
44
+ module RbsExtended # rubocop:disable Metrics/ModuleLength
44
45
  DIRECTIVE_PREFIX = "rigor:v1:"
45
46
 
46
47
  # Returned for `predicate-if-true` / `predicate-if-false`.
@@ -190,5 +191,68 @@ module Rigor
190
191
  negative: match[:negation].to_s == "~"
191
192
  )
192
193
  end
194
+
195
+ # Reads the `rigor:v1:return: <kebab-name>` directive off
196
+ # `RBS::Definition::Method#annotations`. The directive
197
+ # overrides a method's RBS-declared return type with one of
198
+ # the imported-built-in refinements registered in
199
+ # `Rigor::Builtins::ImportedRefinements`. The override is the
200
+ # primary integration path for refinement carriers
201
+ # (`non-empty-string`, `positive-int`, `non-empty-array`, …)
202
+ # in v0.0 — annotation-driven, opt-in per method, and never
203
+ # silently rewrites a hand-authored RBS signature outside the
204
+ # annotation.
205
+ #
206
+ # Example annotation in an RBS file:
207
+ #
208
+ # class User
209
+ # %a{rigor:v1:return: non-empty-string}
210
+ # def name: () -> String
211
+ # end
212
+ #
213
+ # The RBS-declared return is `String`. The override
214
+ # tightens it to `non-empty-string` (i.e.
215
+ # `Difference[String, ""]`) for callers; RBS erasure of the
216
+ # tightened return goes back to `String` so the round-trip
217
+ # to ordinary RBS is unaffected.
218
+ #
219
+ # Returns the resolved `Rigor::Type` value, or `nil` when:
220
+ # - the method has no annotations,
221
+ # - none of the annotations match the `rigor:v1:return:`
222
+ # directive,
223
+ # - the directive's payload names a refinement not
224
+ # registered in `Rigor::Builtins::ImportedRefinements`
225
+ # (the analyzer prefers a silent miss over crashing on a
226
+ # typo; future slices MAY surface the miss as a
227
+ # `:warning` self-diagnostic).
228
+ def read_return_type_override(method_def)
229
+ return nil if method_def.nil?
230
+
231
+ annotations = method_def.annotations
232
+ return nil if annotations.nil? || annotations.empty?
233
+
234
+ annotations.each do |annotation|
235
+ type = parse_return_type_override(annotation.string)
236
+ return type if type
237
+ end
238
+ nil
239
+ end
240
+
241
+ RETURN_DIRECTIVE_PATTERN = /
242
+ \A
243
+ rigor:v1:return:
244
+ \s+
245
+ (?<refinement>[a-z][a-z0-9-]*)
246
+ \s*
247
+ \z
248
+ /x
249
+ private_constant :RETURN_DIRECTIVE_PATTERN
250
+
251
+ def parse_return_type_override(string)
252
+ match = RETURN_DIRECTIVE_PATTERN.match(string)
253
+ return nil if match.nil?
254
+
255
+ Builtins::ImportedRefinements.lookup(match[:refinement])
256
+ end
193
257
  end
194
258
  end
data/lib/rigor/scope.rb CHANGED
@@ -250,6 +250,20 @@ module Rigor
250
250
  table[method_name.to_sym]
251
251
  end
252
252
 
253
+ # v0.0.3 A — top-level def lookup for implicit-self
254
+ # calls. Returns the `Prism::DefNode` for a top-level
255
+ # (or DSL-block-nested, outside any class body) `def
256
+ # <method_name>` in the file, or nil. The sentinel key
257
+ # is owned by `Inference::ScopeIndexer::TOP_LEVEL_DEF_KEY`;
258
+ # consumers should treat its presence as an opaque
259
+ # implementation detail and go through this accessor.
260
+ def top_level_def_for(method_name)
261
+ table = @discovered_def_nodes[Inference::ScopeIndexer::TOP_LEVEL_DEF_KEY]
262
+ return nil unless table
263
+
264
+ table[method_name.to_sym]
265
+ end
266
+
253
267
  def with_discovered_def_nodes(table)
254
268
  rebuild(discovered_def_nodes: table)
255
269
  end
@@ -6,9 +6,11 @@ require_relative "dynamic"
6
6
  require_relative "nominal"
7
7
  require_relative "singleton"
8
8
  require_relative "constant"
9
+ require_relative "integer_range"
9
10
  require_relative "tuple"
10
11
  require_relative "hash_shape"
11
12
  require_relative "union"
13
+ require_relative "difference"
12
14
 
13
15
  module Rigor
14
16
  module Type
@@ -20,7 +22,7 @@ module Rigor
20
22
  #
21
23
  # See docs/internal-spec/internal-type-api.md and
22
24
  # docs/type-specification/normalization.md.
23
- module Combinator
25
+ module Combinator # rubocop:disable Metrics/ModuleLength
24
26
  module_function
25
27
 
26
28
  def top
@@ -65,6 +67,72 @@ module Rigor
65
67
  Constant.new(value)
66
68
  end
67
69
 
70
+ # Bounded-integer carrier. Each bound is either an `Integer` or
71
+ # one of `:neg_infinity` / `:pos_infinity` (sentinels exposed as
72
+ # `IntegerRange::NEG_INFINITY` / `POS_INFINITY`).
73
+ def integer_range(min, max)
74
+ IntegerRange.new(min, max)
75
+ end
76
+
77
+ # Convenience aliases for the most common bounded shapes. The
78
+ # named alias survives roundtrip through `describe` for nicer
79
+ # human-facing output.
80
+ def positive_int
81
+ IntegerRange.new(1, IntegerRange::POS_INFINITY)
82
+ end
83
+
84
+ def non_negative_int
85
+ IntegerRange.new(0, IntegerRange::POS_INFINITY)
86
+ end
87
+
88
+ def negative_int
89
+ IntegerRange.new(IntegerRange::NEG_INFINITY, -1)
90
+ end
91
+
92
+ def non_positive_int
93
+ IntegerRange.new(IntegerRange::NEG_INFINITY, 0)
94
+ end
95
+
96
+ def universal_int
97
+ IntegerRange.new(IntegerRange::NEG_INFINITY, IntegerRange::POS_INFINITY)
98
+ end
99
+
100
+ # Point-removal refinement carrier (ADR-3 OQ3 Option C). Use
101
+ # `non_empty_string` / `non_zero_int` / `non_empty_array` /
102
+ # `non_empty_hash` for the imported built-in shapes; raw
103
+ # `difference(base, removed)` for ad-hoc refinements an
104
+ # `RBS::Extended` annotation introduces.
105
+ def difference(base, removed)
106
+ Difference.new(base, removed)
107
+ end
108
+
109
+ def non_empty_string
110
+ Difference.new(nominal_of("String"), constant_of(""))
111
+ end
112
+
113
+ def non_zero_int
114
+ Difference.new(nominal_of("Integer"), constant_of(0))
115
+ end
116
+
117
+ # `non-empty-array[T]` requires the element type so the
118
+ # `Nominal[Array, [T]]` projection through Array#first /
119
+ # #last keeps element precision intact. The default
120
+ # `Top` admits any array element when the caller does
121
+ # not have a more specific element type.
122
+ def non_empty_array(element = top)
123
+ Difference.new(
124
+ nominal_of("Array", type_args: [element]),
125
+ tuple_of
126
+ )
127
+ end
128
+
129
+ def non_empty_hash(key = top, value = top)
130
+ Difference.new(
131
+ nominal_of("Hash", type_args: [key, value]),
132
+ hash_shape_of({})
133
+ )
134
+ end
135
+
68
136
  # Constructs a heterogeneous, fixed-arity Tuple from positional
69
137
  # element types. `tuple_of()` produces the empty tuple `Tuple[]`,
70
138
  # which is structurally distinct from the raw `Nominal[Array]`.
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../trinary"
4
+
5
+ module Rigor
6
+ module Type
7
+ # `Difference[base, removed]` — the value set of `base` minus
8
+ # the value set of `removed`. Implements the point-removal
9
+ # half of the OQ3 refinement-carrier strategy
10
+ # ([ADR-3](docs/adr/3-type-representation.md), Working
11
+ # Decision Option C):
12
+ #
13
+ # non-empty-string = Difference[Nominal[String], Constant[""]]
14
+ # non-zero-int = Difference[Nominal[Integer], Constant[0]]
15
+ # non-empty-array[T] = Difference[Nominal[Array, [T]], Tuple[]]
16
+ # non-empty-hash[K,V] = Difference[Nominal[Hash, [K,V]], HashShape{}]
17
+ #
18
+ # The carrier itself is structural: it stores `base` and
19
+ # `removed` as inner `Type` references and answers projection
20
+ # / acceptance / display questions by composing those inner
21
+ # answers per the lattice algebra in
22
+ # [`value-lattice.md`](docs/type-specification/value-lattice.md).
23
+ # The canonical-name registry (display side) lives in
24
+ # `Rigor::Type::Combinator` and prints kebab-case names like
25
+ # `non-empty-string` for the recognised shapes; unrecognised
26
+ # differences fall back to the raw `base - removed`
27
+ # operator form per [`type-operators.md`](docs/type-specification/type-operators.md).
28
+ #
29
+ # Construction goes through `Type::Combinator.difference` /
30
+ # `Combinator.non_empty_string` etc. — direct `.new` calls
31
+ # are an internal contract; callers MUST ensure both bounds
32
+ # are valid `Rigor::Type` values and that `removed` is a
33
+ # subtype-or-equal of `base` (otherwise the difference does
34
+ # not narrow anything and a normalisation upstream should
35
+ # collapse to `base`).
36
+ class Difference
37
+ attr_reader :base, :removed
38
+
39
+ def initialize(base, removed)
40
+ @base = base
41
+ @removed = removed
42
+ freeze
43
+ end
44
+
45
+ def describe(verbosity = :short)
46
+ named = canonical_name
47
+ return named if named
48
+
49
+ "#{base.describe(verbosity)} - #{removed.describe(verbosity)}"
50
+ end
51
+
52
+ # Erases to the base nominal: every refinement MUST erase
53
+ # to its base per [`rbs-erasure.md`](docs/type-specification/rbs-erasure.md).
54
+ def erase_to_rbs
55
+ base.erase_to_rbs
56
+ end
57
+
58
+ def top
59
+ Trinary.no
60
+ end
61
+
62
+ def bot
63
+ Trinary.no
64
+ end
65
+
66
+ def dynamic
67
+ base.respond_to?(:dynamic) ? base.dynamic : Trinary.no
68
+ end
69
+
70
+ def accepts(other, mode: :gradual)
71
+ Inference::Acceptance.accepts(self, other, mode: mode)
72
+ end
73
+
74
+ def ==(other)
75
+ other.is_a?(Difference) && base == other.base && removed == other.removed
76
+ end
77
+ alias eql? ==
78
+
79
+ def hash
80
+ [Difference, base, removed].hash
81
+ end
82
+
83
+ def inspect
84
+ "#<Rigor::Type::Difference #{describe(:short)}>"
85
+ end
86
+
87
+ private
88
+
89
+ # Renders the kebab-case shorthand for recognised
90
+ # imported-built-in shapes. Parameterised bases keep their
91
+ # type-args in the canonical form (`non-empty-array[T]`,
92
+ # `non-empty-hash[K, V]`) so element-precision survives the
93
+ # display round-trip. Unrecognised shapes fall back to the
94
+ # raw `base - removed` operator form.
95
+ #
96
+ # The recognised set is kept in sync with the imported-built-in
97
+ # catalogue ([`imported-built-in-types.md`](docs/type-specification/imported-built-in-types.md)).
98
+ def canonical_name
99
+ return nil unless base.is_a?(Nominal)
100
+
101
+ send(CANONICAL_HANDLERS[base.class_name] || :no_canonical_name)
102
+ end
103
+
104
+ CANONICAL_HANDLERS = {
105
+ "String" => :string_canonical_name,
106
+ "Integer" => :integer_canonical_name,
107
+ "Array" => :array_canonical_name_if_empty,
108
+ "Hash" => :hash_canonical_name_if_empty
109
+ }.freeze
110
+ private_constant :CANONICAL_HANDLERS
111
+
112
+ def no_canonical_name
113
+ nil
114
+ end
115
+
116
+ def string_canonical_name
117
+ return nil unless removed.is_a?(Constant) && removed.value == ""
118
+
119
+ "non-empty-string"
120
+ end
121
+
122
+ def integer_canonical_name
123
+ return nil unless removed.is_a?(Constant) && removed.value.is_a?(Integer) && removed.value.zero?
124
+
125
+ "non-zero-int"
126
+ end
127
+
128
+ def array_canonical_name_if_empty
129
+ return nil unless removed.is_a?(Tuple) && removed.elements.empty?
130
+
131
+ array_canonical_name
132
+ end
133
+
134
+ def hash_canonical_name_if_empty
135
+ return nil unless removed.is_a?(HashShape) && removed.pairs.empty?
136
+
137
+ hash_canonical_name
138
+ end
139
+
140
+ def array_canonical_name
141
+ elem = base.type_args.first
142
+ return "non-empty-array" if elem.nil?
143
+
144
+ "non-empty-array[#{elem.describe}]"
145
+ end
146
+
147
+ def hash_canonical_name
148
+ key, value = base.type_args
149
+ return "non-empty-hash" if key.nil? || value.nil?
150
+
151
+ "non-empty-hash[#{key.describe}, #{value.describe}]"
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../trinary"
4
+
5
+ module Rigor
6
+ module Type
7
+ # A bounded integer range carrier. Each bound is either an `Integer`
8
+ # or one of the symbolic infinities `:neg_infinity` / `:pos_infinity`.
9
+ # Inspired by PHPStan's `int<min, max>` family — the named aliases
10
+ # `positive-int` (1..), `non-negative-int` (0..), `negative-int`
11
+ # (..-1), `non-positive-int` (..0) all surface through this single
12
+ # carrier and are recovered in `describe` for human-friendly output.
13
+ #
14
+ # Constraints on construction:
15
+ # - both bounds must be either `Integer` or one of the two infinity
16
+ # sentinels;
17
+ # - if both bounds are concrete, `min <= max` must hold;
18
+ # - the universal case `(-∞, +∞)` is structurally distinct from
19
+ # `Nominal[Integer]` — it carries no extra information today but
20
+ # keeps the carrier closed under range narrowing.
21
+ #
22
+ # Erasure to RBS is always "Integer": RBS itself does not natively
23
+ # express bounded integer ranges.
24
+ class IntegerRange
25
+ NEG_INFINITY = :neg_infinity
26
+ POS_INFINITY = :pos_infinity
27
+ INFINITIES = [NEG_INFINITY, POS_INFINITY].freeze
28
+
29
+ attr_reader :min, :max
30
+
31
+ def initialize(min, max)
32
+ validate_bound!(min, "min")
33
+ validate_bound!(max, "max")
34
+ if min.is_a?(Integer) && max.is_a?(Integer) && min > max
35
+ raise ArgumentError, "IntegerRange requires min (#{min}) <= max (#{max})"
36
+ end
37
+ if min == POS_INFINITY || max == NEG_INFINITY
38
+ raise ArgumentError, "IntegerRange bounds out of order: min=#{min.inspect}, max=#{max.inspect}"
39
+ end
40
+
41
+ @min = min
42
+ @max = max
43
+ freeze
44
+ end
45
+
46
+ def universal?
47
+ min == NEG_INFINITY && max == POS_INFINITY
48
+ end
49
+
50
+ def finite?
51
+ min.is_a?(Integer) && max.is_a?(Integer)
52
+ end
53
+
54
+ def cardinality
55
+ finite? ? (max - min + 1) : Float::INFINITY
56
+ end
57
+
58
+ def covers?(int)
59
+ return false unless int.is_a?(Integer)
60
+
61
+ int.between?(lower, upper)
62
+ end
63
+
64
+ # Returns the lower bound as a numeric (with `-Float::INFINITY` for
65
+ # `:neg_infinity`). Use this in arithmetic comparisons; never compare
66
+ # `:neg_infinity` directly with an `Integer`.
67
+ def lower
68
+ min == NEG_INFINITY ? -Float::INFINITY : min
69
+ end
70
+
71
+ def upper
72
+ max == POS_INFINITY ? Float::INFINITY : max
73
+ end
74
+
75
+ ALIAS_NAMES = {
76
+ [NEG_INFINITY, POS_INFINITY] => "int",
77
+ [1, POS_INFINITY] => "positive-int",
78
+ [0, POS_INFINITY] => "non-negative-int",
79
+ [NEG_INFINITY, -1] => "negative-int",
80
+ [NEG_INFINITY, 0] => "non-positive-int"
81
+ }.freeze
82
+
83
+ def describe(_verbosity = :short)
84
+ ALIAS_NAMES[[min, max]] || generic_description
85
+ end
86
+
87
+ def generic_description
88
+ return "int<#{min}, max>" if max == POS_INFINITY
89
+ return "int<min, #{max}>" if min == NEG_INFINITY
90
+
91
+ "int<#{min}, #{max}>"
92
+ end
93
+
94
+ def erase_to_rbs
95
+ "Integer"
96
+ end
97
+
98
+ def top
99
+ Trinary.no
100
+ end
101
+
102
+ def bot
103
+ Trinary.no
104
+ end
105
+
106
+ def dynamic
107
+ Trinary.no
108
+ end
109
+
110
+ def accepts(other, mode: :gradual)
111
+ Inference::Acceptance.accepts(self, other, mode: mode)
112
+ end
113
+
114
+ def ==(other)
115
+ other.is_a?(IntegerRange) && min == other.min && max == other.max
116
+ end
117
+ alias eql? ==
118
+
119
+ def hash
120
+ [IntegerRange, min, max].hash
121
+ end
122
+
123
+ def inspect
124
+ "#<Rigor::Type::IntegerRange #{describe(:short)}>"
125
+ end
126
+
127
+ private
128
+
129
+ def validate_bound!(bound, label)
130
+ return if bound.is_a?(Integer) || INFINITIES.include?(bound)
131
+
132
+ raise ArgumentError,
133
+ "IntegerRange #{label} must be Integer or :neg_infinity/:pos_infinity, got #{bound.inspect}"
134
+ end
135
+ end
136
+ end
137
+ end
data/lib/rigor/type.rb CHANGED
@@ -16,8 +16,10 @@ require_relative "type/dynamic"
16
16
  require_relative "type/nominal"
17
17
  require_relative "type/singleton"
18
18
  require_relative "type/constant"
19
+ require_relative "type/integer_range"
19
20
  require_relative "type/tuple"
20
21
  require_relative "type/hash_shape"
21
22
  require_relative "type/union"
23
+ require_relative "type/difference"
22
24
  require_relative "type/accepts_result"
23
25
  require_relative "type/combinator"
data/lib/rigor/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rigor
4
- VERSION = "0.0.2"
4
+ VERSION = "0.0.3"
5
5
  end
@@ -39,5 +39,8 @@ module Rigor
39
39
 
40
40
  def self?.read_assert_effects: (untyped method_def) -> Array[AssertEffect]
41
41
  def self?.parse_assert_annotation: (String string) -> AssertEffect?
42
+
43
+ def self?.read_return_type_override: (untyped method_def) -> Type::t?
44
+ def self?.parse_return_type_override: (String string) -> Type::t?
42
45
  end
43
46
  end
data/sig/rigor/scope.rbs CHANGED
@@ -38,6 +38,7 @@ module Rigor
38
38
  def discovered_method?: (String | Symbol class_name, String | Symbol method_name, Symbol kind) -> bool
39
39
  def with_discovered_def_nodes: (Hash[String, Hash[Symbol, untyped]] table) -> Scope
40
40
  def user_def_for: (String | Symbol class_name, String | Symbol method_name) -> untyped?
41
+ def top_level_def_for: (String | Symbol method_name) -> untyped?
41
42
  def with_fact: (Analysis::FactStore::Fact fact) -> Scope
42
43
  def with_self_type: (Type::t? type) -> Scope
43
44
  def with_declared_types: (Hash[untyped, Type::t] table) -> Scope
data/sig/rigor/type.rbs CHANGED
@@ -1,6 +1,6 @@
1
1
  module Rigor
2
2
  module Type
3
- type t = Top | Bot | Dynamic | Constant | Nominal | Singleton | Union | Tuple | HashShape
3
+ type t = Top | Bot | Dynamic | Constant | IntegerRange | Nominal | Singleton | Union | Difference | Tuple | HashShape
4
4
 
5
5
  type accepts_mode = :strict | :gradual | :loose
6
6
 
@@ -58,6 +58,30 @@ module Rigor
58
58
  def inspect: () -> String
59
59
  end
60
60
 
61
+ class IntegerRange
62
+ NEG_INFINITY: Symbol
63
+ POS_INFINITY: Symbol
64
+ attr_reader min: (Integer | Symbol)
65
+ attr_reader max: (Integer | Symbol)
66
+ def initialize: ((Integer | Symbol) min, (Integer | Symbol) max) -> void
67
+ def universal?: () -> bool
68
+ def finite?: () -> bool
69
+ def cardinality: () -> (Integer | Float)
70
+ def covers?: (untyped value) -> bool
71
+ def lower: () -> Numeric
72
+ def upper: () -> Numeric
73
+ def describe: (?Symbol verbosity) -> String
74
+ def generic_description: () -> String
75
+ def erase_to_rbs: () -> String
76
+ def top: () -> Top
77
+ def bot: () -> Bot
78
+ def dynamic: () -> Dynamic
79
+ def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
80
+ def ==: (untyped other) -> bool
81
+ def hash: () -> Integer
82
+ def inspect: () -> String
83
+ end
84
+
61
85
  class Nominal
62
86
  attr_reader class_name: String
63
87
  attr_reader type_args: Array[Type::t]
@@ -101,6 +125,21 @@ module Rigor
101
125
  def inspect: () -> String
102
126
  end
103
127
 
128
+ class Difference
129
+ attr_reader base: Type::t
130
+ attr_reader removed: Type::t
131
+ def initialize: (Type::t base, Type::t removed) -> void
132
+ def describe: (?Symbol verbosity) -> String
133
+ def erase_to_rbs: () -> String
134
+ def top: () -> Top
135
+ def bot: () -> Bot
136
+ def dynamic: () -> Dynamic
137
+ def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
138
+ def ==: (untyped other) -> bool
139
+ def hash: () -> Integer
140
+ def inspect: () -> String
141
+ end
142
+
104
143
  class Tuple
105
144
  attr_reader elements: Array[Type::t]
106
145
  def initialize: (Array[Type::t] elements) -> void
@@ -163,6 +202,17 @@ module Rigor
163
202
  def self?.nominal_of: (Module | String class_name_or_object, ?type_args: Array[Type::t]) -> Nominal
164
203
  def self?.singleton_of: (Module | String class_name_or_object) -> Singleton
165
204
  def self?.constant_of: (untyped value) -> Constant
205
+ def self?.difference: (Type::t base, Type::t removed) -> Difference
206
+ def self?.non_empty_string: () -> Difference
207
+ def self?.non_zero_int: () -> Difference
208
+ def self?.non_empty_array: (?Type::t element) -> Difference
209
+ def self?.non_empty_hash: (?Type::t key, ?Type::t value) -> Difference
210
+ def self?.integer_range: ((Integer | Symbol) min, (Integer | Symbol) max) -> IntegerRange
211
+ def self?.positive_int: () -> IntegerRange
212
+ def self?.non_negative_int: () -> IntegerRange
213
+ def self?.negative_int: () -> IntegerRange
214
+ def self?.non_positive_int: () -> IntegerRange
215
+ def self?.universal_int: () -> IntegerRange
166
216
  def self?.tuple_of: (*Type::t elements) -> Tuple
167
217
  def self?.hash_shape_of: (?Hash[untyped, Type::t]? pairs, **untyped options) -> HashShape
168
218
  def self?.union: (*Type::t types) -> Type::t
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.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rigor contributors
@@ -160,6 +160,11 @@ extra_rdoc_files: []
160
160
  files:
161
161
  - LICENSE
162
162
  - README.md
163
+ - data/builtins/ruby_core/array.yml
164
+ - data/builtins/ruby_core/file.yml
165
+ - data/builtins/ruby_core/io.yml
166
+ - data/builtins/ruby_core/numeric.yml
167
+ - data/builtins/ruby_core/string.yml
163
168
  - exe/rigor
164
169
  - lib/rigor.rb
165
170
  - lib/rigor/analysis/check_rules.rb
@@ -169,6 +174,7 @@ files:
169
174
  - lib/rigor/analysis/runner.rb
170
175
  - lib/rigor/ast.rb
171
176
  - lib/rigor/ast/type_node.rb
177
+ - lib/rigor/builtins/imported_refinements.rb
172
178
  - lib/rigor/cli.rb
173
179
  - lib/rigor/cli/type_of_command.rb
174
180
  - lib/rigor/cli/type_of_renderer.rb
@@ -182,6 +188,10 @@ files:
182
188
  - lib/rigor/environment/rbs_loader.rb
183
189
  - lib/rigor/inference/acceptance.rb
184
190
  - lib/rigor/inference/block_parameter_binder.rb
191
+ - lib/rigor/inference/builtins/array_catalog.rb
192
+ - lib/rigor/inference/builtins/method_catalog.rb
193
+ - lib/rigor/inference/builtins/numeric_catalog.rb
194
+ - lib/rigor/inference/builtins/string_catalog.rb
185
195
  - lib/rigor/inference/closure_escape_analyzer.rb
186
196
  - lib/rigor/inference/coverage_scanner.rb
187
197
  - lib/rigor/inference/expression_typer.rb
@@ -189,6 +199,8 @@ files:
189
199
  - lib/rigor/inference/fallback_tracer.rb
190
200
  - lib/rigor/inference/method_dispatcher.rb
191
201
  - lib/rigor/inference/method_dispatcher/constant_folding.rb
202
+ - lib/rigor/inference/method_dispatcher/file_folding.rb
203
+ - lib/rigor/inference/method_dispatcher/iterator_dispatch.rb
192
204
  - lib/rigor/inference/method_dispatcher/overload_selector.rb
193
205
  - lib/rigor/inference/method_dispatcher/rbs_dispatch.rb
194
206
  - lib/rigor/inference/method_dispatcher/shape_dispatch.rb
@@ -210,8 +222,10 @@ files:
210
222
  - lib/rigor/type/bot.rb
211
223
  - lib/rigor/type/combinator.rb
212
224
  - lib/rigor/type/constant.rb
225
+ - lib/rigor/type/difference.rb
213
226
  - lib/rigor/type/dynamic.rb
214
227
  - lib/rigor/type/hash_shape.rb
228
+ - lib/rigor/type/integer_range.rb
215
229
  - lib/rigor/type/nominal.rb
216
230
  - lib/rigor/type/singleton.rb
217
231
  - lib/rigor/type/top.rb