Skip to content

Commit 964066e

Browse files
authored
Merge pull request #2257 from ksss/test-return-nil
[rbs/unit_test] Treat nil as a return value
2 parents d70b6ee + d59fa39 commit 964066e

File tree

13 files changed

+66
-46
lines changed

13 files changed

+66
-46
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ group :libs do
2929
gem "dbm"
3030
gem "mutex_m"
3131
gem "nkf"
32+
gem "pathname"
3233
end
3334

3435
group :profilers do

Gemfile.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ GEM
7171
parser (3.3.7.0)
7272
ast (~> 2.4.1)
7373
racc
74+
pathname (0.4.0)
7475
power_assert (2.0.5)
7576
pstore (0.1.4)
7677
psych (4.0.6)
@@ -177,6 +178,7 @@ DEPENDENCIES
177178
net-smtp
178179
nkf
179180
ostruct
181+
pathname
180182
pstore
181183
raap
182184
rake

core/gc.rbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ module GC
111111
# `:HAVE_FINALIZE`
112112
# :
113113
#
114-
def self.raw_data: () -> Array[Hash[Symbol, untyped]]
114+
def self.raw_data: () -> Array[Hash[Symbol, untyped]]?
115115

116116
# <!--
117117
# rdoc-file=gc.c

lib/rbs/test/type_check.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ def initialize(self_class:, builder:, sample_size:, unchecked_classes:, instance
2222
end
2323

2424
def overloaded_call(method, method_name, call, errors:)
25-
es = method.method_types.map do |method_type|
26-
es = method_call(method_name, method_type, call, errors: [])
25+
es = method.defs.map do |type_def|
26+
es = method_call(method_name, type_def.type, call, errors: [], annotations: type_def.annotations)
2727

2828
if es.empty?
2929
return errors
@@ -58,11 +58,11 @@ def overloaded_call(method, method_name, call, errors:)
5858
errors
5959
end
6060

61-
def method_call(method_name, method_type, call, errors:)
61+
def method_call(method_name, method_type, call, errors:, annotations: [])
6262
return errors if method_type.type.is_a?(Types::UntypedFunction)
6363

6464
args(method_name, method_type, method_type.type, call.method_call, errors, type_error: Errors::ArgumentTypeError, argument_error: Errors::ArgumentError)
65-
self.return(method_name, method_type, method_type.type, call.method_call, errors, return_error: Errors::ReturnTypeError)
65+
self.return(method_name, method_type, method_type.type, call.method_call, errors, return_error: Errors::ReturnTypeError, annotations:)
6666

6767
if method_type.block
6868
case
@@ -106,8 +106,10 @@ def args(method_name, method_type, fun, call, errors, type_error:, argument_erro
106106
end
107107
end
108108

109-
def return(method_name, method_type, fun, call, errors, return_error:)
109+
def return(method_name, method_type, fun, call, errors, return_error:, annotations: [])
110110
if call.return?
111+
return if Test.call(call.return_value, IS_AP, NilClass) && annotations.find { |a| a.string == "implicitly-returns-nil" }
112+
111113
unless value(call.return_value, fun.return_type)
112114
errors << return_error.new(klass: self_class,
113115
method_name: method_name,

lib/rbs/unit_test/spy.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class WrapSpy
2020
attr_reader :object
2121
attr_reader :method_name
2222

23+
NO_RETURN = Object.new
24+
2325
def initialize(object:, method_name:)
2426
@callback = -> (_) { }
2527
@object = object
@@ -39,7 +41,7 @@ def wrapped_object
3941
define_method(
4042
spy.method_name,
4143
_ = -> (*args, &block) do
42-
return_value = nil
44+
return_value = NO_RETURN
4345
exception = nil
4446
block_calls = [] #: Array[Test::ArgumentsReturn]
4547

@@ -105,7 +107,7 @@ def wrapped_object
105107
arguments: args,
106108
exception: exception
107109
)
108-
when return_value
110+
when ::RBS::UnitTest::Spy::WrapSpy::NO_RETURN != return_value
109111
Test::ArgumentsReturn.return(
110112
arguments: args,
111113
value: return_value

lib/rbs/unit_test/type_assertions.rb

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def send_setup(method_type, receiver, method, args, proc)
163163
end
164164
end
165165

166-
last_trace = trace.last or raise
166+
last_trace = trace.last or raise "empty trace"
167167

168168
yield(mt, last_trace, result, exception)
169169
end
@@ -182,9 +182,9 @@ def send_setup(method_type, receiver, method, args, proc)
182182

183183
assert_empty errors.map {|x| RBS::Test::Errors.to_string(x) }, "Call trace does not match with given method type: #{trace.inspect}"
184184

185-
method_types = method_types(method)
186-
all_errors = method_types.map {|t| typecheck.method_call(method, t, trace, errors: []) }
187-
assert all_errors.any? {|es| es.empty? }, "Call trace does not match one of method definitions:\n #{trace.inspect}\n #{method_types.join(" | ")}"
185+
method_defs = method_defs(method)
186+
all_errors = method_defs.map {|t| typecheck.method_call(method, t.type, trace, errors: [], annotations: t.annotations) }
187+
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
190190

@@ -219,30 +219,36 @@ def send_setup(method_type, receiver, method, args, proc)
219219
assert_operator exception, :is_a?, ::Exception
220220
assert_empty errors.map {|x| RBS::Test::Errors.to_string(x) }
221221

222-
method_types = method_types(method)
223-
all_errors = method_types.map {|t| typecheck.method_call(method, t, trace, errors: []) }
224-
assert all_errors.all? {|es| es.size > 0 }, "Call trace unexpectedly matches one of method definitions:\n #{trace.inspect}\n #{method_types.join(" | ")}"
222+
method_defs = method_defs(method)
223+
all_errors = method_defs.map {|t| typecheck.method_call(method, t.type, trace, errors: [], annotations: t.annotations) }
224+
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
227227
end
228228
end
229229

230-
def method_types(method)
230+
def method_defs(method)
231231
type, definition = target
232232

233233
case type
234234
when Types::ClassInstance
235235
subst = RBS::Substitution.build(definition.type_params, type.args)
236-
definition.methods[method].method_types.map do |method_type|
237-
method_type.sub(subst)
236+
definition.methods[method].defs.map do |type_def|
237+
type_def.update(
238+
type: type_def.type.sub(subst)
239+
)
238240
end
239241
when Types::ClassSingleton
240-
definition.methods[method].method_types
242+
definition.methods[method].defs
241243
else
242244
raise
243245
end
244246
end
245247

248+
def method_types(method)
249+
method_defs(method).map(&:type)
250+
end
251+
246252
def allows_error(*errors)
247253
yield
248254
rescue *errors => exn

sig/test/type_check.rbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ module RBS
77
#
88
# Returns an array with detected errors.
99
#
10-
def method_call: (Symbol, MethodType, CallTrace, errors: Array[Errors::t]) -> Array[Errors::t]
10+
def method_call: (Symbol, MethodType, CallTrace, errors: Array[Errors::t], ?annotations: Array[AST::Annotation]) -> Array[Errors::t]
1111

1212
# Test if given `value` is compatible to type
1313
#
1414
# Returns `true` if the value has the type.
15-
#
15+
#
1616
def value: (untyped value, Types::t) -> bool
1717
end
1818
end

sig/unit_test/spy.rbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ module RBS
55
| [T, S] (untyped object, Symbol method_name) { (WrapSpy[T], T) -> S } -> S
66

77
class WrapSpy[T]
8+
NO_RETURN: Object
9+
810
attr_accessor callback: ^(Test::CallTrace) -> void
911

1012
attr_reader object: T

sig/unit_test/type_assertions.rbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ module RBS
104104
#
105105
def class_class: () -> Class
106106

107+
def method_defs: (Symbol) -> Array[Definition::Method::TypeDef]
108+
107109
def method_types: (Symbol) -> Array[MethodType]
108110

109111
def allows_error: (*Exception) { () -> void } -> void

test/stdlib/Array_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ def test_lshift
8888
def test_aref
8989
assert_send_type "(Integer) -> Integer",
9090
[1,2,3], :[], 0
91+
assert_send_type "(Integer) -> nil",
92+
[1,2,3], :[], 1000
9193
assert_send_type "(Float) -> Integer",
9294
[1,2,3], :[], 0.1
9395
assert_send_type "(ToInt) -> Integer",
@@ -794,6 +796,8 @@ def test_shift
794796
[1,2,3], :shift
795797
assert_send_type "(ToInt) -> Array[Integer]",
796798
[1,2,3], :shift, ToInt.new(1)
799+
assert_send_type "() -> nil",
800+
[], :shift
797801
end
798802

799803
def test_shuffle

0 commit comments

Comments
 (0)