summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFernando Tapia Rico <fertapric@gmail.com>2018-09-28 10:58:31 +0200
committerAndrea Leopardi <an.leopardi@gmail.com>2018-09-28 10:58:31 +0200
commite1e096ab2ed1b705926b3e05a397d3d1a40d2977 (patch)
treea76ae3c7336dc2a17fbd8c300befb3daa34fb9ef
parent97ac0e6a9f1b8dd4fd56fec4427bb8839b396f97 (diff)
downloadelixir-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.ex8
-rw-r--r--lib/elixir/src/elixir_erl_compiler.erl1
-rw-r--r--lib/elixir/test/elixir/kernel/warning_test.exs22
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("""