Skip to content

Commit

Permalink
Merge pull request #520 from erszcz/new-goal-refine-vars-with-guards
Browse files Browse the repository at this point in the history
New known problem: refine bound vars with guards
  • Loading branch information
erszcz authored Mar 16, 2023
2 parents 1498d17 + 4bdb4e1 commit 0061fe9
Showing 1 changed file with 37 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
-module(refine_bound_var_with_guard_should_pass).

-export([f/1]).

%% This type is simpler than gradualizer_type:abstract_type() by having less variants
%% and by using tuples to contain deeper nodes. The latter frees us from having to deal
%% with list (non)emptiness/length in the patterns.
-type simple_type() :: {type, list | nonempty_list, {a}}
| {type, atom, {b}}.

-spec f(simple_type()) -> a.
f({type, T, {InnerNode}})
when T == list orelse T == nonempty_list ->
%% Currently, this clause fails with:
%%
%% test/known_problems/should_pass/refine_bound_var_with_guard_should_pass.erl:
%% The variable on line 14 at column 5 is expected to have type a but it has type b | a
%%
%% f({type, T, {InnerNode}})
%% when T == list orelse T == nonempty_list ->
%% InnerNode;
%% ^^^^^^
%%
%% We can refactor it to pass (see g/1), but then we end up with almost identical repeated code.
%% The end result is more clunky and doesn't feel as lightweight and flexible as normal Erlang.
InnerNode;
f({type, atom, {_InnerNode}}) ->
a.

%% Intentionally not exported.
-spec g(simple_type()) -> a.
g({type, list, {InnerNode}}) ->
InnerNode;
g({type, nonempty_list, {InnerNode}}) ->
InnerNode;
g({type, atom, {_InnerNode}}) ->
a.

0 comments on commit 0061fe9

Please sign in to comment.