Skip to content

Conversation

@josevalim
Copy link
Member

WIP

@josevalim josevalim merged commit cb2e036 into main Nov 11, 2024
24 checks passed
@josevalim josevalim deleted the jv-local-inference branch November 11, 2024 22:06
@josevalim
Copy link
Member Author

💚 💙 💜 💛 ❤️

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)}\
Copy link
Contributor

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()

Copy link
Member Author

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. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants