Better handling of casting with covariance and contravariance

This commit is contained in:
Michael Miller 2019-11-03 13:04:44 -07:00
parent 2a484d5816
commit 59884f253f
6 changed files with 24 additions and 18 deletions

View file

@ -41,11 +41,7 @@ module Spectator::Mocks
%call = ::Spectator::Mocks::GenericMethodCall.new({{name.symbolize}}, %args) %call = ::Spectator::Mocks::GenericMethodCall.new({{name.symbolize}}, %args)
@spectator_stub_calls << %call @spectator_stub_calls << %call
if (%stub = @spectator_stubs.find(&.callable?(%call))) if (%stub = @spectator_stubs.find(&.callable?(%call)))
if (%cast = %stub.as?(::Spectator::Mocks::GenericMethodStub(typeof(%method({{args.splat}}))))) %stub.call(%args, typeof(%method({{args.splat}})))
%cast.call(%args)
else
raise "The return type of stub #{%stub} doesn't match the expected type #{typeof(%method({{args.splat}}))}"
end
else else
%method({{args.splat}}) %method({{args.splat}})
end end
@ -56,11 +52,7 @@ module Spectator::Mocks
%call = ::Spectator::Mocks::GenericMethodCall.new({{name.symbolize}}, %args) %call = ::Spectator::Mocks::GenericMethodCall.new({{name.symbolize}}, %args)
@spectator_stub_calls << %call @spectator_stub_calls << %call
if (%stub = @spectator_stubs.find(&.callable?(%call))) if (%stub = @spectator_stubs.find(&.callable?(%call)))
if (%cast = %stub.as?(::Spectator::Mocks::GenericMethodStub(typeof(%method({{args.splat}}) { |*%yield_args| yield *%yield_args })))) %stub.call(%args, typeof(%method({{args.splat}}) { |*%ya| yield *%ya }))
%cast.call(%args)
else
raise "The return type of stub #{%stub} doesn't match the expected type #{typeof(%method({{args.splat}}) { |*%ya| yield *%ya })}"
end
else else
%method({{args.splat}}) do |*%yield_args| %method({{args.splat}}) do |*%yield_args|
yield *%yield_args yield *%yield_args

View file

@ -13,8 +13,6 @@ module Spectator::Mocks
super && (!@args || @args === call.args) super && (!@args || @args === call.args)
end end
abstract def call(args : GenericArguments(T, NT)) : ReturnType forall T, NT
def to_s(io) def to_s(io)
super(io) super(io)
if @args if @args

View file

@ -10,6 +10,8 @@ module Spectator::Mocks
@name == call.name @name == call.name
end end
abstract def call(args : GenericArguments(T, NT), rt : RT.class) forall T, NT, RT
def to_s(io) def to_s(io)
io << '#' io << '#'
io << @name io << @name

View file

@ -4,8 +4,12 @@ require "./value_method_stub"
module Spectator::Mocks module Spectator::Mocks
class NilMethodStub < GenericMethodStub(Nil) class NilMethodStub < GenericMethodStub(Nil)
def call(_args : GenericArguments(T, NT)) : Nil forall T, NT def call(_args : GenericArguments(T, NT), rt : RT.class) forall T, NT, RT
nil if (cast = nil.as?(RT))
cast
else
raise "The return type of stub #{to_s} : Nil doesn't match the expected type #{RT}"
end
end end
def and_return(value : T) forall T def and_return(value : T) forall T

View file

@ -7,8 +7,13 @@ module Spectator::Mocks
super(name, source, args) super(name, source, args)
end end
def call(_args : GenericArguments(T, NT)) : ReturnType forall T, NT def call(_args : GenericArguments(T, NT), rt : RT.class) forall T, NT, RT
@proc.call result = @proc.call
if (cast = result.as?(RT))
cast
else
raise "The return type of stub #{to_s} : #{ReturnType} doesn't match the expected type #{RT}"
end
end end
end end
end end

View file

@ -7,8 +7,13 @@ module Spectator::Mocks
super(name, source, args) super(name, source, args)
end end
def call(_args : GenericArguments(T, NT)) : ReturnType forall T, NT def call(_args : GenericArguments(T, NT), rt : RT.class) forall T, NT, RT
@value result = @value
if (cast = result.as?(RT))
cast
else
raise "The return type of stub #{to_s} : #{ReturnType} doesn't match the expected type #{RT}"
end
end end
end end
end end