1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2015-2020. 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(beam_type_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 integers/1,numbers/1,coverage/1,booleans/1,setelement/1, 25 cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1, 26 arity_checks/1,elixir_binaries/1,find_best/1, 27 test_size/1,cover_lists_functions/1,list_append/1,bad_binary_unit/1, 28 none_argument/1,success_type_oscillation/1,type_subtraction/1, 29 container_subtraction/1]). 30 31%% Force id/1 to return 'any'. 32-export([id/1]). 33 34suite() -> [{ct_hooks,[ts_install_cth]}]. 35 36all() -> 37 [{group,p}]. 38 39groups() -> 40 [{p,[parallel], 41 [integers, 42 numbers, 43 coverage, 44 booleans, 45 setelement, 46 cons, 47 tuple, 48 record_float, 49 binary_float, 50 float_compare, 51 arity_checks, 52 elixir_binaries, 53 find_best, 54 test_size, 55 cover_lists_functions, 56 list_append, 57 bad_binary_unit, 58 none_argument, 59 success_type_oscillation, 60 type_subtraction, 61 container_subtraction 62 ]}]. 63 64init_per_suite(Config) -> 65 test_lib:recompile(?MODULE), 66 Config. 67 68end_per_suite(_Config) -> 69 ok. 70 71init_per_group(_GroupName, Config) -> 72 Config. 73 74end_per_group(_GroupName, Config) -> 75 Config. 76 77integers(_Config) -> 78 a = do_integers_1(2#11000), 79 b = do_integers_1(2#11001), 80 81 a = do_integers_2(<<0:1>>), 82 {'EXIT',{{case_clause,-1},_}} = (catch do_integers_2(<<1:1>>)), 83 84 college = do_integers_3(), 85 86 zero = do_integers_4(<<0:1>>, 0), 87 one = do_integers_4(<<1:1>>, 0), 88 other = do_integers_4(<<1:1>>, 2), 89 90 zero = do_integers_5(0, 0), 91 one = do_integers_5(0, 1), 92 two = do_integers_5(0, 2), 93 three = do_integers_5(0, 3), 94 95 {'EXIT',{badarith,_}} = (catch do_integers_6()), 96 97 house = do_integers_7(), 98 99 {'EXIT',{badarith,_}} = (catch do_integers_8()), 100 101 ok. 102 103do_integers_1(B0) -> 104 B = B0 band 1, 105 case B band 15 of 106 0 -> a; 107 1 -> b 108 end. 109 110do_integers_2(Bin) -> 111 <<B:1/signed>> = Bin, 112 case B of 113 0 -> a; 114 1 -> b 115 end. 116 117do_integers_3() -> 118 case try 0 after [] end of 119 0 -> college; 120 1 -> 0 121 end. 122 123do_integers_4(<<X:1,T/bits>>, C) -> 124 %% Binary matching gives the range 0-1 for X. 125 %% The range for `X bor C` is unknown. It must not be inherited 126 %% from X. (`X bor C` will reuse the register used for X.) 127 case X bor C of 128 0 -> do_integers_4(T, C, zero); 129 1 -> do_integers_4(T, C, one); 130 _ -> do_integers_4(T, C, other) 131 end. 132 133do_integers_4(_, _, Res) -> 134 Res. 135 136do_integers_5(X0, Y0) -> 137 %% _X and Y will use the same register. 138 _X = X0 band 1, 139 Y = Y0 band 3, 140 case Y of 141 0 -> zero; 142 1 -> one; 143 2 -> two; 144 3 -> three 145 end. 146 147do_integers_6() -> 148 try b after 1 end band 0. 149 150do_integers_7() -> 151 try 152 0 153 band 154 try 155 0:any(), 156 ok 157 catch 158 bad_class:_:_ -> 159 {tag, "nt"} 160 end 161 catch 162 _:_:_ -> 163 house 164 end. 165 166do_integers_8() -> 167 -1 band ((0 div 0) band 0). 168 169numbers(_Config) -> 170 Int = id(42), 171 true = is_integer(Int), 172 true = is_number(Int), 173 false = is_float(Int), 174 175 Float = id(42.0), 176 true = is_float(Float), 177 true = is_number(Float), 178 false = is_integer(Float), 179 180 Number = id(1) + id(2), 181 true = is_number(Number), 182 true = is_integer(Number), 183 false = is_float(Number), 184 185 AnotherNumber = id(99.0) + id(1), 186 true = is_float(AnotherNumber), 187 true = is_number(AnotherNumber), 188 false = is_integer(AnotherNumber), 189 190 NotNumber = id(atom), 191 true = is_atom(NotNumber), 192 false = is_number(NotNumber), 193 false = is_integer(NotNumber), 194 false = is_float(NotNumber), 195 196 true = is_number(Int), 197 true = is_number(Float), 198 true = is_number(Number), 199 true = is_number(AnotherNumber), 200 201 %% Cover beam_ssa_type:join/2. 202 203 Join1 = case id(a) of 204 a -> 3 + id(7); %Number. 205 b -> id(5) / id(2) %Float. 206 end, 207 true = is_integer(Join1), 208 209 Join2 = case id(a) of 210 a -> id(5) / 2; %Float. 211 b -> 3 + id(7) %Number. 212 end, 213 true = is_float(Join2), 214 215 %% Cover beam_ssa_type:meet/2. 216 217 Meet1 = id(0) + -10.0, %Float. 218 10.0 = abs(Meet1), %Number. 219 220 ok. 221 222coverage(Config) -> 223 {'EXIT',{badarith,_}} = (catch id(1) bsl 0.5), 224 {'EXIT',{badarith,_}} = (catch id(2.0) bsl 2), 225 {'EXIT',{badarith,_}} = (catch a + 0.5), 226 {'EXIT',{badarith,_}} = (catch 2.0 * b), 227 228 {'EXIT',{badarith,_}} = (catch id(42.0) / (1 bsl 2000)), 229 230 id(id(42) band 387439739874298734983787934283479243879), 231 id(-1 band id(13)), 232 233 error = if 234 is_map(Config), is_integer(Config) -> ok; 235 true -> error 236 end, 237 error = if 238 is_map(Config), is_atom(Config) -> ok; 239 true -> error 240 end, 241 error = if 242 is_map(Config), is_tuple(Config) -> ok; 243 true -> error 244 end, 245 error = if 246 is_integer(Config), is_bitstring(Config) -> ok; 247 true -> error 248 end, 249 250 ok = case Config of 251 <<_>> when is_binary(Config) -> 252 impossible; 253 [_|_] -> 254 ok 255 end, 256 257 %% Cover beam_type:verified_type(none). 258 {'EXIT',{badarith,_}} = (catch (id(2) / id(1)) band 16#ff), 259 260 false = fun lot:life/147 == #{}, 261 262 ok. 263 264booleans(_Config) -> 265 {'EXIT',{{case_clause,_},_}} = (catch do_booleans_1(42)), 266 267 ok = do_booleans_2(42, 41), 268 error = do_booleans_2(42, 42), 269 270 AnyAtom = id(atom), 271 true = is_atom(AnyAtom), 272 false = is_boolean(AnyAtom), 273 274 MaybeBool = id(maybe), 275 case MaybeBool of 276 true -> ok; 277 maybe -> ok; 278 false -> ok 279 end, 280 false = is_boolean(MaybeBool), 281 282 NotBool = id(a), 283 case NotBool of 284 a -> ok; 285 b -> ok; 286 c -> ok 287 end, 288 false = is_boolean(NotBool), 289 290 ok. 291 292do_booleans_1(B) -> 293 case is_integer(B) of 294 yes -> yes; 295 no -> no 296 end. 297 298do_booleans_2(A, B) -> 299 Not = not do_booleans_cmp(A, B), 300 case Not of 301 true -> 302 case Not of 303 true -> error; 304 false -> ok 305 end; 306 false -> ok 307 end. 308 309do_booleans_cmp(A, B) -> A > B. 310 311setelement(_Config) -> 312 T0 = id({a,42}), 313 {a,_} = T0, 314 {b,_} = setelement(1, T0, b), 315 {z,b} = do_setelement_1(<<(id(1)):32>>, {a,b}, z), 316 {new,two} = do_setelement_2(<<(id(1)):1>>, {one,two}, new), 317 ok. 318 319do_setelement_1(<<N:32>>, Tuple, NewValue) -> 320 _ = element(N, Tuple), 321 %% While updating the type for Tuple, beam_ssa_type would do: 322 %% maps:without(lists:seq(0, 4294967295), Elements) 323 setelement(N, Tuple, NewValue). 324 325do_setelement_2(<<N:1>>, Tuple, NewValue) -> 326 %% Cover the second clause in remove_element_info/2. The 327 %% type for the second element will be kept. 328 two = element(2, Tuple), 329 setelement(N, Tuple, NewValue). 330 331cons(_Config) -> 332 [did] = cons(assigned, did), 333 334 true = cons_is_empty_list([]), 335 false = cons_is_empty_list([a]), 336 337 false = cons_not(true), 338 true = cons_not(false), 339 340 {$a,"bc"} = cons_hdtl(true), 341 {$d,"ef"} = cons_hdtl(false), 342 ok. 343 344cons(assigned, Instrument) -> 345 [Instrument] = [did]. 346 347cons_is_empty_list(L) -> 348 Cons = case L of 349 [] -> "true"; 350 _ -> "false" 351 end, 352 id(1), 353 case Cons of 354 "true" -> true; 355 "false" -> false 356 end. 357 358cons_not(B) -> 359 Cons = case B of 360 true -> "true"; 361 false -> "false" 362 end, 363 id(1), 364 case Cons of 365 "true" -> false; 366 "false" -> true 367 end. 368 369cons_hdtl(B) -> 370 Cons = case B of 371 true -> "abc"; 372 false -> "def" 373 end, 374 id(1), 375 {id(hd(Cons)),id(tl(Cons))}. 376 377-record(bird, {a=a,b=id(42)}). 378 379tuple(_Config) -> 380 {'EXIT',{{badmatch,{necessary}},_}} = (catch do_tuple()), 381 382 [] = [X || X <- [], #bird{a = a} == {r,X,foo}], 383 [] = [X || X <- [], #bird{b = b} == {bird,X}], 384 [] = [X || X <- [], 3 == X#bird.a], 385 386 ok. 387 388do_tuple() -> 389 {0, _} = {necessary}. 390 391-record(x, {a}). 392 393record_float(_Config) -> 394 17.0 = record_float(#x{a={0}}, 1700), 395 23.0 = record_float(#x{a={0}}, 2300.0), 396 {'EXIT',{if_clause,_}} = (catch record_float(#x{a={1}}, 88)), 397 {'EXIT',{if_clause,_}} = (catch record_float(#x{a={}}, 88)), 398 {'EXIT',{if_clause,_}} = (catch record_float(#x{}, 88)), 399 ok. 400 401record_float(R, N0) -> 402 N = N0 / 100, 403 if element(1, R#x.a) =:= 0 -> 404 N 405 end. 406 407binary_float(_Config) -> 408 <<-1/float>> = binary_negate_float(<<1/float>>), 409 ok. 410 411binary_negate_float(<<Float/float>>) -> 412 <<-Float/float>>. 413 414float_compare(_Config) -> 415 false = do_float_compare(-42.0), 416 false = do_float_compare(-42), 417 false = do_float_compare(0), 418 false = do_float_compare(0.0), 419 true = do_float_compare(42), 420 true = do_float_compare(42.0), 421 ok. 422 423do_float_compare(X) -> 424 %% ERL-433: Used to fail before OTP 20. Was accidentally fixed 425 %% in OTP 20. Add a test case to ensure it stays fixed. 426 427 Y = X + 1.0, 428 case X > 0 of 429 T when (T =:= nil) or (T =:= false) -> T; 430 _T -> Y > 0 431 end. 432 433arity_checks(_Config) -> 434 %% ERL-549: an unsafe optimization removed a test_arity instruction, 435 %% causing the following to return 'broken' instead of 'ok'. 436 ok = do_record_arity_check({rgb, 255, 255, 255, 1}), 437 ok = do_tuple_arity_check({255, 255, 255, 1}). 438 439-record(rgb, {r = 255, g = 255, b = 255}). 440 441do_record_arity_check(RGB) when 442 (element(2, RGB) >= 0), (element(2, RGB) =< 255), 443 (element(3, RGB) >= 0), (element(3, RGB) =< 255), 444 (element(4, RGB) >= 0), (element(4, RGB) =< 255) -> 445 if 446 element(1, RGB) =:= rgb, is_record(RGB, rgb) -> broken; 447 true -> ok 448 end. 449 450do_tuple_arity_check(RGB) when is_tuple(RGB), 451 (element(1, RGB) >= 0), (element(1, RGB) =< 255), 452 (element(2, RGB) >= 0), (element(2, RGB) =< 255), 453 (element(3, RGB) >= 0), (element(3, RGB) =< 255) -> 454 case RGB of 455 {255, _, _} -> broken; 456 _ -> ok 457 end. 458 459elixir_binaries(_Config) -> 460 <<"foo blitzky baz">> = elixir_binary_1(<<"blitzky">>), 461 <<"foo * baz">> = elixir_binary_2($*), 462 <<7:4,755:10>> = elixir_bitstring_3(<<755:10>>), 463 ok. 464 465elixir_binary_1(Bar) when is_binary(Bar) -> 466 <<"foo ", 467 case Bar of 468 Rewrite when is_binary(Rewrite) -> 469 Rewrite; 470 Rewrite -> 471 list_to_binary(Rewrite) 472 end/binary, 473 " baz">>. 474 475elixir_binary_2(Arg) -> 476 Bin = <<Arg>>, 477 <<"foo ", 478 case Bin of 479 Rewrite when is_binary(Rewrite) -> 480 Rewrite; 481 Rewrite -> 482 list_to_binary:to_string(Rewrite) 483 end/binary, 484 " baz">>. 485 486elixir_bitstring_3(Bar) when is_bitstring(Bar) -> 487 <<7:4, 488 case Bar of 489 Rewrite when is_bitstring(Rewrite) -> 490 Rewrite; 491 Rewrite -> 492 list_to_bitstring(Rewrite) 493 end/bitstring>>. 494 495find_best(_Config) -> 496 ok = find_best([a], nil), 497 ok = find_best([<<"a">>], nil), 498 {error,_} = find_best([], nil), 499 ok. 500 501%% Failed because beam_type assumed that the operand 502%% for bs_context_binary must be a binary. Not true! 503find_best([a|Tail], Best) -> 504 find_best(Tail, 505 case Best of 506 X when X =:= nil orelse X =:= false -> a; 507 X -> X 508 end); 509find_best([<<"a">>|Tail], Best) -> 510 find_best(Tail, 511 case Best of 512 X when X =:= nil orelse X =:= false -> <<"a">>; 513 X -> X 514 end); 515find_best([], a) -> 516 ok; 517find_best([], <<"a">>) -> 518 ok; 519find_best([], nil) -> 520 {error,<<"should not get here">>}. 521 522test_size(_Config) -> 523 2 = do_test_size({a,b}), 524 4 = do_test_size(<<42:32>>), 525 ok. 526 527do_test_size(Term) when is_tuple(Term) -> 528 size(Term); 529do_test_size(Term) when is_binary(Term) -> 530 size(Term). 531 532cover_lists_functions(Config) -> 533 case lists:suffix([no|Config], Config) of 534 true -> 535 ct:fail(should_be_false); 536 false -> 537 ok 538 end, 539 Zipped = lists:zipwith(fun(A, B) -> {A,B} end, 540 lists:duplicate(length(Config), zip), 541 Config), 542 true = is_list(Zipped), 543 ok. 544 545list_append(_Config) -> 546 %% '++'/2 has a quirk where it returns the right-hand argument as-is when 547 %% the left-hand is []. 548 hello = id([]) ++ id(hello), 549 ok. 550 551%% OTP-15872: The compiler would treat the "Unit" of bs_init instructions as 552%% the unit of the result instead of the required unit of the input, causing 553%% is_binary checks to be wrongly optimized away. 554bad_binary_unit(_Config) -> 555 Bin = id(<<1,2,3>>), 556 Bitstring = <<Bin/binary,1:1>>, 557 false = is_binary(Bitstring), 558 ok. 559 560%% ERL-1013: The compiler would crash during the type optimization pass. 561none_argument(_Config) -> 562 Binary = id(<<3:16, 42>>), 563 error = id(case Binary of 564 <<Len:16, Body/binary>> when length(Body) == Len - 2 -> 565 %% The type for Body will be none. It means 566 %% that this clause will never match and that 567 %% uncompress/1 will never be called. 568 uncompress(Body); 569 _ -> 570 error 571 end), 572 ok. 573 574uncompress(CompressedBinary) -> 575 %% The type for CompressedBinary is none, which beam_ssa_type 576 %% did not handle properly. 577 zlib:uncompress(CompressedBinary). 578 579%% ERL-1289: The compiler could enter an endless loop when a return/argument 580%% type pairing was joined with another. 581%% 582%% While this always resulted in correct success types, the joined argument 583%% types could now cover more cases than they did before, making the effective 584%% return type less specific. When a function affected by this was analyzed 585%% again its success typing could become more specific again and start the 586%% process anew. 587success_type_oscillation(_Config) -> 588 Base = {a, []}, 589 590 Base = sto_1(id(case_1_1)), 591 Base = sto_1(id(case_2_1)), 592 {b, [Base]} = sto_1(id(case_2_2)), 593 594 ok. 595 596sto_1(case_1_1) -> {a, []}; 597sto_1(case_1_2) -> {a, []}; 598sto_1(case_2_1) -> sto_1(case_1_1); 599sto_1(case_2_2) -> {b, [sto_1(case_1_1)]}; 600sto_1(case_2_3) -> {b, [sto_1(case_1_1)]}; 601sto_1(case_2_4) -> {b, [sto_1(case_1_2)]}; 602sto_1(case_3_1) -> {b, [sto_1(case_2_1)]}; 603sto_1(case_3_2) -> {b, [sto_1(case_2_2)]}; 604sto_1(case_3_3) -> {b, [sto_1(case_2_3)]}; 605sto_1(case_3_4) -> {b, [sto_1(case_2_4)]}; 606sto_1(case_4_1) -> {b, [sto_1(case_3_1)]}; 607sto_1(case_4_2) -> {b, [sto_1(case_3_2)]}; 608sto_1(step_4_3) -> {b, [sto_1(case_3_3)]}. 609 610%% ERL-1440: On inequality, we subtracted the type *common to* both variables 611%% rather than the left-hand type from the right-hand variable and vice versa, 612%% giving an erroneously narrow type. 613%% 614%% In the test below, we have functions returning integers ranged 1..2 and 615%% 2..3 and test for their equality. We know that it can only succeed when both 616%% return 2, but they can fail when the former returns 1 or the latter returns 617%% 3, so we must not subtract 2 on the failure path. 618type_subtraction(Config) when is_list(Config) -> 619 true = type_subtraction_1(id(<<"A">>)), 620 ok. 621 622type_subtraction_1(_x@1) -> 623 _a@1 = ts_12(_x@1), 624 _b@1 = ts_23(_x@1), 625 case _a@1 /= _b@1 of 626 false -> error; 627 true -> _a@1 =:= 3 andalso _b@1 =:= 2 628 end. 629 630ts_12(_x@1) -> 631 case _x@1 == <<"A">> of 632 false -> 633 2; 634 true -> 635 3 636 end. 637 638ts_23(_x@1) -> 639 case _x@1 == <<"A">> of 640 false -> 641 1; 642 true -> 643 2 644 end. 645 646%% GH-4774: The validator didn't update container contents on type subtraction. 647container_subtraction(Config) when is_list(Config) -> 648 A = id(baz), 649 650 cs_1({foo,[]}), 651 cs_1({bar,A}), 652 cs_2({bar,A}), 653 654 ok. 655 656cs_1({_,[]}) -> 657 ok; 658cs_1({_,_}=Other) -> 659 cs_2(Other). 660 661cs_2({bar,baz}) -> 662 ok. 663 664id(I) -> 665 I. 666