假设我有一个功能foo/1
,其规格为-spec foo(atom()) -> #r{}.
,其中#r{}
是定义为-record(r, {a :: 1..789}).
的记录,但我有foo(a) -> 800.
在我的代码中,当我对它运行透析器时,它没有警告我这一点,(800
不是函数foo/1
的“有效”返回值),我可以让透析器警告我此?
修改
Dialyzer保留将此范围扩大为更大范围的权利。
但是我找不到如何禁用它。
答案 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”的情况下运行。但是,在您的特定情况下,您实际上需要任何额外的值来产生警告。