tapioca 0.6.0 → 0.6.4

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.
@@ -23,17 +23,31 @@ module T
23
23
  def type_member(variance = :invariant, fixed: nil, lower: T.untyped, upper: BasicObject)
24
24
  # `T::Generic#type_member` just instantiates a `T::Type::TypeMember` instance and returns it.
25
25
  # We use that when registering the type member and then later return it from this method.
26
- type_member = Tapioca::TypeMember.new(variance, fixed, lower, upper)
27
- Tapioca::GenericTypeRegistry.register_type_variable(self, type_member)
28
- type_member
26
+ Tapioca::TypeVariableModule.new(
27
+ T.cast(self, Module),
28
+ Tapioca::TypeVariableModule::Type::Member,
29
+ variance,
30
+ fixed,
31
+ lower,
32
+ upper
33
+ ).tap do |type_variable|
34
+ Tapioca::GenericTypeRegistry.register_type_variable(self, type_variable)
35
+ end
29
36
  end
30
37
 
31
38
  def type_template(variance = :invariant, fixed: nil, lower: T.untyped, upper: BasicObject)
32
39
  # `T::Generic#type_template` just instantiates a `T::Type::TypeTemplate` instance and returns it.
33
40
  # We use that when registering the type template and then later return it from this method.
34
- type_template = Tapioca::TypeTemplate.new(variance, fixed, lower, upper)
35
- Tapioca::GenericTypeRegistry.register_type_variable(self, type_template)
36
- type_template
41
+ Tapioca::TypeVariableModule.new(
42
+ T.cast(self, Module),
43
+ Tapioca::TypeVariableModule::Type::Template,
44
+ variance,
45
+ fixed,
46
+ lower,
47
+ upper
48
+ ).tap do |type_variable|
49
+ Tapioca::GenericTypeRegistry.register_type_variable(self, type_variable)
50
+ end
37
51
  end
38
52
  end
39
53
 
@@ -42,15 +56,26 @@ module T
42
56
 
43
57
  module Types
44
58
  class Simple
45
- # This module intercepts calls to the `name` method for
46
- # simple types, so that it can ask the name to the type if
47
- # the type is generic, since, by this point, we've created
48
- # a clone of that type with the `name` method returning the
49
- # appropriate name for that specific concrete type.
50
- module GenericNamePatch
59
+ module GenericPatch
60
+ def valid?(obj)
61
+ # Since `Tapioca::TypeVariable` is a `Module`, it will be wrapped by a
62
+ # `Simple` type. We want to always make type variable types valid, so we
63
+ # need to explicitly check that `raw_type` is a `Tapioca::TypeVariable`
64
+ # and return `true`
65
+ if defined?(Tapioca::TypeVariableModule) && Tapioca::TypeVariableModule === @raw_type
66
+ return true
67
+ end
68
+
69
+ obj.is_a?(@raw_type)
70
+ end
71
+
72
+ # This method intercepts calls to the `name` method for simple types, so that
73
+ # it can ask the name to the type if the type is generic, since, by this point,
74
+ # we've created a clone of that type with the `name` method returning the
75
+ # appropriate name for that specific concrete type.
51
76
  def name
52
- if T::Generic === @raw_type
53
- # for types that are generic, use the name
77
+ if T::Generic === @raw_type || Tapioca::TypeVariableModule === @raw_type
78
+ # for types that are generic or are type variables, use the name
54
79
  # returned by the "name" method of this instance
55
80
  @name ||= T.unsafe(@raw_type).name.freeze
56
81
  else
@@ -60,60 +85,57 @@ module T
60
85
  end
61
86
  end
62
87
 
63
- prepend GenericNamePatch
88
+ prepend GenericPatch
64
89
  end
65
90
  end
66
91
  end
67
92
 
68
93
  module Tapioca
69
- class TypeMember < T::Types::TypeMember
94
+ # This is subclassing from `Module` so that instances of this type will be modules.
95
+ # The reason why we want that is because that means those instances will automatically
96
+ # get bound to the constant names they are assigned to by Ruby. As a result, we don't
97
+ # need to do any matching of constants to type variables to bind their names, Ruby will
98
+ # do that automatically for us and we get the `name` method for free from `Module`.
99
+ class TypeVariableModule < Module
70
100
  extend T::Sig
71
101
 
72
- sig { returns(T.nilable(String)) }
73
- attr_accessor :name
74
-
75
- sig { returns(T.untyped) }
76
- attr_reader :fixed, :lower, :upper
102
+ class Type < T::Enum
103
+ enums do
104
+ Member = new("type_member")
105
+ Template = new("type_template")
106
+ end
107
+ end
77
108
 
78
- sig { params(variance: Symbol, fixed: T.untyped, lower: T.untyped, upper: T.untyped).void }
79
- def initialize(variance, fixed, lower, upper)
80
- super(variance)
109
+ sig do
110
+ params(context: Module, type: Type, variance: Symbol, fixed: T.untyped, lower: T.untyped, upper: T.untyped).void
111
+ end
112
+ def initialize(context, type, variance, fixed, lower, upper) # rubocop:disable Metrics/ParameterLists
113
+ @context = context
114
+ @type = type
115
+ @variance = variance
81
116
  @fixed = fixed
82
117
  @lower = lower
83
118
  @upper = upper
119
+ super()
84
120
  end
85
121
 
86
- sig { returns(String) }
87
- def serialize
88
- parts = []
89
- parts << ":#{@variance}" unless @variance == :invariant
90
- parts << "fixed: #{@fixed}" if @fixed
91
- parts << "lower: #{@lower}" unless @lower == T.untyped
92
- parts << "upper: #{@upper}" unless @upper == BasicObject
93
-
94
- parameters = parts.join(", ")
95
-
96
- serialized = +"type_member"
97
- serialized << "(#{parameters})" unless parameters.empty?
98
- serialized
99
- end
100
- end
101
-
102
- class TypeTemplate < T::Types::TypeTemplate
103
- extend T::Sig
104
-
105
122
  sig { returns(T.nilable(String)) }
106
- attr_accessor :name
107
-
108
- sig { returns(T.untyped) }
109
- attr_reader :fixed, :lower, :upper
123
+ def name
124
+ constant_name = super
125
+
126
+ # This is a hack to work around modules under anonymous modules not having
127
+ # names in 2.6 and 2.7: https://bugs.ruby-lang.org/issues/14895
128
+ #
129
+ # This happens when a type variable is declared under `class << self`, for
130
+ # example.
131
+ #
132
+ # The workaround is to give the parent context a name, at which point, our
133
+ # module gets bound to a name under that name, as well.
134
+ unless constant_name
135
+ constant_name = with_bound_name_pre_3_0 { super }
136
+ end
110
137
 
111
- sig { params(variance: Symbol, fixed: T.untyped, lower: T.untyped, upper: T.untyped).void }
112
- def initialize(variance, fixed, lower, upper)
113
- super(variance)
114
- @fixed = fixed
115
- @lower = lower
116
- @upper = upper
138
+ constant_name&.split("::")&.last
117
139
  end
118
140
 
119
141
  sig { returns(String) }
@@ -126,9 +148,25 @@ module Tapioca
126
148
 
127
149
  parameters = parts.join(", ")
128
150
 
129
- serialized = +"type_template"
151
+ serialized = @type.serialize.dup
130
152
  serialized << "(#{parameters})" unless parameters.empty?
131
153
  serialized
132
154
  end
155
+
156
+ private
157
+
158
+ sig do
159
+ type_parameters(:Result)
160
+ .params(block: T.proc.returns(T.type_parameter(:Result)))
161
+ .returns(T.type_parameter(:Result))
162
+ end
163
+ def with_bound_name_pre_3_0(&block)
164
+ require "securerandom"
165
+ temp_name = "TYPE_VARIABLE_TRACKING_#{SecureRandom.hex}"
166
+ self.class.const_set(temp_name, @context)
167
+ block.call
168
+ ensure
169
+ self.class.send(:remove_const, temp_name) if temp_name
170
+ end
133
171
  end
134
172
  end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.6.0"
5
+ VERSION = "0.6.4"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tapioca
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ufuk Kayserilioglu
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2021-12-17 00:00:00.000000000 Z
14
+ date: 2022-02-11 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -115,14 +115,14 @@ dependencies:
115
115
  requirements:
116
116
  - - ">="
117
117
  - !ruby/object:Gem::Version
118
- version: 0.19.2
118
+ version: 1.2.0
119
119
  type: :runtime
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
123
  - - ">="
124
124
  - !ruby/object:Gem::Version
125
- version: 0.19.2
125
+ version: 1.2.0
126
126
  - !ruby/object:Gem::Dependency
127
127
  name: yard-sorbet
128
128
  requirement: !ruby/object:Gem::Requirement