Skip to content

Commit

Permalink
Fix the bitstring subtype generic case
Browse files Browse the repository at this point in the history
If the return type of a function returning a binary comprehension is a
supertype of a bitstring, we want the function to match correctly. While
before I had fixed a special case (binary), when fixing a deeper case
with nested unions and arbitrary bitstring sizes, it turned out to be
better to expand the union and try to typecheck against any of them.

So on the return of `flatten_type(ResTy, Env)` we try to typecheck the
binary comprehension. If it does, then we have a match, and we merge
into it the constraints that any possible match on subsequent flattened
types might give. If it returns the specific error, we ignore it, if it
returns a different one, not related to the fact that we're trying to
match on subtypes, we crash.
  • Loading branch information
NelsonVides committed Oct 12, 2019
1 parent cd9d8ca commit 38ca950
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 7 deletions.
19 changes: 13 additions & 6 deletions src/typechecker.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2302,7 +2302,18 @@ do_type_check_expr_in(Env, ResTy, {call, P, Name, Args}) ->
do_type_check_expr_in(Env, ResTy, {lc, P, Expr, Qualifiers}) ->
type_check_comprehension_in(Env, ResTy, lc, Expr, P, Qualifiers);
do_type_check_expr_in(Env, ResTy, {bc, P, Expr, Qualifiers}) ->
type_check_comprehension_in(Env, ResTy, bc, Expr, P, Qualifiers);
Error = {type_error, bc, P, ResTy},
{Res, Acc} = lists:mapfoldl(
fun(FlatTy, Acc) ->
case catch {type_check_comprehension_in(Env, FlatTy, bc, Expr, P, Qualifiers), Acc} of
{{#{}, C1}, {#{}, C2}} -> {ok, {#{}, constraints:combine(C1, C2)}};
{{#{}, _} = C, {type_error, _, _, _}} -> {ok, C};
{type_error, bc, P, FlatTy} -> {type_error,Acc};
{type_error, _, _, _} = E -> throw(E)
end
end, Error, flatten_type(ResTy, Env)),
lists:any(fun(El) -> El =:= ok end, Res) orelse throw(Error),
Acc;

%% Functions
do_type_check_expr_in(Env, Ty, {'fun', _, {clauses, Clauses}} = Fun) ->
Expand Down Expand Up @@ -2783,11 +2794,7 @@ type_check_comprehension_in(Env, ResTy, bc, Expr, P, []) ->
[{integer, erl_anno:new(0), 0},
{integer, erl_anno:new(0), 1}]};
_ ->
case subtype({type, erl_anno:new(0), binary, []}, ResTy, Env) of
{true, _} -> ResTy;
false ->
throw({type_error, bc, P, ResTy})
end
throw({type_error, bc, P, ResTy})
end,
{_VB, Cs} = type_check_expr_in(Env, ExprTy, Expr),
{#{}, Cs};
Expand Down
9 changes: 8 additions & 1 deletion test/should_pass/binary_in_union.erl
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
-module(binary_in_union).
-export([iodata_binary/0]).
-export([
iodata_binary/0,
bitstring_fun/0
]).

-spec iodata_binary() -> iodata().
iodata_binary() ->
<<<<"A">> || _ <- lists:seq(1, 10)>>.

-spec bitstring_fun() -> <<_:7, _:_*3>> | string().
bitstring_fun() ->
<< <<1:N>> || N <- lists:seq(3, 12)>>.

0 comments on commit 38ca950

Please sign in to comment.