Skip to content

Commit f0e2410

Browse files
authored
Merge pull request #2241 from ksss/variable-duplication-error
Check variable duplication
2 parents 44014d6 + 795eb65 commit f0e2410

File tree

4 files changed

+131
-0
lines changed

4 files changed

+131
-0
lines changed

lib/rbs/definition_builder.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ def define_instance(definition, type_name, subst)
151151
end
152152

153153
when AST::Members::InstanceVariable
154+
InstanceVariableDuplicationError.check!(variables: definition.instance_variables, member: member, type_name: type_name)
154155
insert_variable(
155156
type_name,
156157
definition.instance_variables,
@@ -159,6 +160,7 @@ def define_instance(definition, type_name, subst)
159160
)
160161

161162
when AST::Members::ClassVariable
163+
ClassVariableDuplicationError.check!(variables: definition.class_variables, member: member, type_name: type_name)
162164
insert_variable(type_name, definition.class_variables, name: member.name, type: member.type)
163165
end
164166
end
@@ -287,9 +289,11 @@ def build_singleton0(type_name)
287289
end
288290

289291
when AST::Members::ClassInstanceVariable
292+
ClassInstanceVariableDuplicationError.check!(variables: definition.instance_variables, member: member, type_name: type_name)
290293
insert_variable(type_name, definition.instance_variables, name: member.name, type: member.type)
291294

292295
when AST::Members::ClassVariable
296+
ClassVariableDuplicationError.check!(variables: definition.class_variables, member: member, type_name: type_name)
293297
insert_variable(type_name, definition.class_variables, name: member.name, type: member.type)
294298
end
295299
end

lib/rbs/errors.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,51 @@ def type_name
322322
end
323323
end
324324

325+
class VariableDuplicationError < DefinitionError
326+
include DetailedMessageable
327+
328+
attr_reader :member
329+
330+
def initialize(member:)
331+
@member = member
332+
333+
super "#{Location.to_string location}: Duplicated variable name #{member.name}"
334+
end
335+
336+
def location
337+
loc = @member.location or raise
338+
loc[:name]
339+
end
340+
end
341+
342+
class InstanceVariableDuplicationError < VariableDuplicationError
343+
def self.check!(variables:, member:, type_name:)
344+
if old = variables[member.name]
345+
if old.declared_in == type_name
346+
raise new(member: member)
347+
end
348+
end
349+
end
350+
end
351+
352+
class ClassInstanceVariableDuplicationError < VariableDuplicationError
353+
def self.check!(variables:, member:, type_name:)
354+
if old = variables[member.name]
355+
if old.declared_in == type_name
356+
raise new(member: member)
357+
end
358+
end
359+
end
360+
end
361+
362+
class ClassVariableDuplicationError < VariableDuplicationError
363+
def self.check!(variables:, member:, type_name:)
364+
if old = variables[member.name]
365+
raise new(member: member)
366+
end
367+
end
368+
end
369+
325370
class UnknownMethodAliasError < DefinitionError
326371
include DetailedMessageable
327372

sig/errors.rbs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,28 @@ module RBS
182182
def location: () -> AST::Members::Mixin::loc?
183183
end
184184

185+
class VariableDuplicationError < DefinitionError
186+
include DetailedMessageable
187+
188+
attr_reader member: AST::Members::Var
189+
190+
def initialize: (member: AST::Members::Var) -> void
191+
192+
def location: () -> Location[bot, bot]
193+
end
194+
195+
class InstanceVariableDuplicationError < VariableDuplicationError
196+
def self.check!: (variables: Hash[Symbol, Definition::Variable], member: AST::Members::InstanceVariable, type_name: TypeName) -> void
197+
end
198+
199+
class ClassInstanceVariableDuplicationError < VariableDuplicationError
200+
def self.check!: (variables: Hash[Symbol, Definition::Variable], member: AST::Members::ClassInstanceVariable, type_name: TypeName) -> void
201+
end
202+
203+
class ClassVariableDuplicationError < VariableDuplicationError
204+
def self.check!: (variables: Hash[Symbol, Definition::Variable], member: AST::Members::ClassVariable, type_name: TypeName) -> void
205+
end
206+
185207
# The `alias` member declares an alias from unknown method
186208
#
187209
class UnknownMethodAliasError < DefinitionError

test/rbs/definition_builder_test.rb

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,4 +2705,64 @@ module Foo
27052705
end
27062706
end
27072707
end
2708+
2709+
def test_duplicated_variable
2710+
SignatureManager.new do |manager|
2711+
manager.add_file("instance.rbs", <<-EOF)
2712+
class InstanceVariable
2713+
@instance: Integer
2714+
@instance: Integer
2715+
end
2716+
2717+
class ClassInstanceVariable
2718+
self.@class_instance: Integer
2719+
self.@class_instance: Integer
2720+
end
2721+
2722+
class ClassVariable
2723+
@@class: Integer
2724+
@@class: Integer
2725+
end
2726+
EOF
2727+
2728+
manager.build do |env|
2729+
builder = DefinitionBuilder.new(env: env)
2730+
2731+
assert_raises(RBS::InstanceVariableDuplicationError) do
2732+
builder.build_instance(type_name("::InstanceVariable"))
2733+
end
2734+
assert_raises(RBS::ClassInstanceVariableDuplicationError) do
2735+
builder.build_singleton(type_name("::ClassInstanceVariable"))
2736+
end
2737+
assert_raises(RBS::ClassVariableDuplicationError) do
2738+
builder.build_instance(type_name("::ClassVariable"))
2739+
end
2740+
end
2741+
end
2742+
2743+
SignatureManager.new do |manager|
2744+
manager.add_file("inherited.rbs", <<-EOF)
2745+
class A
2746+
@instance: Integer
2747+
self.@class_instance: Integer
2748+
@@class: Integer
2749+
end
2750+
2751+
class B < A
2752+
@instance: Integer
2753+
self.@class_instance: Integer
2754+
@@class: Integer
2755+
end
2756+
EOF
2757+
2758+
manager.build do |env|
2759+
builder = DefinitionBuilder.new(env: env)
2760+
2761+
builder.build_instance(type_name("::A"))
2762+
assert_raises(RBS::ClassVariableDuplicationError) do
2763+
builder.build_instance(type_name("::B"))
2764+
end
2765+
end
2766+
end
2767+
end
27082768
end

0 commit comments

Comments
 (0)