Minimizing the example quite a bit, I have these two versions:
The first that Dialyzer can call:
-module(zoo).
-export([main/0]).
-type red_panda_food() :: bamboo.
-type squid_food() :: sperm_whale.
-spec feed_squid(fun(() -> squid_food())) -> squid_food().
feed_squid(Generator) -> Generator().
main() ->
%% The zoo buys a feeder for both the red panda and squid
FeederRP = fun() -> bamboo end,
FeederSquid = fun() -> sperm_whale end,
%% CRITICAL POINT %%
%% This should not be right!
feed_squid(FeederRP),
%% Time to feed them!
feed_squid(FeederSquid)
Then one that has no warnings:
[...]
%% CRITICAL POINT %%
%% Time to feed them!
feed_squid(FeederSquid)
%% This should not be right!
feed_squid(FeederRP).
The dialog box warnings for the version that it can catch are as follows:
zoo.erl:7: The contract zoo:feed_squid(fun(() -> squid_food())) -> squid_food() cannot be right because the inferred return for feed_squid(FeederRP::fun(() -> 'bamboo')) on line 15 is 'bamboo'
zoo.erl:10: Function main/0 has no local return
... , .
, , Dialyzer , feed_squid/1 fun() -> bamboo fun() -> none() (, , , feed_squid/1, ). , , Dialyzer , .
Dialyzer , -Woverspecs:
zoo.erl:7: Type specification zoo:feed_squid(fun(() -> squid_food())) -> squid_food() is a subtype of the success typing: zoo:feed_squid(fun(() -> 'bamboo' | 'sperm_whale')) -> 'bamboo' | 'sperm_whale'
... , ! /, , , , Dialyzer . , , , Dialyzer ( ).
: !
, , , . feed_squid/1 (fun() -> any()) -> any(). feed_squid/1 FeederRP , , bamboo, main/0. feed_squid/1 FeederSquid sperm_whale, FeederSquid, FeederRP sperm_whale OR bamboo. FeederRP, - sperm_whale OR bamboo. spec, promises, sperm_whale, Dialyzer . , fun() -> bamboo | sperm_whale , fun() -> bamboo, fun() -> bamboo. spec (fun() -> sperm_whale), Dialyzer , fun() -> none(). feed_squid/1 (, Dialyzer ), , sperm_whale, !
"" , , , , , "" fun(...) -> none().