4

我希望添加规范永远不会降低安全性,但这正是在以下情况下发生的情况。

在下面的代码中,Dialyzer(错误地)相信我 bar 的返回类型是1. 这导致它说 foo() 中的模式永远无法匹配——不正确的建议,如果注意,会引入运行时错误!

-module(sample).
-export([foo/0]).

foo() ->
    case bar() of
        1 -> ok;
        2 -> something
    end.

 -spec bar() -> 1.
bar() ->
  rand:uniform(2).

删除规范以bar/0解决问题——但为什么 Dialyzer 信任我?Dialyzer 在这里违反了它的“无误报”承诺:它在没有错误时发出警告。并且(更糟糕的是)Dialyzer 推动引入了一个新错误。

4

2 回答 2

6

Dialyzer 在检查其规范之前计算每个函数的成功键入,此操作有几种可能的结果:

  1. 规范类型与成功类型不匹配:无效类型规范警告
  2. 规范类型是成功类型的严格超类型:Warning only with -Wunderspecsor-Wspecdiffs
  3. 规范类型是成功类型的严格子类型:仅使用-Woverspecsor警告-Wspecdiffs
  4. 规范类型和成功类型完全匹配:一切都很好
  5. 规范类型和成功类型重叠但不完全匹配(如-1..1pos_integer()):与 2 相同。

对于 1,它继续使用成功类型,否则继续使用成功类型和规范类型之间的交集。

你的情况是 3,这通常不会被警告,因为作为程序员,你知道得更好(就透析器而言,也许rand:uniform(2)只能 return 1)。你可以激活它

{dialyzer, [{warnings, [underspecs,overspecs]}]}.

rebar.config文件中

于 2020-12-16T22:05:56.707 回答
5

Dialyzer 自己的分析(当前)基于多种过度近似,因此它无法辨别您更严格的规范是由于您绝对错误还是由于 Dialyzer 在某处过度近似。

因此,它选择信任您的规范,并在以后根据该信息报告确定的错误。

通常,其他现代系统提供的与类型错误相关的信息都带有“报告的所有部分并且没有明确指定的责任”,因此。这里实际上是推理、规范和模式不兼容的情况,但 Dialyzer 只归咎于模式。这是使用它时要记住的一个怪癖。

于 2020-12-17T09:49:45.417 回答