diff options
author | Fernando Tapia Rico <fertapric@gmail.com> | 2018-09-28 10:58:31 +0200 |
---|---|---|
committer | Andrea Leopardi <an.leopardi@gmail.com> | 2018-09-28 10:58:31 +0200 |
commit | e1e096ab2ed1b705926b3e05a397d3d1a40d2977 (patch) | |
tree | a76ae3c7336dc2a17fbd8c300befb3daa34fb9ef | |
parent | 97ac0e6a9f1b8dd4fd56fec4427bb8839b396f97 (diff) | |
download | elixir-e1e096ab2ed1b705926b3e05a397d3d1a40d2977.tar.gz |
Warn on underspecified opaque types (#8232)
Refers to #5800
Performs the erl_lint check "underspecified_opaque, {TypeName, Arity}}" in Elixir.
After reading the Erlang/OTP codebase, it seems an "underspecified opaque" is an opaque type of arity 0 with a spec of "term" or "any".
-rw-r--r-- | lib/elixir/lib/kernel/typespec.ex | 8 | ||||
-rw-r--r-- | lib/elixir/src/elixir_erl_compiler.erl | 1 | ||||
-rw-r--r-- | lib/elixir/test/elixir/kernel/warning_test.exs | 22 |
3 files changed, 31 insertions, 0 deletions
diff --git a/lib/elixir/lib/kernel/typespec.ex b/lib/elixir/lib/kernel/typespec.ex index 2ada08d05..e2234e207 100644 --- a/lib/elixir/lib/kernel/typespec.ex +++ b/lib/elixir/lib/kernel/typespec.ex @@ -283,6 +283,11 @@ defmodule Kernel.Typespec do compile_error(caller, message) end + if underspecified?(kind, arity, spec) do + message = "@#{kind} type #{name}/#{arity} is underspecified and therefore meaningless" + :elixir_errors.warn(caller.line, caller.file, message) + end + {{kind, {name, arity}, caller.line, type, export}, state} end @@ -292,6 +297,9 @@ defmodule Kernel.Typespec do defp valid_variable_ast?(_), do: false + defp underspecified?(:opaque, 0, {:type, _, type, []}) when type in [:any, :term], do: true + defp underspecified?(_kind, _arity, _spec), do: false + defp translate_spec({kind, {{:when, _meta, [spec, guard]}, pos}}, state) do caller = :elixir_locals.get_cached_env(pos) translate_spec(kind, spec, guard, caller, state) diff --git a/lib/elixir/src/elixir_erl_compiler.erl b/lib/elixir/src/elixir_erl_compiler.erl index 371836fe2..86010ffc7 100644 --- a/lib/elixir/src/elixir_erl_compiler.erl +++ b/lib/elixir/src/elixir_erl_compiler.erl @@ -52,6 +52,7 @@ handle_file_warning(_, _File, {_Line, erl_lint, {unused_function, _}}) -> ok; handle_file_warning(_, _File, {_Line, erl_lint, {unused_var, _}}) -> ok; handle_file_warning(_, _File, {_Line, erl_lint, {shadowed_var, _, _}}) -> ok; handle_file_warning(_, _File, {_Line, erl_lint, {exported_var, _, _}}) -> ok; +handle_file_warning(_, _File, {_Line, erl_lint, {underspecified_opaque, _}}) -> ok; handle_file_warning(_, _File, {_Line, v3_core, {map_key_repeated, _}}) -> ok; %% Ignore behaviour warnings as we check for these problem ourselves diff --git a/lib/elixir/test/elixir/kernel/warning_test.exs b/lib/elixir/test/elixir/kernel/warning_test.exs index 5e162a10c..cee4d71b4 100644 --- a/lib/elixir/test/elixir/kernel/warning_test.exs +++ b/lib/elixir/test/elixir/kernel/warning_test.exs @@ -1203,6 +1203,28 @@ defmodule Kernel.WarningTest do purge(Sample) end + test "underspecified opaque types" do + output = + capture_err(fn -> + Code.eval_string(""" + defmodule Sample do + @opaque op1 :: term + @opaque op2 :: any + @opaque op3 :: atom + end + """) + end) + + assert output =~ "nofile:2" + assert output =~ "@opaque type op1/0 is underspecified and therefore meaningless" + assert output =~ "nofile:3" + assert output =~ "@opaque type op2/0 is underspecified and therefore meaningless" + refute output =~ "nofile:4" + refute output =~ "op3" + after + purge(Sample) + end + test "typedoc on typep" do assert capture_err(fn -> Code.eval_string(""" |