如何在一个匹配所有`else`的`with`语句中避免来自Dialyzer的“永不匹配”错误?

时间:2018-04-04 21:45:36

标签: elixir typechecking dialyzer

我有以下代码:

@spec test_pass(String.t) :: (:failed | {:ok, map()})
def test_pass(pass) do
  db_user = %{password_hash: @hash_for_foo}
  with {:ok, ^db_user} <- Comeonin.Argon2.check_pass(db_user, pass) do
    {:ok, db_user}
  else
    _ -> :failed
  end

Dyalizer正在给我“永远不能匹配的错误”:

⟨my_file⟩.ex:25: The pattern {'ok', _} can never match the type {'error',<<_:64,_:_*8>>}

我的问题是,为什么?我知道它无法匹配,我实际上并不在意,这就是我首先使用with的原因。所有不匹配的案例都在else

中处理

如何更改dialyzer会满足的代码?

正在寻找@dialyzer {:nowarn_function, …}。我已经在{:error, _} -> …机构中使用else表达式尝试了它,但没有用。

Erlang / Elixir版本(elixir -v):

Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false]

Elixir 1.6.1 (compiled with OTP 19)

Argon.check_pass/2 is external, from Comeonein

我检查了comeonin,并在其上运行了mix dialixier,并报告了多个no local return错误。

2 个答案:

答案 0 :(得分:4)

Dialyzer非常不友好。然而,如果它报告错误,则意味着基于各种类型规范,您已经注释了您的功能,因此它看起来与您的实际使用相矛盾。

当Dialyzer抱怨{'error',<<_:64,_:_*8>>}时,这意味着Argon2.check_pass对它有一些相互矛盾的类型规范,要么本身,要么可能是更深层次的东西。 Dialyzer不能非常友好地指出你究竟发生矛盾的地点和原因。

由于我无法完全访问您的代码,为了解决问题,我最多可以指出您执行以下几个步骤:

  1. 如果Argon2.check_pass有明确的@spec注释,那么请将其评论出去,看看Dialyzer是否还会抱怨。

  2. 如果投诉已经消失,请使用@spec修改any注释的各个部分,直到问题消失为止进行识别。因此,问题将在那里得到解决,或者您需要深入研究Argon2.check_pass可能导致问题的其他功能。

  3. 如果1.失败,则复制粘贴定义Argon2.check_pass的函数作为私有函数:tmp_check_pass,看看它是如何改变问题的。

  4. 4.如果需要,您可能需要引入更多tmp_... Argon2.check_pass所依赖的@spec函数,以便找出投诉的根本原因。在此之前,首先尝试评论Argon2.check_pass利用的任何支持函数的所有{'error',<<_:64,_:_*8>>}注释,并相应地应用第1点。

    最终,您将到达代码中的特定位置,根据您向Dialyzer提供的规范,您的代码的某些用法违反了以下类型:{{1}}类型

    这里的关键思考是试图找出投诉的根本原因,而Dialyzer遗憾地指出不时太精确了。

答案 1 :(得分:0)

正如另一个问题"Dialyzer is usually never wrong", but I can't figure out how my @spec is incorrect所说,Dialyzer检测到您的Comeonin.Argon2.check_pass()呼叫将永远不会返回OK,所以...

我还没有解决方案,只是想弄清楚原因。