esl / gradient

Gradient is a static typechecker for Elixir
Apache License 2.0
435 stars 13 forks source link

can't import a module which uses `TypeAnnotations` #164

Closed paulswartz closed 1 year ago

paulswartz commented 1 year ago

I wrote up a quick example in https://github.com/paulswartz/gradient/commit/64ba4f5f74f32e3b3426a285e8bf55165d730277, but I get this compilation error trying to run import Annotations.ShouldPass:

== Compilation error in file test/examples/annotations.ex ==
** (CompileError) test/examples/annotations.ex:37: cannot import Annotations.ShouldPass.::/2 because it conflicts with Elixir special forms
    (elixir 1.13.4) src/elixir_import.erl:123: :elixir_import.calculate/6
    (elixir 1.13.4) src/elixir_import.erl:28: :elixir_import.import/4
Excluding tags: [:ex_lt_1_11, :ex_lt_1_12, :ex_lt_1_13, :ex_gt_1_13]

Thank you for this tool; I'm excited to see where it goes!

erszcz commented 1 year ago

Hi, @paulswartz!

Thanks for raising this! It's an interesting case since it highlights that it's possible to define a function with the ::/2 name in a module with the use/__using__ mechanism, but it's not possible to import such a function from another module. I'm not sure yet what the long-term solution to this should be... or if anything has to be done about it at all 🤔 We probably have to gather some more experience of using this in practice.

A workaround for the short-term, though, is to import with the except keyword:

defmodule AnnotationTest.ImportExample do
  import AnnotationTest, except: ["::": 2]
end

If we still want to use annotations in AnnotationTest.ImportExample, we can use Gradient.TypeAnnotation to enable them.

paulswartz commented 1 year ago

This pointed me at another potential solution: what about making ::/2 and :::/2 defp instead?

# lib/gradient/type_annotation.ex
      @compile {:inline, "::": 2, ":::": 2}
      defp unquote(:"::")(expr, _type), do: expr
      defp unquote(:":::")(expr, _type), do: expr
erszcz commented 1 year ago

Good idea, @paulswartz! Indeed, it seems to fix the problem. Thanks again for raising this and for coming up with a fix 🌟