diff options
Diffstat (limited to 'lib/compiler/test/beam_type_SUITE.erl')
-rw-r--r-- | lib/compiler/test/beam_type_SUITE.erl | 209 |
1 files changed, 201 insertions, 8 deletions
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl index 9f691716e3..076a604aa4 100644 --- a/lib/compiler/test/beam_type_SUITE.erl +++ b/lib/compiler/test/beam_type_SUITE.erl @@ -21,9 +21,10 @@ -export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1, init_per_group/2,end_per_group/2, - integers/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]). + 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,list_append/1,bad_binary_unit/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -33,6 +34,7 @@ all() -> groups() -> [{p,[parallel], [integers, + numbers, coverage, booleans, setelement, @@ -43,7 +45,11 @@ groups() -> float_compare, arity_checks, elixir_binaries, - find_best + find_best, + test_size, + cover_lists_functions, + list_append, + bad_binary_unit ]}]. init_per_suite(Config) -> @@ -113,8 +119,8 @@ do_integers_4(_, _, Res) -> Res. do_integers_5(X0, Y0) -> - %% X and Y will use the same register. - X = X0 band 1, + %% _X and Y will use the same register. + _X = X0 band 1, Y = Y0 band 3, case Y of 0 -> zero; @@ -123,6 +129,59 @@ do_integers_5(X0, Y0) -> 3 -> three end. +numbers(_Config) -> + Int = id(42), + true = is_integer(Int), + true = is_number(Int), + false = is_float(Int), + + Float = id(42.0), + true = is_float(Float), + true = is_number(Float), + false = is_integer(Float), + + Number = id(1) + id(2), + true = is_number(Number), + true = is_integer(Number), + false = is_float(Number), + + AnotherNumber = id(99.0) + id(1), + true = is_float(AnotherNumber), + true = is_number(AnotherNumber), + false = is_integer(AnotherNumber), + + NotNumber = id(atom), + true = is_atom(NotNumber), + false = is_number(NotNumber), + false = is_integer(NotNumber), + false = is_float(NotNumber), + + true = is_number(Int), + true = is_number(Float), + true = is_number(Number), + true = is_number(AnotherNumber), + + %% Cover beam_ssa_type:join/2. + + Join1 = case id(a) of + a -> 3 + id(7); %Number. + b -> id(5) / id(2) %Float. + end, + true = is_integer(Join1), + + Join2 = case id(a) of + a -> id(5) / 2; %Float. + b -> 3 + id(7) %Number. + end, + true = is_float(Join2), + + %% Cover beam_ssa_type:meet/2. + + Meet1 = id(0) + -10.0, %Float. + 10.0 = abs(Meet1), %Number. + + ok. + coverage(Config) -> {'EXIT',{badarith,_}} = (catch id(1) bsl 0.5), {'EXIT',{badarith,_}} = (catch id(2.0) bsl 2), @@ -164,30 +223,127 @@ coverage(Config) -> ok. booleans(_Config) -> - {'EXIT',{{case_clause,_},_}} = (catch do_booleans(42)), + {'EXIT',{{case_clause,_},_}} = (catch do_booleans_1(42)), + + ok = do_booleans_2(42, 41), + error = do_booleans_2(42, 42), + + AnyAtom = id(atom), + true = is_atom(AnyAtom), + false = is_boolean(AnyAtom), + + MaybeBool = id(maybe), + case MaybeBool of + true -> ok; + maybe -> ok; + false -> ok + end, + false = is_boolean(MaybeBool), + + NotBool = id(a), + case NotBool of + a -> ok; + b -> ok; + c -> ok + end, + false = is_boolean(NotBool), + ok. -do_booleans(B) -> +do_booleans_1(B) -> case is_integer(B) of yes -> yes; no -> no end. +do_booleans_2(A, B) -> + Not = not do_booleans_cmp(A, B), + case Not of + true -> + case Not of + true -> error; + false -> ok + end; + false -> ok + end. + +do_booleans_cmp(A, B) -> A > B. + setelement(_Config) -> T0 = id({a,42}), {a,_} = T0, {b,_} = setelement(1, T0, b), + {z,b} = do_setelement_1(<<(id(1)):32>>, {a,b}, z), + {new,two} = do_setelement_2(<<(id(1)):1>>, {one,two}, new), ok. +do_setelement_1(<<N:32>>, Tuple, NewValue) -> + _ = element(N, Tuple), + %% While updating the type for Tuple, beam_ssa_type would do: + %% maps:without(lists:seq(0, 4294967295), Elements) + setelement(N, Tuple, NewValue). + +do_setelement_2(<<N:1>>, Tuple, NewValue) -> + %% Cover the second clause in remove_element_info/2. The + %% type for the second element will be kept. + two = element(2, Tuple), + setelement(N, Tuple, NewValue). + cons(_Config) -> [did] = cons(assigned, did), + + true = cons_is_empty_list([]), + false = cons_is_empty_list([a]), + + false = cons_not(true), + true = cons_not(false), + + {$a,"bc"} = cons_hdtl(true), + {$d,"ef"} = cons_hdtl(false), ok. cons(assigned, Instrument) -> [Instrument] = [did]. +cons_is_empty_list(L) -> + Cons = case L of + [] -> "true"; + _ -> "false" + end, + id(1), + case Cons of + "true" -> true; + "false" -> false + end. + +cons_not(B) -> + Cons = case B of + true -> "true"; + false -> "false" + end, + id(1), + case Cons of + "true" -> false; + "false" -> true + end. + +cons_hdtl(B) -> + Cons = case B of + true -> "abc"; + false -> "def" + end, + id(1), + {id(hd(Cons)),id(tl(Cons))}. + +-record(bird, {a=a,b=id(42)}). + tuple(_Config) -> {'EXIT',{{badmatch,{necessary}},_}} = (catch do_tuple()), + + [] = [X || X <- [], #bird{a = a} == {r,X,foo}], + [] = [X || X <- [], #bird{b = b} == {bird,X}], + [] = [X || X <- [], 3 == X#bird.a], + ok. do_tuple() -> @@ -324,6 +480,43 @@ find_best([], <<"a">>) -> find_best([], nil) -> {error,<<"should not get here">>}. +test_size(_Config) -> + 2 = do_test_size({a,b}), + 4 = do_test_size(<<42:32>>), + ok. + +do_test_size(Term) when is_tuple(Term) -> + size(Term); +do_test_size(Term) when is_binary(Term) -> + size(Term). + +cover_lists_functions(Config) -> + case lists:suffix([no|Config], Config) of + true -> + ct:fail(should_be_false); + false -> + ok + end, + Zipped = lists:zipwith(fun(A, B) -> {A,B} end, + lists:duplicate(length(Config), zip), + 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. + +%% OTP-15872: The compiler would treat the "Unit" of bs_init instructions as +%% the unit of the result instead of the required unit of the input, causing +%% is_binary checks to be wrongly optimized away. +bad_binary_unit(_Config) -> + Bin = id(<<1,2,3>>), + Bitstring = <<Bin/binary,1:1>>, + false = is_binary(Bitstring), + ok. id(I) -> I. |