Skip to content

Commit

Permalink
Bugfix: Allow non-empty concrete lists
Browse files Browse the repository at this point in the history
We used to report an error if we had a concrete list like '[1]' and
it should have type 'nonempty_list()'. Why? Because the list is
represented as a cons followed by a nil, and we require the tail of
the cons to have the same type as the whole cons. But this patch
weakens the demand on the type of the tail of the cons so that
it is always allowed to be the empty list.
  • Loading branch information
josefs committed Dec 5, 2018
1 parent 7cd9e6f commit 12b3b71
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 3 deletions.
15 changes: 12 additions & 3 deletions src/typechecker.erl
Expand Up @@ -1010,6 +1010,15 @@ expect_tuple_union([], AccTy, AccCs, any, N) ->
expect_tuple_union([], AccTy, AccCs, _NoAny, _N) ->
{AccTy, AccCs}.


-spec allow_empty_list(type()) -> type().
allow_empty_list({type, P, nonempty_list, []}) ->
{type, P, list, []};
allow_empty_list({type, P, nonempty_list, [T]}) ->
{type, P, list, [T]};
allow_empty_list(Ty) ->
Ty.

%% Categorizes a function type.
%% Normalizes the type (expand user-def and remote types). Errors for non-fun
%% types are returned with the original non-normalized type.
Expand Down Expand Up @@ -1924,15 +1933,15 @@ do_type_check_expr_in(Env, Ty, Cons = {cons, LINE, H, T}) ->
case expect_list_type(Ty, dont_allow_nil_type) of
{elem_ty, ETy, Cs} ->
{VB1, Cs1} = type_check_expr_in(Env, ETy, H),
{VB2, Cs2} = type_check_expr_in(Env, Ty, T),
{VB2, Cs2} = type_check_expr_in(Env, allow_empty_list(Ty), T),
{union_var_binds(VB1, VB2, Env#env.tenv), constraints:combine([Cs, Cs1, Cs2])};
{elem_tys, ETys, Cs} ->
{VB1, Cs1} = type_check_union_in(Env, ETys, H),
{VB2, Cs2} = type_check_expr_in(Env, Ty, T),
{VB2, Cs2} = type_check_expr_in (Env, allow_empty_list(Ty), T),
{union_var_binds(VB1, VB2, Env#env.tenv), constraints:combine([Cs, Cs1, Cs2])};
any ->
{_Ty, VB1, Cs1} = type_check_expr (Env, H),
{ VB2, Cs2} = type_check_expr_in(Env, Ty, T),
{ VB2, Cs2} = type_check_expr_in(Env, allow_empty_list(Ty), T),
{union_var_binds(VB1, VB2, Env#env.tenv), constraints:combine(Cs1, Cs2)};
{type_error, _} ->
throw({type_error, cons, LINE, Cons, Ty})
Expand Down
5 changes: 5 additions & 0 deletions test/should_pass/nonempty_cons.erl
@@ -0,0 +1,5 @@
-module(nonempty_cons).

-spec t() -> [integer(), ...].
t() ->
[1].

0 comments on commit 12b3b71

Please sign in to comment.