Method return type restriction takes precedence over original return type

Raise TypeCastError on ambiguous stub values.
This commit is contained in:
Michael Miller 2022-03-24 02:01:25 -06:00
parent 5aceaf7d8c
commit b97a367be7
No known key found for this signature in database
GPG key ID: AC78B32D30CE34A2

View file

@ -152,29 +152,30 @@ 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.
{% if !method.abstract? %} {% if method.return_type %}
# The method isn't abstract, so we can reference the type it returns without calling it. # Return type restriction takes priority since it can be a superset of the original implementation.
_spectator_cast_stub_value(%stub, %call, typeof({{original}}), {{method.return_type && method.return_type.resolve >= Nil || false}})
{% elsif method.return_type %}
_spectator_cast_stub_value(%stub, %call, {{method.return_type}}, {{method.return_type.resolve >= Nil}}) _spectator_cast_stub_value(%stub, %call, {{method.return_type}}, {{method.return_type.resolve >= Nil}})
{% elsif !method.abstract? %}
# The method isn't abstract, infer the type it returns without calling it.
_spectator_cast_stub_value(%stub, %call, typeof({{original}}), {{method.return_type && method.return_type.resolve >= Nil || false}})
{% else %} {% else %}
# Stubbed method is abstract and there's no return type annotation. # Stubbed method is abstract and there's no return type annotation.
# Return the value of the stub as-is. # The value of the stub could be returned as-is.
# This may produce a "bloated" union of all known stub types. # This may produce a "bloated" union of all known stub types,
%stub.value # and generally causes more annoying problems.
raise TypeCastError.new("#{_spectator_stubbed_name} received message #{%call} but cannot resolve the return type.")
{% end %} {% end %}
else else
# A stub wasn't found, invoke the type-specific fallback logic. # A stub wasn't found, invoke the type-specific fallback logic.
{% if !method.abstract? %} {% if method.return_type && method.abstract? %}
# Pass along the type of the original method and a block to invoke it.
_spectator_stub_fallback(%call, typeof({{original}})) { {{original}} }
{% elsif method.return_type %}
# Stubbed method is abstract, so it can't be called.
# Pass along just the return type annotation. # Pass along just the return type annotation.
_spectator_abstract_stub_fallback(%call, {{method.return_type}}) _spectator_abstract_stub_fallback(%call, {{method.return_type}})
{% else %} {% elsif method.abstract? %}
# Stubbed method is abstract and there's no type annotation. # Stubbed method is abstract and there's no type annotation.
_spectator_abstract_stub_fallback(%call) _spectator_abstract_stub_fallback(%call)
{% else %}
# Pass along the type of the original method and a block to invoke it.
_spectator_stub_fallback(%call, typeof({{original}})) { {{original}} }
{% end %} {% end %}
end end
end end
@ -241,9 +242,10 @@ module Spectator
_spectator_cast_stub_value(%stub, %call, {{method.return_type}}, {{method.return_type.resolve >= Nil}}) _spectator_cast_stub_value(%stub, %call, {{method.return_type}}, {{method.return_type.resolve >= Nil}})
{% else %} {% else %}
# Stubbed method is abstract and there's no return type annotation. # Stubbed method is abstract and there's no return type annotation.
# Return the value of the stub as-is. # The value of the stub could be returned as-is.
# This may produce a "bloated" union of all known stub types. # This may produce a "bloated" union of all known stub types,
raise "oof" # and generally causes more annoying problems.
raise TypeCastError.new("#{_spectator_stubbed_name} received message #{%call} but cannot resolve the return type.")
{% end %} {% end %}
else else
# A stub wasn't found, invoke the type-specific fallback logic. # A stub wasn't found, invoke the type-specific fallback logic.