WhatsApp / eqwalizer

A type-checker for Erlang
Apache License 2.0
506 stars 27 forks source link

Issue with maybe expr #55

Open egobrain opened 4 months ago

egobrain commented 4 months ago

This simplified code:

-module(t).
-feature(maybe_expr, enable).

-export([mult2/1]).

-spec mult2(string()) -> {ok, string()} | {error, bad_int}.
mult2(Str) ->
    maybe
        {ok, Int} ?= convert_to_int(Str),
        {ok, integer_to_list(Int*2)}
    end.

-spec convert_to_int(string()) -> {ok, integer()} | {error, bad_int}.
convert_to_int(Str) ->
    try list_to_integer(Str) of Int ->
        {ok, Int}
    catch _:_ -> {error, bad_int}
    end.

leads to issue:

error: incompatible_types
  ┌─ src/t.erl:9:22
  │
9 │         {ok, Int} ?= convert_to_int(Str),
  │                      ^^^^^^^^^^^^^^^^^^^
  │                      │
  │                      convert_to_int(Str).
Expression has type:   {'ok', number()} | {'error', 'bad_int'}
Context expected type: {'ok', string()} | {'error', 'bad_int'}

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

  {'ok', number()} | {'error', 'bad_int'} is not compatible with {'ok', string()} | {'error', 'bad_int'}
  because
  {'ok', number()} is not compatible with {'ok', string()} | {'error', 'bad_int'}
  because
  at tuple index 2:
  {'ok', number()} is not compatible with {'ok', string()}
  because
  number() is not compatible with string()

Everything works well If i replace it with equivalent case expression:

-spec mult2(string()) -> {ok, string()} | {error, bad_int}.
mult2(Str) ->
    case convert_to_int(Str) of
        {ok, Int} ->
            {ok, integer_to_list(Int*2)};
        Other ->
            Other
    end.
ilya-klyuchnikov commented 4 months ago

Yes, that is a false positive. Unfortunately, eqwalizer has very limited support for handling maybe expressions and we don't have any plans to improve it in the nearest future.