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

Unexpected incompatible type #51

Open
gilbertwong96 opened this issue Jan 8, 2024 · 3 comments
Open

Unexpected incompatible type #51

gilbertwong96 opened this issue Jan 8, 2024 · 3 comments

Comments

@gilbertwong96
Copy link

gilbertwong96 commented Jan 8, 2024

I wrote codes with the maybe feature like this:

-module(test_eqwalizer).

-feature(maybe_expr, enable).

-export([main/1]).


-spec main(Args :: list(binary())) -> {ok, binary()} | {error, any()}.
main(Args) ->
    maybe
        true ?= (length(Args) =/= 0) orelse {error, empty_args},
        true ?= is_binary(lists:last(Args)) orelse {error, badargs},
        {ok, <<"ok">>}
    end.

I suppose the type spec is correct. However, the eqwalizer reports the error incompatible_types.

The entire output is as below:

error: incompatible_types
   ┌─ src/test_eqwalizer.erl:11:17
   │
11 │         true ?= (length(Args) =/= 0) orelse {error, empty_args},
   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   │                 │
   │                 _ orelse _.
Expression has type:   'true' | {'error', 'empty_args'}
Context expected type: {'ok', binary()} | {'error', term()}

See https://fb.me/eqwalizer_errors#incompatible_types
   │                 

  'true' | {'error', 'empty_args'} is not compatible with {'ok', binary()} | {'error', term()}
  because
  'true' is not compatible with {'ok', binary()} | {'error', term()}
  because
  'true' is not compatible with {'ok', binary()}

error: incompatible_types
   ┌─ src/test_eqwalizer.erl:12:17
   │
12 │         true ?= is_binary(lists:last(Args)) orelse {error, badargs},
   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   │                 │
   │                 _ orelse _.
Expression has type:   'true' | {'error', 'badargs'}
Context expected type: {'ok', binary()} | {'error', term()}

See https://fb.me/eqwalizer_errors#incompatible_types
   │                 

  'true' | {'error', 'badargs'} is not compatible with {'ok', binary()} | {'error', term()}
  because
  'true' is not compatible with {'ok', binary()} | {'error', term()}
  because
  'true' is not compatible with {'ok', binary()}

2 ERRORS

Could you please give me an explanation ?

@VLanvin
Copy link
Contributor

VLanvin commented Jan 8, 2024

To support this example, we need complex reasoning about patterns and types to eliminate the types matched by the left hand side of ?= from the right hand side.

This is something we currently do not support but would like to, although it is very difficult in the general case (where the pattern is more complex than an atom).

I plan to investigate this during the coming year.

@cowang4
Copy link

cowang4 commented Mar 27, 2024

I plan to investigate this during the coming year.

@VLanvin isn't this needed for maybe support? In the meantime should we have eqwalizer not run in maybe blocks? Or all maybe blocks will need % eqwalizer:fixme comments?

@VLanvin
Copy link
Contributor

VLanvin commented Mar 28, 2024

isn't this needed for maybe support? In the meantime should we have eqwalizer not run in maybe blocks? Or all maybe blocks will need % eqwalizer:fixme comments?

A lot can already be done with maybe blocks and eqWAlizer, such as binding variables via patterns, e.g., {ok, V} ?= foo(Arg). The type of V here will be correctly refined according to the spec of foo/1.

More complex behaviour that mixes predicates, patterns, and booleans such as what is being proposed here, is what is not supported currently.

I don't think it's worth disabling eqWAlizer in maybe blocks for such cases, as we can indeed use % eqwalizer:fixme comments. If the use-case becomes too frequent, then we can re-consider.

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

No branches or pull requests

3 participants