-
Notifications
You must be signed in to change notification settings - Fork 3k
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
dialyzer: add global variable binding #7717
base: master
Are you sure you want to change the base?
dialyzer: add global variable binding #7717
Conversation
Make typed argument names and type variables global in their declaration. Before this PR, the following example would make the linter to complain about singleton variable used: ```erlang -foo(X :: integer()) -> X. foo(X) -> X. ``` So the linter would complain with the following message: ``` type variable 'X' is only used once (is unbound) ``` With this pull request, an argument name given to a type becomes bound globally and usable anywhere in the type specification. bound type annotations cannot receive different types, which was something that we never took care of. Example: ``` -spec id(X) -> X when X :: string(), X :: integer(). # notice that this was allowed ``` This PR throws a linter error if such declaration of duplicate names with different types appear. That said, in cases where there are multiple type annotations with different types, the PR simply performs type equality of the types (such as nominal typing), and does not try to infer their structure (structural typing). This means that the following is an error, even if their internal structure represent the same thing: ``` -spec id(X :: string()) -> X :: [char()]. ``` The main reason for not detecting this type equivalence is that, if one really is going to duplicate the name, then it should be explicit that the types assigned to the same type annotation are identical.
CT Test ResultsNo tests were run for this PR. This is either because the build failed, or the PR is based on a branch without GH actions tests configured. Results for commit c0275b4 To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass. See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally. Artifacts
// Erlang/OTP Github Action Bot |
90ee1bc
to
88a89c8
Compare
as per OTP pull request [#7717](erlang/otp#7717), duplicate annotation types will not be allowed in OTP-27. this commit simply re-writes the type specification so that it is compliant with the change.
as per OTP pull request [#7717](erlang/otp#7717), duplicate annotation types will not be allowed in OTP-27. this PR simply re-writes the type specification so that it is compliant with the OTP change.
Stalled until a new tag for |
Stalled until the following PR is merged |
I have a concern that this PR changes the semantics how type specs are interpreted: Right now - as documentation says - such syntax is used for documentation purposes. - It's not the same as type variables. https://www.erlang.org/doc/reference_manual/typespec.html#specifications-for-functions
And currently for dialyzer (and for eqWAlizer, and I believe for Gradualizer as well) To me, as a documentation reader, argument names and type variables are different concepts. This PR makes documentation confusing - as the addition to documentation (see below) implies that "argument names" and "type variables" are the same concepts.
|
I am not sure that this PR will go through, due to breaking existing 3rd party code. That said:
Type variables and argument names are different. This PR only binds argument names to types, so that one can reuse the name. Example: -spec foo(X :: integer(), Y) -> {X, Y}. Argument -spec foo(X :: integer(), Y) -> {X :: integer(), Y}. The type variable -spec foo(X :: integer(), Y) -> {X, Y}. The first -spec foo(X, Y) -> {X, Y} when X :: integer(). The only difference is that you do not need to use the |
This example below has tripped some customers thinking that -spec foo(X :: integer(), Y) -> {X, Y}. which is not true. Here the second Does this make sense? |
I will continue stalling this until we know this is correct and dependencies to which I submitted PRs have been merged. |
Make typed argument names and type variables global in their declaration.
Before this PR, the following example would make the linter to complain about singleton variable used:
So the linter would complain with the following message:
With this pull request, an argument name given to a type becomes bound globally and usable anywhere in the type specification.
Furthermore, bound type annotations cannot receive different types, which was something that we never took care of, and duplicate annotation names are also disallowed.
Example:
This code throws a linter error if such declaration of duplicate names with different types appear.