Skip to content

Commit d2da22d

Browse files
authored
Merge pull request ruby#2301 from ruby/annotations
Fix method annotations
2 parents 7122e32 + 00306bd commit d2da22d

File tree

5 files changed

+423
-62
lines changed

5 files changed

+423
-62
lines changed

lib/rbs/definition.rb

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ def initialize(type:, member:, defined_in:, implemented_in:, overload_annotation
4242
@member = member
4343
@defined_in = defined_in
4444
@implemented_in = implemented_in
45-
@member_annotations = member.annotations
46-
@overload_annotations = overload_annotations
47-
@annotations = member.annotations + overload_annotations
45+
@member_annotations = []
46+
@overload_annotations = []
47+
@annotations = []
4848
end
4949

5050
def ==(other)
@@ -66,7 +66,10 @@ def comment
6666
end
6767

6868
def update(type: self.type, member: self.member, defined_in: self.defined_in, implemented_in: self.implemented_in)
69-
TypeDef.new(type: type, member: member, defined_in: defined_in, implemented_in: implemented_in, overload_annotations: overload_annotations)
69+
TypeDef.new(type: type, member: member, defined_in: defined_in, implemented_in: implemented_in).tap do |type_def|
70+
type_def.overload_annotations.replace(self.overload_annotations)
71+
type_def.member_annotations.replace(self.member_annotations)
72+
end
7073
end
7174

7275
def overload?
@@ -77,20 +80,33 @@ def overload?
7780
false
7881
end
7982
end
83+
84+
def each_annotation(&block)
85+
if block
86+
member_annotations.each(&block)
87+
overload_annotations.each(&block)
88+
else
89+
enum_for :each_annotation
90+
end
91+
end
8092
end
8193

8294
attr_reader :super_method
8395
attr_reader :defs
8496
attr_reader :accessibility
8597
attr_reader :extra_annotations
98+
attr_reader :annotations
8699
attr_reader :alias_of
100+
attr_reader :alias_member
87101

88-
def initialize(super_method:, defs:, accessibility:, annotations: [], alias_of:)
102+
def initialize(super_method:, defs:, accessibility:, annotations: [], alias_of:, alias_member: nil)
89103
@super_method = super_method
90104
@defs = defs
91105
@accessibility = accessibility
92106
@extra_annotations = []
107+
@annotations = []
93108
@alias_of = alias_of
109+
@alias_member = alias_member
94110
end
95111

96112
def ==(other)
@@ -99,7 +115,8 @@ def ==(other)
99115
other.defs == defs &&
100116
other.accessibility == accessibility &&
101117
other.annotations == annotations &&
102-
other.alias_of == alias_of
118+
other.alias_of == alias_of &&
119+
other.alias_member == alias_member
103120
end
104121

105122
alias eql? ==
@@ -130,10 +147,6 @@ def comments
130147
@comments ||= defs.map(&:comment).compact.uniq
131148
end
132149

133-
def annotations
134-
@annotations ||= defs.flat_map {|d| d.member_annotations }
135-
end
136-
137150
def members
138151
@members ||= defs.map(&:member).uniq
139152
end
@@ -149,49 +162,42 @@ def private?
149162
def sub(s)
150163
return self if s.empty?
151164

152-
self.class.new(
165+
update(
153166
super_method: super_method&.sub(s),
154-
defs: defs.map {|defn| defn.update(type: defn.type.sub(s)) },
155-
accessibility: @accessibility,
156-
alias_of: alias_of
167+
defs: defs.map {|defn| defn.update(type: defn.type.sub(s)) }
157168
)
158169
end
159170

160171
def map_type(&block)
161-
self.class.new(
172+
update(
162173
super_method: super_method&.map_type(&block),
163-
defs: defs.map {|defn| defn.update(type: defn.type.map_type(&block)) },
164-
accessibility: @accessibility,
165-
alias_of: alias_of
174+
defs: defs.map {|defn| defn.update(type: defn.type.map_type(&block)) }
166175
)
167176
end
168177

169178
def map_type_bound(&block)
170-
self.class.new(
179+
update(
171180
super_method: super_method&.map_type_bound(&block),
172-
defs: defs.map {|defn| defn.update(type: defn.type.map_type_bound(&block)) },
173-
accessibility: @accessibility,
174-
alias_of: alias_of
181+
defs: defs.map {|defn| defn.update(type: defn.type.map_type_bound(&block)) }
175182
)
176183
end
177184

178185
def map_method_type(&block)
179-
self.class.new(
180-
super_method: super_method,
186+
update(
181187
defs: defs.map {|defn| defn.update(type: yield(defn.type)) },
182-
accessibility: @accessibility,
183-
alias_of: alias_of
184188
)
185189
end
186190

187-
def update(super_method: self.super_method, defs: self.defs, accessibility: self.accessibility, alias_of: self.alias_of, annotations: self.annotations)
191+
def update(super_method: self.super_method, defs: self.defs, accessibility: self.accessibility, alias_of: self.alias_of, annotations: self.annotations, alias_member: self.alias_member)
188192
self.class.new(
189193
super_method: super_method,
190194
defs: defs,
191195
accessibility: accessibility,
192196
alias_of: alias_of,
193-
annotations: annotations
194-
)
197+
alias_member: alias_member
198+
).tap do |method|
199+
method.annotations.replace(annotations)
200+
end
195201
end
196202
end
197203

lib/rbs/definition_builder.rb

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -389,12 +389,14 @@ def build_singleton(type_name)
389389
type: method_type,
390390
member: initialize_def.member,
391391
defined_in: initialize_def.defined_in,
392-
implemented_in: initialize_def.implemented_in,
393-
overload_annotations: initialize_def.overload_annotations
394-
)
392+
implemented_in: initialize_def.implemented_in
393+
).tap do |type_def|
394+
type_def.overload_annotations.replace(initialize_def.overload_annotations)
395+
end
395396
end,
396397
accessibility: :public,
397-
alias_of: nil
398+
alias_of: nil,
399+
alias_member: nil
398400
)
399401

400402
definition.methods[:new] = typed_new
@@ -663,8 +665,11 @@ def define_method(methods, definition, method, subst, self_type_methods, defined
663665
defn.update(defined_in: defined_in, implemented_in: implemented_in)
664666
end,
665667
accessibility: original_method.accessibility,
666-
alias_of: original_method
668+
alias_of: original_method,
669+
alias_member: original
667670
)
671+
672+
method_definition.annotations.replace(original.annotations)
668673
when AST::Members::MethodDefinition
669674
if duplicated_method = methods[method.name]
670675
raise DuplicatedMethodDefinitionError.new(
@@ -679,9 +684,11 @@ def define_method(methods, definition, method, subst, self_type_methods, defined
679684
type: subst.empty? ? overload.method_type : overload.method_type.sub(subst),
680685
member: original,
681686
defined_in: defined_in,
682-
implemented_in: implemented_in,
683-
overload_annotations: overload.annotations
684-
)
687+
implemented_in: implemented_in
688+
).tap do |type_def|
689+
# Keep the original annotations given to overloads.
690+
type_def.overload_annotations.replace(overload.annotations)
691+
end
685692
end
686693

687694
# @type var accessibility: RBS::Definition::accessibility
@@ -701,8 +708,11 @@ def define_method(methods, definition, method, subst, self_type_methods, defined
701708
super_method: super_method,
702709
defs: defs,
703710
accessibility: accessibility,
704-
alias_of: nil
711+
alias_of: nil,
712+
alias_member: nil
705713
)
714+
715+
method_definition.annotations.replace(original.annotations)
706716
when AST::Members::AttrReader, AST::Members::AttrWriter, AST::Members::AttrAccessor
707717
if duplicated_method = methods[method.name]
708718
raise DuplicatedMethodDefinitionError.new(
@@ -751,8 +761,11 @@ def define_method(methods, definition, method, subst, self_type_methods, defined
751761
)
752762
],
753763
accessibility: method.accessibility,
754-
alias_of: nil
764+
alias_of: nil,
765+
alias_member: nil
755766
)
767+
768+
method_definition.annotations.replace(original.annotations)
756769
when nil
757770
# Overloading method definition only
758771

@@ -779,8 +792,11 @@ def define_method(methods, definition, method, subst, self_type_methods, defined
779792
defn.update(implemented_in: implemented_in)
780793
end,
781794
accessibility: existing_method.accessibility,
782-
alias_of: existing_method.alias_of
795+
alias_of: existing_method.alias_of,
796+
alias_member: nil
783797
)
798+
799+
method_definition.annotations.replace(existing_method.annotations)
784800
end
785801

786802
method.overloads.each do |overloading_def|
@@ -789,12 +805,19 @@ def define_method(methods, definition, method, subst, self_type_methods, defined
789805
type: subst.empty? ? overload.method_type : overload.method_type.sub(subst),
790806
member: overloading_def,
791807
defined_in: defined_in,
792-
implemented_in: implemented_in,
793-
overload_annotations: overload.annotations
808+
implemented_in: implemented_in
794809
)
795810

811+
type_def.overload_annotations.replace(overload.annotations)
812+
796813
method_definition.defs.unshift(type_def)
797814
end
815+
816+
method_definition.annotations.concat(overloading_def.annotations)
817+
end
818+
819+
method_definition.defs.each do |type_def|
820+
type_def.member_annotations.replace(method_definition.annotations)
798821
end
799822

800823
methods[method.name] = method_definition

lib/rbs/unit_test/type_assertions.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def send_setup(method_type, receiver, method, args, proc)
183183
assert_empty errors.map {|x| RBS::Test::Errors.to_string(x) }, "Call trace does not match with given method type: #{trace.inspect}"
184184

185185
method_defs = method_defs(method)
186-
all_errors = method_defs.map {|t| typecheck.method_call(method, t.type, trace, errors: [], annotations: t.annotations) }
186+
all_errors = method_defs.map {|t| typecheck.method_call(method, t.type, trace, errors: [], annotations: t.each_annotation.to_a) }
187187
assert all_errors.any? {|es| es.empty? }, "Call trace does not match one of method definitions:\n #{trace.inspect}\n #{method_defs.map(&:type).join(" | ")}"
188188

189189
raise exception if exception
@@ -220,7 +220,7 @@ def send_setup(method_type, receiver, method, args, proc)
220220
assert_empty errors.map {|x| RBS::Test::Errors.to_string(x) }
221221

222222
method_defs = method_defs(method)
223-
all_errors = method_defs.map {|t| typecheck.method_call(method, t.type, trace, errors: [], annotations: t.annotations) }
223+
all_errors = method_defs.map {|t| typecheck.method_call(method, t.type, trace, errors: [], annotations: t.each_annotation.to_a) }
224224
assert all_errors.all? {|es| es.size > 0 }, "Call trace unexpectedly matches one of method definitions:\n #{trace.inspect}\n #{method_defs.map(&:type).join(" | ")}"
225225

226226
result

sig/definition.rbs

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,50 @@ module RBS
2828
attr_reader defined_in: TypeName
2929
attr_reader implemented_in: TypeName?
3030

31-
# Annotations given to `#member`
31+
# Annotations given to the method definition syntax
32+
#
33+
# If the method have multiple syntaxes, union of the annotations to the member will be included, without dedup.
34+
#
35+
# The value should be updated during setup.
36+
#
3237
attr_reader member_annotations: Array[AST::Annotation]
3338

3439
# Annotations given to the overload associated to the method type
40+
#
41+
# The value should be updated during setup.
42+
#
3543
attr_reader overload_annotations: Array[AST::Annotation]
3644

37-
# Concatenation of `member_annotations` and `overload_annotations`
38-
attr_reader annotations: Array[AST::Annotation]
39-
40-
def initialize: (type: MethodType, member: method_member, defined_in: TypeName, implemented_in: TypeName?, ?overload_annotations: Array[AST::Annotation]) -> void
45+
# Always returns an empty array
46+
%a{deprecated} attr_reader annotations: Array[AST::Annotation]
47+
48+
# `overload_annotations` is ignored.
49+
def initialize: (
50+
type: MethodType,
51+
member: method_member,
52+
defined_in: TypeName,
53+
implemented_in: TypeName?
54+
) -> void
55+
| %a{deprecated} (
56+
type: MethodType,
57+
member: method_member,
58+
defined_in: TypeName,
59+
implemented_in: TypeName?,
60+
overload_annotations: nil
61+
) -> void
4162

4263
def comment: () -> AST::Comment?
4364

4465
def update: (?type: MethodType, ?member: method_member, ?defined_in: TypeName, ?implemented_in: TypeName?) -> TypeDef
4566

4667
def overload?: () -> bool
68+
69+
# Yields member and overload annotations, without dedup
70+
#
71+
# Member annotation yields first.
72+
#
73+
def each_annotation: () { (AST::Annotation) -> void } -> void
74+
| () -> Enumerator[AST::Annotation]
4775
end
4876

4977
attr_reader super_method: Method?
@@ -56,21 +84,38 @@ module RBS
5684
attr_reader comments: Array[AST::Comment]
5785

5886
attr_reader members: Array[method_member]
87+
88+
# The original method when the method is defined with `alias` syntax
5989
attr_reader alias_of: Method?
6090

91+
# Present if the method is defined with `alias` syntax
92+
attr_reader alias_member: AST::Members::Alias?
93+
6194
# Unused, always returns empty array
62-
attr_reader extra_annotations: Array[AST::Annotation]
95+
%a{deprecated} attr_reader extra_annotations: Array[AST::Annotation]
6396

64-
# Union of annotations given to `defs`, not contains annotations given to each overload
97+
# Union of annotations given to `def`s and `alias`, not contains annotations given to each overload
98+
#
99+
# The elements will be updated during `Method` object setup.
100+
#
65101
attr_reader annotations: Array[AST::Annotation]
66102

67103
# Note that the annotations given through `annotations:` keyword is ignored.
68104
#
69-
def initialize: (super_method: Method?,
70-
defs: Array[TypeDef],
71-
accessibility: accessibility,
72-
alias_of: Method?,
73-
?annotations: Array[AST::Annotation]) -> void
105+
def initialize: (
106+
super_method: Method?,
107+
defs: Array[TypeDef],
108+
accessibility: accessibility,
109+
alias_of: Method?,
110+
alias_member: AST::Members::Alias?
111+
) -> void
112+
| %a{deprecated} (
113+
super_method: Method?,
114+
defs: Array[TypeDef],
115+
accessibility: accessibility,
116+
alias_of: Method?,
117+
annotations: Array[AST::Annotation]
118+
) -> void
74119

75120
def public?: () -> bool
76121

@@ -97,7 +142,8 @@ module RBS
97142
?defs: Array[TypeDef],
98143
?accessibility: accessibility,
99144
?alias_of: Method?,
100-
?annotations: Array[AST::Annotation]
145+
?annotations: Array[AST::Annotation],
146+
?alias_member: AST::Members::Alias?
101147
) -> Method
102148
end
103149

0 commit comments

Comments
 (0)