1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(core_alias_SUITE).
21
22-export([all/0, suite/0, groups/0,init_per_suite/1, end_per_suite/1,
23         init_per_group/2, end_per_group/2,
24         tuples/1, cons/1, catastrophic_runtime/1]).
25
26-include_lib("common_test/include/ct.hrl").
27
28suite() -> [{ct_hooks,[ts_install_cth]}].
29
30all() ->
31    [{group,p}].
32
33groups() ->
34    [{p,[parallel],
35      [tuples, cons, catastrophic_runtime]}].
36
37init_per_suite(Config) ->
38    test_lib:recompile(?MODULE),
39    Config.
40
41end_per_suite(_Config) ->
42    ok.
43
44init_per_group(_GroupName, Config) ->
45    Config.
46
47end_per_group(_GroupName, Config) ->
48    Config.
49
50id(X) -> X.
51
52tuples(Config) when is_list(Config) ->
53    Tuple = id({ok,id(value)}),
54
55    true = erts_debug:same(Tuple, simple_tuple(Tuple)),
56    true = erts_debug:same(Tuple, simple_tuple_in_map(#{hello => Tuple})),
57    true = erts_debug:same(Tuple, simple_tuple_case_repeated(Tuple, Tuple)),
58    true = erts_debug:same(Tuple, simple_tuple_fun_repeated(Tuple, Tuple)),
59    true = erts_debug:same(Tuple, simple_tuple_twice_head(Tuple, Tuple)),
60
61    {Tuple1, Tuple2} = id(simple_tuple_twice_body(Tuple)),
62    true = erts_debug:same(Tuple, Tuple1),
63    true = erts_debug:same(Tuple, Tuple2),
64
65    Nested = id({nested,Tuple}),
66    true = erts_debug:same(Tuple, nested_tuple_part(Nested)),
67    true = erts_debug:same(Nested, nested_tuple_whole(Nested)),
68    true = erts_debug:same(Nested, nested_tuple_with_alias(Nested)),
69
70    true = erts_debug:same(Tuple, tuple_rebinding_after(Tuple)),
71
72    Tuple = id(unaliased_tuple_rebinding_before(Tuple)),
73    false = erts_debug:same(Tuple, unaliased_tuple_rebinding_before(Tuple)),
74    Nested = id(unaliased_literal_tuple_head(Nested)),
75    false = erts_debug:same(Nested, unaliased_literal_tuple_head(Nested)),
76    Nested = id(unaliased_literal_tuple_body(Nested)),
77    false = erts_debug:same(Nested, unaliased_literal_tuple_body(Nested)),
78    Nested = id(unaliased_different_var_tuple(Nested, Tuple)),
79    false = erts_debug:same(Nested, unaliased_different_var_tuple(Nested, Tuple)).
80
81simple_tuple({ok,X}) ->
82    {ok,X}.
83simple_tuple_twice_head({ok,X}, {ok,X}) ->
84    {ok,X}.
85simple_tuple_twice_body({ok,X}) ->
86    {{ok,X},{ok,X}}.
87simple_tuple_in_map(#{hello := {ok,X}}) ->
88    {ok,X}.
89simple_tuple_fun_repeated({ok,X}, Y) ->
90    io:format("~p~n", [X]),
91    (fun({ok,X}) -> {ok,X} end)(Y).
92simple_tuple_case_repeated({ok,X}, Y) ->
93    io:format("~p~n", [X]),
94    case Y of {ok,X} -> {ok,X} end.
95
96nested_tuple_part({nested,{ok,X}}) ->
97    {ok,X}.
98nested_tuple_whole({nested,{ok,X}}) ->
99    {nested,{ok,X}}.
100nested_tuple_with_alias({nested,{ok,_}=Y}) ->
101    {nested,Y}.
102
103tuple_rebinding_after(Y) ->
104    (fun(X) -> {ok,X} end)(Y),
105    case Y of {ok,X} -> {ok,X} end.
106unaliased_tuple_rebinding_before({ok,X}) ->
107    io:format("~p~n", [X]),
108    (fun(X) -> {ok,X} end)(value).
109unaliased_literal_tuple_head({nested,{ok,value}=X}) ->
110    io:format("~p~n", [X]),
111    {nested,{ok,value}}.
112unaliased_literal_tuple_body({nested,{ok,value}=X}) ->
113    Res = {nested,Y={ok,value}},
114    io:format("~p~n", [[X,Y]]),
115    Res.
116unaliased_different_var_tuple({nested,{ok,value}=X}, Y) ->
117    io:format("~p~n", [X]),
118    {nested,Y}.
119
120cons(Config) when is_list(Config) ->
121    Cons = id([ok|id(value)]),
122
123    true = erts_debug:same(Cons, simple_cons(Cons)),
124    true = erts_debug:same(Cons, simple_cons_in_map(#{hello => Cons})),
125    true = erts_debug:same(Cons, simple_cons_case_repeated(Cons, Cons)),
126    true = erts_debug:same(Cons, simple_cons_fun_repeated(Cons, Cons)),
127    true = erts_debug:same(Cons, simple_cons_twice_head(Cons, Cons)),
128
129    {Cons1,Cons2} = id(simple_cons_twice_body(Cons)),
130    true = erts_debug:same(Cons, Cons1),
131    true = erts_debug:same(Cons, Cons2),
132
133    Nested = id([nested,Cons]),
134    true = erts_debug:same(Cons, nested_cons_part(Nested)),
135    true = erts_debug:same(Nested, nested_cons_whole(Nested)),
136    true = erts_debug:same(Nested, nested_cons_with_alias(Nested)),
137    true = erts_debug:same(Cons, cons_rebinding_after(Cons)),
138
139    Unstripped = id([a,b]),
140    Stripped = id(cons_with_binary([<<>>|Unstripped])),
141    true = erts_debug:same(Unstripped, Stripped),
142
143    Cons = id(unaliased_cons_rebinding_before(Cons)),
144    false = erts_debug:same(Cons, unaliased_cons_rebinding_before(Cons)),
145    Nested = id(unaliased_literal_cons_head(Nested)),
146    false = erts_debug:same(Nested, unaliased_literal_cons_head(Nested)),
147    Nested = id(unaliased_literal_cons_body(Nested)),
148    false = erts_debug:same(Nested, unaliased_literal_cons_body(Nested)),
149    Nested = id(unaliased_different_var_cons(Nested, Cons)),
150    false = erts_debug:same(Nested, unaliased_different_var_cons(Nested, Cons)).
151
152simple_cons([ok|X]) ->
153    [ok|X].
154simple_cons_twice_head([ok|X], [ok|X]) ->
155    [ok|X].
156simple_cons_twice_body([ok|X]) ->
157    {[ok|X],[ok|X]}.
158simple_cons_in_map(#{hello := [ok|X]}) ->
159    [ok|X].
160simple_cons_fun_repeated([ok|X], Y) ->
161    io:format("~p~n", [X]),
162    (fun([ok|X]) -> [ok|X] end)(Y).
163simple_cons_case_repeated([ok|X], Y) ->
164    io:format("~p~n", [X]),
165    case Y of [ok|X] -> [ok|X] end.
166
167nested_cons_part([nested,[ok|X]]) ->
168    [ok|X].
169nested_cons_whole([nested,[ok|X]]) ->
170    [nested,[ok|X]].
171nested_cons_with_alias([nested,[ok|_]=Y]) ->
172    [nested,Y].
173
174cons_with_binary([<<>>,X|Y]) ->
175    cons_with_binary([X|Y]);
176cons_with_binary(A) ->
177    A.
178
179cons_rebinding_after(Y) ->
180    (fun(X) -> [ok|X] end)(Y),
181    case Y of [ok|X] -> [ok|X] end.
182unaliased_cons_rebinding_before([ok|X]) ->
183    io:format("~p~n", [X]),
184    (fun(X) -> [ok|X] end)(value).
185unaliased_literal_cons_head([nested,[ok|value]=X]) ->
186    io:format("~p~n", [X]),
187    [nested,[ok|value]].
188unaliased_literal_cons_body([nested,[ok|value]=X]) ->
189    Res = [nested,Y=[ok|value]],
190    io:format("~p~n", [[X, Y]]),
191    Res.
192unaliased_different_var_cons([nested,[ok|value]=X], Y) ->
193    io:format("~p~n", [X]),
194    [nested,Y].
195
196catastrophic_runtime(Config) ->
197    ct:timetrap({minutes, 6}),
198    Depth = 16000,
199
200    PrivDir = proplists:get_value(priv_dir,Config),
201    Path = filename:join(PrivDir, "catastrophic_runtime.erl"),
202
203    Term = catastrophic_runtime_1(Depth),
204    Source = ["-module(catastrophic_runtime). t(Value) -> ", Term, "."],
205    ok = file:write_file(Path, Source),
206
207    {ok, catastrophic_runtime} = compile:file(Path, [return_error]),
208    file:delete(Path),
209
210    ok.
211
212catastrophic_runtime_1(0) ->
213    <<"Value">>;
214catastrophic_runtime_1(N) ->
215    Nested = catastrophic_runtime_1(N - 1),
216    Integer = integer_to_binary(N),
217    Eq = [<<"{{'.',[],[erlang,'=:=']},[],[Value, \"">>, Integer, <<"\"]}">>],
218    [<<"{{'.',[],[erlang,atom]},[],[">>, Nested, <<",">>, Eq, <<"]}">>].
219
220