Erlang Dialyzer:只接受某些整数?

时间:2015-06-09 10:12:27

标签: erlang dialyzer

假设我有一个功能foo/1,其规格为-spec foo(atom()) -> #r{}.,其中#r{}是定义为-record(r, {a :: 1..789}).的记录,但我有foo(a) -> 800.在我的代码中,当我对它运行透析器时,它没有警告我这一点,(800不是函数foo/1的“有效”返回值),我可以让透析器警告我此?

修改

Learn You Some Erlang说:

  

Dialyzer保留将此范围扩大为更大范围的权利。

但是我找不到如何禁用它。

1 个答案:

答案 0 :(得分:0)

从Erlang 18开始,整数范围的处理由erl_types:t_from_range/2完成。正如你所能see一样,为了获得一个范围的“安全”过度激活,会发生很多概括。

如果您尝试?USE_UNSAFE_RANGES(请参阅代码),可能会捕获您的特定错误,但成本很高:本机编译和递归整数函数的透析将无法完成!

原因是递归函数的类型分析使用简单的fixpoint方法,其中初始类型接受基本情况,并使用递归情况重复扩展以包含更多值。在某些时候,如果要终止该过程,必须进行过多的过程。这是一个具体的例子:

fact(1) -> 1;
fact(N) -> N * fact(N - 1).

最初假定fact/1具有fun(none()) -> none()类型。使用它来分析代码,第二个子句是'失败',只有第一个是好的。因此,在第一次迭代后,新类型为fun(1) -> 1。使用新类型,第二个子句可以成功,将类型扩展为fun(1|2) -> 1|2。然后fun(1|2|3) -> 1|2|6继续?SET_LIMIT,直到达到t_from_range,在这种情况下fun(1..255) -> pos_integer()停止使用各个值,类型变为1..255。下一次迭代会将pos_integer()扩展为fun(pos_integer()) -> pos_integer(),然后-Woverspecs就是一个固定点!

接下来的答案不正确(解释下面的第一条评论):

如果使用{{1}}选项,您应该收到此代码的警告。默认情况下不启用此选项,因为Dialyzer在假设过度逼近函数的返回值“ok”的情况下运行。但是,在您的特定情况下,您实际上需要任何额外的值来产生警告。