【问题标题】:Erlang Dialyzer: only accept certain integers?Erlang Dialyzer:只接受某些整数?
【发布时间】:2015-11-03 18:30:57
【问题描述】:

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

编辑

Learn You Some Erlang 说:

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

但我找不到如何禁用它。

【问题讨论】:

  • foo(a) 不会受到记录 r 的类型规范的影响,因为它只接受一个原子作为参数。

标签: erlang dialyzer


【解决方案1】:

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

如果您尝试?USE_UNSAFE_RANGES(请参阅代码),您的特定错误可能会被捕获,但代价是可怕的:递归整数函数的本地编译和透析永远不会完成!

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

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 选项,您应该会收到此代码的警告。默认情况下不启用此选项,因为 Dialyzer 的运行假设是“可以”过度逼近函数的返回值。但是,在您的特定情况下,您实际上需要任何额外的值来产生警告。

【讨论】:

  • 实际上不会。如果范围很小,比如1..3,然后你返回4,即使你没有指定-Woverspecs,dialyzer也会警告你,但是如果范围很大,即使你指定@,dialyzer也不会警告你987654340@.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-24
  • 1970-01-01
相关资源
最近更新 更多