aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2019-05-29 13:24:42 +0200
committerErlang/OTP <[email protected]>2019-05-29 13:24:42 +0200
commitf9b7f0c9202ccfeb8b09844f6ae689acb30447a2 (patch)
tree0b86da5178d6e8d1cc3c08eda52d8e4f1433760f
parent9afe8ad5eb15c1a205ca428d84c06d4a1fe888cc (diff)
parent00dc96a9a0086e829e574b651b4a28155aa826df (diff)
downloadotp-f9b7f0c9202ccfeb8b09844f6ae689acb30447a2.tar.gz
otp-f9b7f0c9202ccfeb8b09844f6ae689acb30447a2.tar.bz2
otp-f9b7f0c9202ccfeb8b09844f6ae689acb30447a2.zip
Merge branch 'john/compiler/list_append_type/OTP-15841' into maint-22
* john/compiler/list_append_type/OTP-15841: compiler: Fix broken type for erlang:'++'/2
-rw-r--r--lib/compiler/src/beam_ssa_type.erl14
-rw-r--r--lib/compiler/src/beam_validator.erl12
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl11
3 files changed, 26 insertions, 11 deletions
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl
index 2ea7e89dfa..34cdd0d663 100644
--- a/lib/compiler/src/beam_ssa_type.erl
+++ b/lib/compiler/src/beam_ssa_type.erl
@@ -896,11 +896,15 @@ type(call, [#b_remote{mod=#b_literal{val=Mod},
{_,_} ->
#t_tuple{}
end;
- {erlang,'++',[List1,List2]} ->
- case get_type(List1, Ts) =:= cons orelse
- get_type(List2, Ts) =:= cons of
- true -> cons;
- false -> list
+ {erlang,'++',[LHS,RHS]} ->
+ LType = get_type(LHS, Ts),
+ RType = get_type(RHS, Ts),
+ case LType =:= cons orelse RType =:= cons of
+ true ->
+ cons;
+ false ->
+ %% `[] ++ RHS` yields RHS, even if RHS is not a list.
+ join(list, RType)
end;
{erlang,'--',[_,_]} ->
list;
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 09a5a6c104..ebe9631e09 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -2844,10 +2844,14 @@ call_return_type_1(erlang, setelement, 3, Vst) ->
setelement(3, TupleType, #{})
end;
call_return_type_1(erlang, '++', 2, Vst) ->
- case get_term_type({x,0}, Vst) =:= cons orelse
- get_term_type({x,1}, Vst) =:= cons of
- true -> cons;
- false -> list
+ LType = get_term_type({x,0}, Vst),
+ RType = get_term_type({x,1}, Vst),
+ case LType =:= cons orelse RType =:= cons of
+ true ->
+ cons;
+ false ->
+ %% `[] ++ RHS` yields RHS, even if RHS is not a list
+ join(list, RType)
end;
call_return_type_1(erlang, '--', 2, _Vst) ->
list;
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 0d1680fb15..2297c2e0f5 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -24,7 +24,7 @@
integers/1,numbers/1,coverage/1,booleans/1,setelement/1,
cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1,
arity_checks/1,elixir_binaries/1,find_best/1,
- test_size/1,cover_lists_functions/1]).
+ test_size/1,cover_lists_functions/1,list_append/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -47,7 +47,8 @@ groups() ->
elixir_binaries,
find_best,
test_size,
- cover_lists_functions
+ cover_lists_functions,
+ list_append
]}].
init_per_suite(Config) ->
@@ -501,5 +502,11 @@ cover_lists_functions(Config) ->
true = is_list(Zipped),
ok.
+list_append(_Config) ->
+ %% '++'/2 has a quirk where it returns the right-hand argument as-is when
+ %% the left-hand is [].
+ hello = id([]) ++ id(hello),
+ ok.
+
id(I) ->
I.