为什么Dialyzer没有发现这个简单的错误?

时间:2016-04-15 10:44:38

标签: erlang dialyzer

Dialyzer不会发出此函数返回类型不一致的信号

-spec myfun(integer()) -> zero | one.
myfun(0) -> zero;
myfun(1) -> one;
myfun(2) -> other_number.

但它检测到最后一行是

的情况
myfun(_) -> other_number.

为什么会这样? 上面应该是一个非常简单的案例,我相信......

由于

1 个答案:

答案 0 :(得分:4)

对于“为什么透析器没有......”这类问题的简单回答是“因为它的设计总是正确的”或“因为它永远不会承诺它会捕获所有或任何特定的东西”。

对于更复杂的答案,您需要进一步指定您的问题。如果我在模块中编写示例:

-module(bar).

-export([myfun1/1, myfun2/1]).

-spec myfun1(integer()) -> zero | one.

myfun1(0) -> zero;
myfun1(1) -> one;
myfun1(2) -> other_number.

-spec myfun2(integer()) -> zero | one.

myfun2(0) -> zero;
myfun2(1) -> one;
myfun2(_) -> other_number.

透析它:

$ dialyzer bar.erl 
  Checking whether the PLT /home/stavros/.dialyzer_plt is up-to-date... yes
  Proceeding with analysis... done in 0m0.64s
done (passed successfully)

......两者之间都没有“检测到”差异,导致两者都不是“错误”。事实上,代码在某种程度上更通用(可以返回额外的值),并且在某些方面更具限制性(不能处理每个整数,对于版本1)而不是规范。

可以使用-Woverspecs找到第二个版本的问题:

$ dialyzer -Woverspecs bar.erl 
  Checking whether the PLT /home/stavros/.dialyzer_plt is up-to-date... yes
  Proceeding with analysis...
bar.erl:11: Type specification bar:myfun2(integer()) -> 'zero' | 'one' is a subtype of the success typing: bar:myfun2(_) -> 'one' | 'other_number' | 'zero'
 done in 0m0.58s
done (warnings were emitted)

警告准确地解释了规范比代码更具限制性。

极不寻常的-Wspecdiffs

也可以检测到这两个问题
$ dialyzer -Wspecdiffs bar.erl 
  Checking whether the PLT /home/stavros/.dialyzer_plt is up-to-date... yes
  Proceeding with analysis...
bar.erl:5: Type specification bar:myfun1(integer()) -> 'zero' | 'one' is not equal to the success typing: bar:myfun1(0 | 1 | 2) -> 'one' | 'other_number' | 'zero'
bar.erl:11: Type specification bar:myfun2(integer()) -> 'zero' | 'one' is a subtype of the success typing: bar:myfun2(_) -> 'one' | 'other_number' | 'zero'
 done in 0m0.61s
done (warnings were emitted)

鼓励-Woverspecs-Wspecdiffs操作模式,因为透析器的类型分析可以并且将概括类型,因此“以更严格的方式指定的东西”可以是泛化的结果。 / p>

也可能是你打算只用0和1作为参数调用这些函数,在这种情况下规范是'ok'。