Erlang:为什么 Dialyzer 没有注意到这个错误?

Erlang: Why Dialyzer does not notice this error?

现在,我尝试使用 Dialyzer 并使用 -spec-type

我将以下代码提供给 Dialyzer,我希望 Dialyzer 注意到 "hoge(a) + 1 is invalid",但 Dialyzer 没有注意到。

-spec hoge (X) -> bad      when X :: a;
           (X) -> number() when X :: number().
hoge(X) when is_number(X) -> 1;
hoge(a) -> bad.

foo() ->
  _ = hoge(a) + 1.

但是,在另一个设置中,

-spec hoge (X) -> bad      when X :: a;
           (X) -> string() when X :: number().
hoge(X) when is_number(X) -> "1";
hoge(a) -> bad.


foo() ->
  _ = hoge(a) + 1.

Dialyzer 告诉我这个错误,

test.erl:12: The call erlang:'+'('bad' | [49,...],1) will never return since it differs in the 1st argument from the success typing arguments: (number(),number())

为什么 Dialyzer 在第一次设置时无法注意到类型错误。

-spec hoge (X) -> bad      when X :: a;
           (X) -> number() when X :: number().

这个合同(规范)不是"hoge is typed of 'a' -> 'bad' | number() -> number()"而是“'a' | number() -> 'bad' | number()”?


这是第一个示例的完整模块。

-module(example).
-export([hoge/1, foo/0]).

-spec hoge (X) -> bad      when X :: a;
           (X) -> number() when X :: number().
hoge(X) when is_number(X) -> 1;
hoge(a) -> bad.

foo() ->
  _ = hoge(a) + 1.

"why Dialyzer doesn't catch this error" 个问题的标准答案始终是 "because it is never wrong"。 Dialyzer 从不承诺找出所有错误。


在您的问题示例中,如果没有规范,Dialyzer 的类型推断算法确实会为所有参数和所有 return 值生成联合类型。使用规范,Dialyzer 仍然推断联合,但是 应该 使用规范来缩小调用的 return 值,然后产生错误。这看起来像 "reduced sensitivity" 的情况(但本身不是错误)。在任何情况下,您都可以提交错误报告。

在您的工作示例中,任何可能的值都会导致错误的结果,即使没有规范,Dialyzer 自己的类型推断也足够了。