Skip to content

Commit a80fa85

Browse files
committed
Let Module self types be a list
1 parent 5dd7ff7 commit a80fa85

13 files changed

+168
-118
lines changed

lib/rbs/ast/declarations.rb

+44-6
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,44 @@ def to_json(*a)
204204
end
205205

206206
class Module < Base
207+
class Self
208+
attr_reader :name
209+
attr_reader :args
210+
attr_reader :location
211+
212+
def initialize(name:, args:, location:)
213+
@name = name
214+
@args = args
215+
@location = location
216+
end
217+
218+
def ==(other)
219+
other.is_a?(Self) && other.name == name && other.args == args
220+
end
221+
222+
alias eql? ==
223+
224+
def hash
225+
self.class.hash ^ name.hash ^ args.hash ^ location.hash
226+
end
227+
228+
def to_json(*a)
229+
{
230+
name: name,
231+
args: args,
232+
location: location
233+
}.to_json(*a)
234+
end
235+
236+
def to_s
237+
if args.empty?
238+
name.to_s
239+
else
240+
"#{name}[#{args.join(", ")}]"
241+
end
242+
end
243+
end
244+
207245
include NestedDeclarationHelper
208246
include MixinHelper
209247

@@ -212,13 +250,13 @@ class Module < Base
212250
attr_reader :members
213251
attr_reader :location
214252
attr_reader :annotations
215-
attr_reader :self_type
253+
attr_reader :self_types
216254
attr_reader :comment
217255

218-
def initialize(name:, type_params:, members:, self_type:, annotations:, location:, comment:)
256+
def initialize(name:, type_params:, members:, self_types:, annotations:, location:, comment:)
219257
@name = name
220258
@type_params = type_params
221-
@self_type = self_type
259+
@self_types = self_types
222260
@members = members
223261
@annotations = annotations
224262
@location = location
@@ -229,14 +267,14 @@ def ==(other)
229267
other.is_a?(Module) &&
230268
other.name == name &&
231269
other.type_params == type_params &&
232-
other.self_type == self_type &&
270+
other.self_types == self_types &&
233271
other.members == members
234272
end
235273

236274
alias eql? ==
237275

238276
def hash
239-
self.class.hash ^ name.hash ^ type_params.hash ^ self_type.hash ^ members.hash
277+
self.class.hash ^ name.hash ^ type_params.hash ^ self_types.hash ^ members.hash
240278
end
241279

242280
def to_json(*a)
@@ -245,7 +283,7 @@ def to_json(*a)
245283
name: name,
246284
type_params: type_params,
247285
members: members,
248-
self_type: self_type,
286+
self_types: self_types,
249287
annotations: annotations,
250288
location: location,
251289
comment: comment

lib/rbs/definition_builder.rb

+3-28
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,9 @@ def build_instance(type_name)
243243
end
244244

245245
if entry.is_a?(Environment::ModuleEntry)
246-
if self_type_ancestor = module_self_ancestor(type_name, entry)
247-
definition_pairs.push [
248-
self_type_ancestor,
249-
build_interface(self_type_ancestor.name)
250-
]
246+
entry.self_types.each do |module_self|
247+
ancestor = Definition::Ancestor::Instance.new(name: module_self.name, args: module_self.args)
248+
definition_pairs.push [ancestor, build_interface(module_self.name)]
251249
end
252250
end
253251

@@ -259,29 +257,6 @@ def build_instance(type_name)
259257
end
260258
end
261259

262-
def module_self_ancestor(type_name, entry)
263-
self_decls = entry.decls.select {|d| d.decl.self_type }
264-
265-
return if self_decls.empty?
266-
267-
selfs = self_decls.map do |d|
268-
Definition::Ancestor::Instance.new(
269-
name: d.decl.self_type.name,
270-
args: d.decl.self_type.args
271-
)
272-
end
273-
274-
selfs.uniq!
275-
276-
return selfs[0] if selfs.size == 1
277-
278-
raise ModuleSelfTypeMismatchError.new(
279-
name: type_name,
280-
entry: entry,
281-
location: self_decls[0].decl.location
282-
)
283-
end
284-
285260
def build_singleton(type_name)
286261
try_cache type_name, cache: singleton_cache do
287262
entry = env.class_decls[type_name] or raise "Unknown name for build_singleton: #{type_name}"

lib/rbs/environment.rb

+11-5
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,16 @@ def type_params
5959
end
6060

6161
class ModuleEntry < MultiEntry
62-
def self_type
63-
primary.decl.self_type
62+
def self_types
63+
decls.flat_map do |d|
64+
d.decl.self_types
65+
end.uniq
6466
end
6567

6668
def primary
6769
@primary ||= begin
6870
validate_type_params
69-
decls.find {|d| d.decl.self_type } || decls.first
71+
decls.first
7072
end
7173
end
7274
end
@@ -257,8 +259,12 @@ def resolve_declaration(resolver, decl, outer:, prefix:)
257259
AST::Declarations::Module.new(
258260
name: decl.name.with_prefix(prefix),
259261
type_params: decl.type_params,
260-
self_type: decl.self_type&.yield_self do |self_type|
261-
absolute_type(resolver, self_type, context: context)
262+
self_types: decl.self_types.map do |module_self|
263+
AST::Declarations::Module::Self.new(
264+
name: absolute_type_name(resolver, module_self.name, context: context),
265+
args: module_self.args.map {|type| absolute_type(resolver, type, context: context) },
266+
location: module_self.location
267+
)
262268
end,
263269
members: decl.members.map do |member|
264270
case member

lib/rbs/errors.rb

-14
Original file line numberDiff line numberDiff line change
@@ -198,20 +198,6 @@ def initialize(name:, super_classes:, entry:)
198198
end
199199
end
200200

201-
class ModuleSelfTypeMismatchError < StandardError
202-
attr_reader :name
203-
attr_reader :entry
204-
attr_reader :location
205-
206-
def initialize(name:, entry:, location:)
207-
@name = name
208-
@entry = entry
209-
@location = location
210-
211-
super "#{Location.to_string location}: Module self type mismatch: #{name}"
212-
end
213-
end
214-
215201
class InconsistentMethodVisibilityError < StandardError
216202
attr_reader :type_name
217203
attr_reader :method_name

lib/rbs/parser.y

+45-7
Original file line numberDiff line numberDiff line change
@@ -106,41 +106,79 @@ rule
106106
}
107107

108108
module_decl:
109-
annotations kMODULE start_new_scope class_name module_type_params module_self_type class_members kEND {
109+
annotations kMODULE start_new_scope class_name module_type_params colon_module_self_types class_members kEND {
110110
reset_variable_scope
111111

112112
location = val[1].location + val[7].location
113113
result = Declarations::Module.new(
114114
name: val[3].value,
115115
type_params: val[4]&.value || Declarations::ModuleTypeParams.empty,
116-
self_type: val[5],
116+
self_types: val[5],
117117
members: val[6],
118118
annotations: val[0],
119119
location: location,
120120
comment: leading_comment(val[0].first&.location || location)
121121
)
122122
}
123-
| annotations kMODULE start_new_scope tUKEYWORD type class_members kEND {
123+
| annotations kMODULE start_new_scope tUKEYWORD module_self_types class_members kEND {
124124
reset_variable_scope
125125

126126
location = val[1].location + val[6].location
127127
result = Declarations::Module.new(
128128
name: val[3].value,
129129
type_params: Declarations::ModuleTypeParams.empty,
130-
self_type: val[4],
130+
self_types: val[4],
131131
members: val[5],
132132
annotations: val[0],
133133
location: location,
134134
comment: leading_comment(val[0].first&.location || location)
135135
)
136136
}
137137

138-
module_self_type:
139-
{ result = nil }
140-
| kCOLON type {
138+
colon_module_self_types:
139+
{ result = [] }
140+
| kCOLON module_self_types {
141141
result = val[1]
142142
}
143143

144+
module_self_types:
145+
module_self_type {
146+
result = [val[0]]
147+
}
148+
| module_self_types kCOMMA module_self_type {
149+
result = val[0].push(val[2])
150+
}
151+
152+
module_self_type:
153+
qualified_name kLBRACKET type_list kRBRACKET {
154+
name = val[0].value
155+
args = val[2]
156+
location = val[0].location + val[3].location
157+
158+
case
159+
when name.class?
160+
result = Declarations::Module::Self.new(name: name, args: args, location: location)
161+
when name.interface?
162+
result = Declarations::Module::Self.new(name: name, args: args, location: location)
163+
else
164+
raise SemanticsError.new("Module self type should be instance or interface", subject: val[0], location: val[0].location)
165+
end
166+
}
167+
| qualified_name {
168+
name = val[0].value
169+
args = []
170+
location = val[0].location
171+
172+
case
173+
when name.class?
174+
result = Declarations::Module::Self.new(name: name, args: args, location: location)
175+
when name.interface?
176+
result = Declarations::Module::Self.new(name: name, args: args, location: location)
177+
else
178+
raise SemanticsError.new("Module self type should be instance or interface", subject: val[0], location: val[0].location)
179+
end
180+
}
181+
144182
class_members:
145183
{ result = [] }
146184
| class_members class_member {

lib/rbs/prototype/rb.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def process(node, decls:, comments:, singleton:)
8181
mod = AST::Declarations::Module.new(
8282
name: const_to_name(module_name),
8383
type_params: AST::Declarations::ModuleTypeParams.empty,
84-
self_type: nil,
84+
self_types: [],
8585
members: [],
8686
annotations: [],
8787
location: nil,

lib/rbs/prototype/rbi.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def push_module(name, comment:)
6969
members: [],
7070
annotations: [],
7171
location: nil,
72-
self_type: nil,
72+
self_types: [],
7373
comment: comment
7474
)
7575

lib/rbs/prototype/runtime.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ def generate_module(mod)
370370
decl = AST::Declarations::Module.new(
371371
name: type_name,
372372
type_params: AST::Declarations::ModuleTypeParams.empty,
373-
self_type: nil,
373+
self_types: [],
374374
members: [],
375375
annotations: [],
376376
location: nil,

lib/rbs/writer.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ def write_decl(decl)
8585
puts "end"
8686

8787
when AST::Declarations::Module
88-
self_type = if decl.self_type
89-
" : #{decl.self_type}"
88+
self_type = unless decl.self_types.empty?
89+
" : #{decl.self_types.join(", ")}"
9090
end
9191

9292
write_comment decl.comment

schema/decls.json

+21-10
Original file line numberDiff line numberDiff line change
@@ -226,15 +226,11 @@
226226
"$ref": "#/definitions/classMember"
227227
}
228228
},
229-
"self_type": {
230-
"oneOf": [
231-
{
232-
"$ref": "types.json"
233-
},
234-
{
235-
"type": "null"
236-
}
237-
]
229+
"self_types": {
230+
"type": "array",
231+
"items": {
232+
"$ref": "#/definitions/moduleSelf"
233+
}
238234
},
239235
"annotations": {
240236
"type": "array",
@@ -249,7 +245,22 @@
249245
"$ref": "location.json"
250246
}
251247
},
252-
"required": ["declaration", "name", "type_params", "members", "self_type", "annotations", "location", "comment"]
248+
"required": ["declaration", "name", "type_params", "members", "self_types", "annotations", "location", "comment"]
249+
},
250+
"moduleSelf": {
251+
"type": "object",
252+
"properties": {
253+
"name": {
254+
"type": "string"
255+
},
256+
"args": {
257+
"type": "array",
258+
"items": {
259+
"$ref": "types.json"
260+
}
261+
}
262+
},
263+
"required": ["name", "args"]
253264
},
254265
"interfaceMember": {
255266
"oneOf": [

0 commit comments

Comments
 (0)