Skip to content
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

Call to undefined function :erlang.'++'/2 in OTP 22 #437

Closed
japhib opened this issue Aug 23, 2022 · 2 comments · Fixed by #440
Closed

Call to undefined function :erlang.'++'/2 in OTP 22 #437

japhib opened this issue Aug 23, 2022 · 2 comments · Fixed by #440

Comments

@japhib
Copy link

japhib commented Aug 23, 2022

Hi, just want to say how awesome this project is. I'm hoping to use it on a 300k+ LOC Elixir project for work -- just want to work out some issues first. Note that because I'm using Elixir with Gradient, the error message in the title is probably formatted differently -- but I've narrowed this down to 100% being an issue with Gradualizer, not Gradient.

The issue is that using the ++ operator on OTP 22 generates the error message Call to undefined function :erlang.'++'/2. This issue does not happen with OTP 24. I was able to narrow this down to gradualizer_db:import_module/2 loading specs from the erlang BEAM file, and on OTP 22 that file doesn't contain a spec for ++.

I verified this by disassembling the BEAM files using:

iex> {:ok, forms} = Gradient.ElixirFileUtils.get_forms_from_beam('/Users/myusername/.asdf/installs/erlang/22.3.4.22/lib/erts-10.7.2.14/ebin/erlang.beam')
iex> IO.puts(:erl_prettypr.format(:erl_syntax.form_list(forms)))

Again, sorry for using Elixir here rather than Erlang, but it's probably pretty simple to do the same thing from Erlang using :erl_prettypr.format(:erl_syntax.form_list(forms)). Anyways, I logged out what file it's loading the erlang module from, and when it loads from .asdf/installs/erlang/22.3.4.22/lib/erts-10.7.2.14/ebin/erlang.beam, the ++ spec is not present, but when it loads from .asdf/installs/erlang/24.2.1/lib/erts-12.2.1/ebin/erlang.beam, the ++ spec IS present.

(I guess it's possible that in the very latest version of OTP 22, since 22.3.4.22, this spec has been added. But that seems unlikely. I can double check on this.)

What seems like the easiest fix is to add a thing somewhere inside gradualizer_db when we import the erlang module, which is only enabled for OTP version 22 and earlier. (Maybe also OTP 23 -- I'll have to check.) At that point we'd import some hard-coded function specs for missing functions, such as ++, and any others we find. (I'm assuming there are quite a few more.)

But, I'm open to other ways to fix this. I'm happy to submit an MR for this sometime in the next few days/weeks, just wanted to agree on the method of solving the issue before I start coding it. What do you think?

@erszcz
Copy link
Collaborator

erszcz commented Aug 24, 2022

Hi, @japhib!

Thanks for your interest!

In general, the notion of overriding OTP specs already has a solution in Gradualizer - it's the prelude. It's also possible to specify locations of other such *.specs.erl in a project setting. Please see the following example:

$ cat plusplus.erl
-module(plusplus).

-export([f/0,
         g/0]).

-spec f() -> [integer()].
f() ->
    [3] ++ [1].

-spec g() -> [integer()].
g() ->
    plusplus_helper:concat([3], [1]).
$ gradualizer plusplus.erl
plusplus.erl: Call to undefined function plusplus_helper:concat/2 on line 12 at column 20
$ gradualizer --specs_override_dir gradualizer_overrides/ -- plusplus.erl
$ ls gradualizer_overrides/
plusplus_helper.specs.erl
$ cat gradualizer_overrides/plusplus_helper.specs.erl
-module(plusplus_helper).

-spec plusplus_helper:concat([T], [T]) -> [T].

specs_override_dir could also be used from a rebar.config file to apply to an entire Rebar3 Erlang project. So in general, there's already a way provide the external specs for functions defined without them.

Now, things get tricky when we're considering the above for Elixir - I think it's not yet possible to do something similar with Gradient. I've created a ticket to track it - esl/gradient#122.

For this particular case, though, I see no harm in including the specs directly in Gradualizer's prelude - #440.

Thanks for reaching out and good luck with Gradient and your project!

@japhib
Copy link
Author

japhib commented Aug 24, 2022

Thanks for all the information and the quick response! I’ll test the proposed changes with my project to make sure it fixes it as intended.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants