Reintroduce nil type check for stub value cast

This commit is contained in:
Michael Miller 2022-04-30 12:10:02 -06:00
parent 9817b2948e
commit 739629ef9d
No known key found for this signature in database
GPG Key ID: 32B47AE8F388A1FF
1 changed files with 11 additions and 6 deletions

View File

@ -130,7 +130,7 @@ module Spectator
if %stub = _spectator_find_stub(%call) if %stub = _spectator_find_stub(%call)
# Cast the stub or return value to the expected type. # Cast the stub or return value to the expected type.
# This is necessary to match the expected return type of the original method. # This is necessary to match the expected return type of the original method.
_spectator_cast_stub_value(%stub, %call, typeof({{original}})) _spectator_cast_stub_value(%stub, %call, typeof({{original}}), {{method.return_type && method.return_type.resolve < Nil || false}})
else else
# Delegate missing stub behavior to concrete type. # Delegate missing stub behavior to concrete type.
_spectator_stub_fallback(%call, typeof({{original}})) do _spectator_stub_fallback(%call, typeof({{original}})) do
@ -221,7 +221,7 @@ module Spectator
# This is necessary to match the expected return type of the original method. # This is necessary to match the expected return type of the original method.
{% if method.return_type %} {% if method.return_type %}
# Return type restriction takes priority since it can be a superset of the original implementation. # Return type restriction takes priority since it can be a superset of the original implementation.
_spectator_cast_stub_value(%stub, %call, {{method.return_type}}) _spectator_cast_stub_value(%stub, %call, {{method.return_type}}, {{method.return_type.resolve < Nil}})
{% elsif !method.abstract? %} {% elsif !method.abstract? %}
# The method isn't abstract, infer the type it returns without calling it. # The method isn't abstract, infer the type it returns without calling it.
_spectator_cast_stub_value(%stub, %call, typeof({{original}})) _spectator_cast_stub_value(%stub, %call, typeof({{original}}))
@ -328,7 +328,8 @@ module Spectator
# *stub* is the variable holding the stub. # *stub* is the variable holding the stub.
# *call* is the variable holding the captured method call. # *call* is the variable holding the captured method call.
# *type* is the expected type to cast the value to. # *type* is the expected type to cast the value to.
private macro _spectator_cast_stub_value(stub, call, type) # *nullable* indicates whether *type* can be nil or not.
private macro _spectator_cast_stub_value(stub, call, type, nullable = true)
# Attempt to cast the stub to the method's return type. # Attempt to cast the stub to the method's return type.
# If successful, return the value of the stub. # If successful, return the value of the stub.
# This is a common usage where the return type is simple and matches the stub type exactly. # This is a common usage where the return type is simple and matches the stub type exactly.
@ -348,9 +349,12 @@ module Spectator
# Attempt to cast the value to the method's return type. # Attempt to cast the value to the method's return type.
# If successful, which it will be in most cases, return it. # If successful, which it will be in most cases, return it.
# The caller will receive a properly typed value without unions or other side-effects. # The caller will receive a properly typed value without unions or other side-effects.
begin if %cast = %value.as?({{type}})
%value.as({{type}}) %cast
rescue TypeCastError else
{% if nullable %}
nil
{% else %}
# The stubbed value was something else entirely and cannot be cast to the return type. # The stubbed value was something else entirely and cannot be cast to the return type.
# There's something weird going on (compiler bug?) that sometimes causes this class lookup to fail. # There's something weird going on (compiler bug?) that sometimes causes this class lookup to fail.
%type = begin %type = begin
@ -359,6 +363,7 @@ module Spectator
"<Unknown>" "<Unknown>"
end end
raise TypeCastError.new("#{_spectator_stubbed_name} received message #{ {{call}} } and is attempting to return a `#{%type}`, but returned type must be `#{ {{type}} }`.") raise TypeCastError.new("#{_spectator_stubbed_name} received message #{ {{call}} } and is attempting to return a `#{%type}`, but returned type must be `#{ {{type}} }`.")
{% end %}
end end
end end
end end