-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Perform return type inference and application across local calls #13984
Conversation
💚 💙 💜 💛 ❤️ |
def_expr = {kind, meta, [guards_to_expr(guards, {fun, [], args}), [do: body]]} | ||
|
||
exception = | ||
RuntimeError.exception(""" | ||
found error while checking types for #{Exception.format_mfa(module, fun, length(args))}: | ||
found error while checking types for #{Exception.format_mfa(stack.module, fun, length(args))}: | ||
|
||
#{Exception.format_banner(:error, e, stack)}\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this should be Exception.format_banner(:error, e, trace)
? Dialyzer is warning about that:
The call 'Elixir.Exception':format_banner
('error',
_e@1 ::
#{'__exception__' := 'true',
'__struct__' := atom(),
atom() => _},
_stack@1 ::
#{'function' := {_, _},
'mode' := 'dynamic' | 'infer' | 'traversal',
_ => _}) breaks the contract
(kind(), any(), stacktrace()) -> 'Elixir.String':t()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the report!
I tried to prove that we could catch this error too. Check this out. If I do this diff:
--- a/lib/elixir/lib/exception.ex
+++ b/lib/elixir/lib/exception.ex
@@ -131,7 +131,7 @@ def normalize(_kind, payload, _stacktrace), do: payload
@spec format_banner(kind, any, stacktrace) :: String.t()
def format_banner(kind, exception, stacktrace \\ [])
- def format_banner(:error, exception, stacktrace) do
+ def format_banner(:error, exception, [_ | _] = stacktrace) do
exception = normalize(:error, exception, stacktrace)
"** (" <> inspect(exception.__struct__) <> ") " <> message(exception)
end
diff --git a/lib/elixir/lib/module/types.ex b/lib/elixir/lib/module/types.ex
index acfb2f7d6..6976e6579 100644
--- a/lib/elixir/lib/module/types.ex
+++ b/lib/elixir/lib/module/types.ex
@@ -277,7 +277,7 @@ defp with_file_meta(stack, meta) do
end
end
- defp internal_error!(e, trace, kind, meta, fun, args, guards, body, stack) do
+ defp internal_error!(e, trace, kind, meta, fun, args, guards, body, %{} = stack) do
def_expr = {kind, meta, [guards_to_expr(guards, {fun, [], args}), [do: body]]}
exception =
I get this report:
warning: incompatible types given to Exception.format_banner/3:
Exception.format_banner(:error, e, stack)
given types:
:error, dynamic(), dynamic(%{...})
but expected one of:
#1
dynamic(:error), dynamic(), dynamic(non_empty_list(term(), term()))
#2
dynamic(:throw), dynamic(), dynamic()
#3
dynamic(:exit), dynamic(), dynamic()
#4
dynamic({:EXIT, term()}), dynamic(), dynamic()
where "e" was given the type:
# type: dynamic()
# from: lib/elixir/lib/module/types.ex:280:24
e
where "stack" was given the type:
# type: dynamic(%{...})
# from: lib/elixir/lib/module/types.ex:280:75
%{} = stack
typing violation found at:
│
287 │ #{Exception.format_banner(:error, e, stack)}\
│ ~
│
└─ (elixir 1.18.0-dev) lib/elixir/lib/module/types.ex:287:19: Module.Types.internal_error!/9
Which is nice!
I think however Dialyzer is typechecking across the function boundaries, because that's the only way it could know that stack has mode :dynamic | :infer | :traversal
. I will play with some of the ideas later. :)
WIP