diff options
Diffstat (limited to 'lib/compiler')
-rw-r--r-- | lib/compiler/src/beam_dict.erl | 13 | ||||
-rw-r--r-- | lib/compiler/src/sys_core_fold.erl | 192 | ||||
-rw-r--r-- | lib/compiler/src/v3_core.erl | 69 | ||||
-rw-r--r-- | lib/compiler/test/Makefile | 2 | ||||
-rw-r--r-- | lib/compiler/test/bs_match_SUITE.erl | 9 | ||||
-rw-r--r-- | lib/compiler/test/warnings_SUITE.erl | 10 |
6 files changed, 176 insertions, 119 deletions
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl index a503fcab38..c50ed28aa9 100644 --- a/lib/compiler/src/beam_dict.erl +++ b/lib/compiler/src/beam_dict.erl @@ -36,7 +36,6 @@ strings = <<>> :: binary(), %String pool lambdas = [], %[{...}] literals = dict:new() :: dict(), %Format: {Literal,Number} - next_atom = 1 :: pos_integer(), next_import = 0 :: non_neg_integer(), string_offset = 0 :: non_neg_integer(), next_literal = 0 :: non_neg_integer(), @@ -66,13 +65,14 @@ highest_opcode(#asm{highest_opcode=Op}) -> Op. %% atom(Atom, Dict) -> {Index,Dict'} -spec atom(atom(), bdict()) -> {pos_integer(), bdict()}. -atom(Atom, #asm{atoms=Atoms0,next_atom=NextIndex}=Dict) when is_atom(Atom) -> +atom(Atom, #asm{atoms=Atoms0}=Dict) when is_atom(Atom) -> case gb_trees:lookup(Atom, Atoms0) of {value,Index} -> {Index,Dict}; none -> + NextIndex = gb_trees:size(Atoms0) + 1, Atoms = gb_trees:insert(Atom, NextIndex, Atoms0), - {NextIndex,Dict#asm{atoms=Atoms,next_atom=NextIndex+1}} + {NextIndex,Dict#asm{atoms=Atoms}} end. %% Remembers an exported function. @@ -139,7 +139,7 @@ lambda(Lbl, Index, OldUniq, NumFree, #asm{lambdas=Lambdas0}=Dict) -> Lambdas = [{Lbl,{OldIndex,Lbl,Index,NumFree,OldUniq}}|Lambdas0], {OldIndex,Dict#asm{lambdas=Lambdas}}. -%% Returns the index for a literal (adding it to the atom table if necessary). +%% Returns the index for a literal (adding it to the literal table if necessary). %% literal(Literal, Dict) -> {Index,Dict'} -spec literal(term(), bdict()) -> {non_neg_integer(), bdict()}. @@ -156,14 +156,15 @@ literal(Lit, #asm{literals=Tab0,next_literal=NextIndex}=Dict) -> %% atom_table(Dict) -> {LastIndex,[Length,AtomString...]} -spec atom_table(bdict()) -> {non_neg_integer(), [[non_neg_integer(),...]]}. -atom_table(#asm{atoms=Atoms,next_atom=NumAtoms}) -> +atom_table(#asm{atoms=Atoms}) -> + NumAtoms = gb_trees:size(Atoms), Sorted = lists:keysort(2, gb_trees:to_list(Atoms)), Fun = fun({A,_}) -> L = atom_to_list(A), [length(L)|L] end, AtomTab = lists:map(Fun, Sorted), - {NumAtoms-1,AtomTab}. + {NumAtoms,AtomTab}. %% Returns the table of local functions. %% local_table(Dict) -> {NumLocals, [{Function, Arity, Label}...]} diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 96015fbe58..9360556e00 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -460,7 +460,8 @@ eval_binary(#c_binary{anno=Anno,segments=Ss}=Bin) -> Bin; throw:{badarg,Warning} -> add_warning(Bin, Warning), - #c_call{module=#c_literal{val=erlang}, + #c_call{anno=Anno, + module=#c_literal{val=erlang}, name=#c_literal{val=error}, args=[#c_literal{val=badarg}]} end. @@ -658,36 +659,34 @@ call_0(Call, M, N, As0, Sub) -> %% We inline some very common higher order list operations. %% We use the same evaluation order as the library function. -call_1(_Call, lists, all, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, all, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^all',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, X = #c_var{name='X'}, Err1 = #c_tuple{es=[#c_literal{val='case_clause'}, X]}, CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true}, - body=#c_apply{op=Loop, args=[Xs]}}, + body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}, CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true}, body=#c_literal{val=false}}, CC3 = #c_clause{pats=[X], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err1]}}, + body=match_fail(Anno, Err1)}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_case{arg=#c_apply{op=F, args=[X]}, + body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]}, clauses = [CC1, CC2, CC3]}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=true}}, Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err2]}}, + body=match_fail(Anno, Err2)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, any, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, any, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^any',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, @@ -696,72 +695,71 @@ call_1(_Call, lists, any, [Arg1,Arg2], Sub) -> CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true}, body=#c_literal{val=true}}, CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true}, - body=#c_apply{op=Loop, args=[Xs]}}, + body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}, CC3 = #c_clause{pats=[X], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err1]}}, + body=match_fail(Anno, Err1)}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_case{arg=#c_apply{op=F, args=[X]}, + body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]}, clauses = [CC1, CC2, CC3]}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=false}}, Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err2]}}, + body=match_fail(Anno, Err2)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, foreach, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, foreach, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^foreach',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, X = #c_var{name='X'}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_seq{arg=#c_apply{op=F, args=[X]}, - body=#c_apply{op=Loop, args=[Xs]}}}, + body=#c_seq{arg=#c_apply{anno=Anno, op=F, args=[X]}, + body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=ok}}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, map, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, map, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^map',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, X = #c_var{name='X'}, H = #c_var{name='H'}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_let{vars=[H], arg=#c_apply{op=F, args=[X]}, + body=#c_let{vars=[H], arg=#c_apply{anno=Anno, + op=F, + args=[X]}, body=#c_cons{hd=H, - tl=#c_apply{op=Loop, + tl=#c_apply{anno=Anno, + op=Loop, args=[Xs]}}}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=[]}}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, flatmap, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, flatmap, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^flatmap',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, @@ -769,26 +767,27 @@ call_1(_Call, lists, flatmap, [Arg1,Arg2], Sub) -> H = #c_var{name='H'}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, body=#c_let{vars=[H], - arg=#c_apply{op=F, args=[X]}, - body=#c_call{module=#c_literal{val=erlang}, + arg=#c_apply{anno=Anno, op=F, args=[X]}, + body=#c_call{anno=Anno, + module=#c_literal{val=erlang}, name=#c_literal{val='++'}, args=[H, - #c_apply{op=Loop, + #c_apply{anno=Anno, + op=Loop, args=[Xs]}]}}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=[]}}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, filter, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, filter, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^filter',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, @@ -800,72 +799,75 @@ call_1(_Call, lists, filter, [Arg1,Arg2], Sub) -> CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true}, body=Xs}, CC3 = #c_clause{pats=[X], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err1]}}, + body=match_fail(Anno, Err1)}, Case = #c_case{arg=B, clauses = [CC1, CC2, CC3]}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, body=#c_let{vars=[B], - arg=#c_apply{op=F, args=[X]}, + arg=#c_apply{anno=Anno, op=F, args=[X]}, body=#c_let{vars=[Xs], - arg=#c_apply{op=Loop, + arg=#c_apply{anno=Anno, + op=Loop, args=[Xs]}, body=Case}}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=[]}}, Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err2]}}, + body=match_fail(Anno, Err2)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, foldl, [Arg1,Arg2,Arg3], Sub) -> +call_1(#c_call{anno=Anno}, lists, foldl, [Arg1,Arg2,Arg3], Sub) -> Loop = #c_var{name={'lists^foldl',2}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, X = #c_var{name='X'}, A = #c_var{name='A'}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_apply{op=Loop, - args=[Xs, #c_apply{op=F, args=[X, A]}]}}, + body=#c_apply{anno=Anno, + op=Loop, + args=[Xs, #c_apply{anno=Anno, + op=F, + args=[X, A]}]}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs, A], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, A, L], arg=#c_values{es=[Arg1, Arg2, Arg3]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L, A]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L, A]}}}, Sub); -call_1(_Call, lists, foldr, [Arg1,Arg2,Arg3], Sub) -> +call_1(#c_call{anno=Anno}, lists, foldr, [Arg1,Arg2,Arg3], Sub) -> Loop = #c_var{name={'lists^foldr',2}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, X = #c_var{name='X'}, A = #c_var{name='A'}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_apply{op=F, args=[X, #c_apply{op=Loop, - args=[Xs, A]}]}}, + body=#c_apply{anno=Anno, + op=F, + args=[X, #c_apply{anno=Anno, + op=Loop, + args=[Xs, A]}]}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs, A], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, A, L], arg=#c_values{es=[Arg1, Arg2, Arg3]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L, A]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L, A]}}}, Sub); -call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) -> +call_1(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) -> Loop = #c_var{name={'lists^mapfoldl',2}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, @@ -876,15 +878,16 @@ call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) -> C1 = #c_clause{pats=[P], guard=#c_literal{val=true}, body=E}, Err = #c_tuple{es=[#c_literal{val='badmatch'}, X]}, C2 = #c_clause{pats=[X], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, #c_case{arg=A, clauses=[C1, C2]} end, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=Match(#c_apply{op=F, args=[X, Avar]}, + body=Match(#c_apply{anno=Anno, op=F, args=[X, Avar]}, #c_tuple{es=[X, Avar]}, %%% Tuple passing version - Match(#c_apply{op=Loop, args=[Xs, Avar]}, + Match(#c_apply{anno=Anno, + op=Loop, + args=[Xs, Avar]}, #c_tuple{es=[Xs, Avar]}, #c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]}) %%% Multiple-value version @@ -902,22 +905,23 @@ call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) -> %%% body=#c_values{es=[#c_literal{val=[]}, A]}}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs, Avar], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, Avar, L], arg=#c_values{es=[Arg1, Arg2, Arg3]}, body=#c_letrec{defs=[{Loop,Fun}], %%% Tuple passing version - body=#c_apply{op=Loop, args=[L, Avar]}}}, + body=#c_apply{anno=Anno, + op=Loop, + args=[L, Avar]}}}, %%% Multiple-value version %%% body=#c_let{vars=[Xs, A], %%% arg=#c_apply{op=Loop, %%% args=[L, A]}, %%% body=#c_tuple{es=[Xs, A]}}}}, Sub); -call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) -> +call_1(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) -> Loop = #c_var{name={'lists^mapfoldr',2}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, @@ -928,15 +932,16 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) -> C1 = #c_clause{pats=[P], guard=#c_literal{val=true}, body=E}, Err = #c_tuple{es=[#c_literal{val='badmatch'}, X]}, C2 = #c_clause{pats=[X], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, #c_case{arg=A, clauses=[C1, C2]} end, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, %%% Tuple passing version - body=Match(#c_apply{op=Loop, args=[Xs, Avar]}, + body=Match(#c_apply{anno=Anno, + op=Loop, + args=[Xs, Avar]}, #c_tuple{es=[Xs, Avar]}, - Match(#c_apply{op=F, args=[X, Avar]}, + Match(#c_apply{anno=Anno, op=F, args=[X, Avar]}, #c_tuple{es=[X, Avar]}, #c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]})) %%% Multiple-value version @@ -955,15 +960,16 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) -> %%% body=#c_values{es=[#c_literal{val=[]}, A]}}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs, Avar], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, Avar, L], arg=#c_values{es=[Arg1, Arg2, Arg3]}, body=#c_letrec{defs=[{Loop,Fun}], %%% Tuple passing version - body=#c_apply{op=Loop, args=[L, Avar]}}}, + body=#c_apply{anno=Anno, + op=Loop, + args=[L, Avar]}}}, %%% Multiple-value version %%% body=#c_let{vars=[Xs, A], %%% arg=#c_apply{op=Loop, @@ -973,6 +979,11 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) -> call_1(#c_call{module=M, name=N}=Call, _, _, As, Sub) -> call_0(Call, M, N, As, Sub). +match_fail(Anno, Arg) -> + #c_primop{anno=Anno, + name=#c_literal{val='match_fail'}, + args=[Arg]}. + %% fold_call(Call, Mod, Name, Args, Sub) -> Expr. %% Try to safely evaluate the call. Just try to evaluate arguments, %% do the call and convert return values to literals. If this @@ -1280,9 +1291,9 @@ eval_setelement_2(Pos, [H|T], NewVal) when Pos > 1 -> %% eval_failure(Call, Reason) -> add_warning(Call, {eval_failure,Reason}), - #c_call{module=#c_literal{val=erlang}, - name=#c_literal{val=error}, - args=[#c_literal{val=Reason}]}. + Call#c_call{module=#c_literal{val=erlang}, + name=#c_literal{val=error}, + args=[#c_literal{val=Reason}]}. %% simplify_apply(Call0, Mod, Func, Args) -> Call %% Simplify an apply/3 to a call if the number of arguments @@ -1742,23 +1753,24 @@ opt_bool_clauses([_|_], _, _) -> opt_bool_not(#c_case{arg=Arg,clauses=Cs0}=Case0) -> case Arg of - #c_call{module=#c_literal{val=erlang}, + #c_call{anno=Anno,module=#c_literal{val=erlang}, name=#c_literal{val='not'}, args=[Expr]} -> - Cs = opt_bool_not(Expr, Cs0), + Cs = opt_bool_not(Anno, Expr, Cs0), Case = Case0#c_case{arg=Expr,clauses=Cs}, opt_bool_not(Case); _ -> opt_bool_case_redundant(Case0) end. -opt_bool_not(Expr, Cs) -> +opt_bool_not(Anno, Expr, Cs) -> Tail = case is_bool_expr(Expr) of false -> [#c_clause{anno=[compiler_generated], pats=[#c_var{name=cor_variable}], guard=#c_literal{val=true}, - body=#c_call{module=#c_literal{val=erlang}, + body=#c_call{anno=Anno, + module=#c_literal{val=erlang}, name=#c_literal{val=error}, args=[#c_literal{val=badarg}]}}]; true -> [] @@ -1957,13 +1969,25 @@ case_tuple_pat([#c_tuple{es=Ps}], Arity) when length(Ps) =:= Arity -> case_tuple_pat([#c_literal{val=T}], Arity) when tuple_size(T) =:= Arity -> Ps = [#c_literal{val=E} || E <- tuple_to_list(T)], {ok,Ps,[]}; -case_tuple_pat([#c_var{anno=A}=V], Arity) -> - Vars = make_vars(A, 1, Arity), - {ok,Vars,[{V,#c_tuple{es=Vars}}]}; +case_tuple_pat([#c_var{anno=Anno0}=V], Arity) -> + Vars = make_vars(Anno0, 1, Arity), + + %% If the entire case statement is evaluated in an effect + %% context (e.g. "case {A,B} of ... end, ok"), there will + %% be a warning that a term is constructed but never used. + %% To avoid that warning, we must annotate the tuple as + %% compiler generated. + + Anno = [compiler_generated|Anno0], + {ok,Vars,[{V,#c_tuple{anno=Anno,es=Vars}}]}; case_tuple_pat([#c_alias{var=V,pat=P}], Arity) -> case case_tuple_pat([P], Arity) of - {ok,Ps,Avs} -> {ok,Ps,[{V,#c_tuple{es=unalias_pat_list(Ps)}}|Avs]}; - error -> error + {ok,Ps,Avs} -> + Anno0 = core_lib:get_anno(P), + Anno = [compiler_generated|Anno0], + {ok,Ps,[{V,#c_tuple{anno=Anno,es=unalias_pat_list(Ps)}}|Avs]}; + error -> + error end; case_tuple_pat(_, _) -> error. diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 2da24b2908..e1a593fffa 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -1820,7 +1820,21 @@ upattern_list([], _, St) -> {[],[],[],[],St}. %% upat_bin([Pat], [KnownVar], State) -> %% {[Pat],[GuardTest],[NewVar],[UsedVar],State}. upat_bin(Es0, Ks, St0) -> - upat_bin(Es0, Ks, [], St0). + {Es1,Pg,Pv,Pu0,St1} = upat_bin(Es0, Ks, [], St0), + + %% In a clause such as <<Sz:8,V:Sz>> in a function head, Sz will both + %% be new and used; a situation that is not handled properly by + %% uclause/4. (Basically, since Sz occurs in two sets that are + %% subtracted from each other, Sz will not be added to the list of + %% known variables and will seem to be new the next time it is + %% used in a match.) + %% Since the variable Sz really is new (it does not use a + %% value bound prior to the binary matching), Sz should only be + %% included in the set of new variables. Thus we should take it + %% out of the set of used variables. + + Pu1 = subtract(Pu0, intersection(Pv, Pu0)), + {Es1,Pg,Pv,Pu1,St1}. %% upat_bin([Pat], [KnownVar], [LocalVar], State) -> %% {[Pat],[GuardTest],[NewVar],[UsedVar],State}. @@ -1832,35 +1846,36 @@ upat_bin([], _, _, St) -> {[],[],[],[],St}. %% upat_element(Segment, [KnownVar], [LocalVar], State) -> -%% {Segment,[GuardTest],[NewVar],[UsedVar],[LocalVar],State} -upat_element(#c_bitstr{val=H0,size=Sz}=Seg, Ks, Bs, St0) -> - {H1,Hg,Hv,[],St1} = upattern(H0, Ks, St0), - Bs1 = case H0 of - #c_var{name=Hname} -> - case H1 of +%% {Segment,[GuardTest],[NewVar],[UsedVar],[LocalVar],State} +upat_element(#c_bitstr{val=H0,size=Sz0}=Seg, Ks, Bs0, St0) -> + {H1,Hg,Hv,[],St1} = upattern(H0, Ks, St0), + Bs1 = case H0 of #c_var{name=Hname} -> - Bs; - #c_var{name=Other} -> - [{Hname, Other}|Bs] - end; - _ -> - Bs - end, - {Sz1, Us} = case Sz of - #c_var{name=Vname} -> - rename_bitstr_size(Vname, Bs); - _Other -> {Sz, []} - end, - {Seg#c_bitstr{val=H1, size=Sz1},Hg,Hv,Us,Bs1,St1}. - -rename_bitstr_size(V, [{V, N}|_]) -> - New = #c_var{name=N}, - {New, [N]}; + case H1 of + #c_var{name=Hname} -> + Bs0; + #c_var{name=Other} -> + [{Hname,Other}|Bs0] + end; + _ -> + Bs0 + end, + {Sz1,Us} = case Sz0 of + #c_var{name=Vname} -> + rename_bitstr_size(Vname, Bs0); + _Other -> + {Sz0,[]} + end, + {Seg#c_bitstr{val=H1,size=Sz1},Hg,Hv,Us,Bs1,St1}. + +rename_bitstr_size(V, [{V,N}|_]) -> + New = #c_var{name=N}, + {New,[N]}; rename_bitstr_size(V, [_|Rest]) -> - rename_bitstr_size(V, Rest); + rename_bitstr_size(V, Rest); rename_bitstr_size(V, []) -> - Old = #c_var{name=V}, - {Old, [V]}. + Old = #c_var{name=V}, + {Old,[V]}. used_in_any(Les) -> foldl(fun (Le, Ns) -> union((get_anno(Le))#a.us, Ns) end, diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index 934bf39393..fe713fd019 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -157,7 +157,7 @@ release_tests_spec: make_emakefile $(EMAKEFILE) $(ERL_FILES) $(CORE_FILES) $(RELSYSDIR) $(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \ $(INLINE_ERL_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index 1e3c670fb8..9184e14cb2 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -142,7 +142,14 @@ otp_5269(Config) when is_list(Config) -> [X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end, %% "binsize variable" ^ [1,2]), - + ?line check(fun() -> + (fun (<<A:1/binary, B:8/integer, _C:B/binary>>) -> + case A of + B -> wrong; + _ -> ok + end + end)(<<1,2,3,4>>) end, + ok), ok. null_fields(Config) when is_list(Config) -> diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl index 8cc3ca4199..dd18a6e1a3 100644 --- a/lib/compiler/test/warnings_SUITE.erl +++ b/lib/compiler/test/warnings_SUITE.erl @@ -453,6 +453,16 @@ effect(Config) when is_list(Config) -> true -> ok end, ok. + + m8(A, B) -> + case {A,B} of + V -> V + end, + ok. + + m9(Bs) -> + [{B,ok} = {B,foo:bar(B)} || B <- Bs], + ok. ">>, [], {warnings,[{5,sys_core_fold,{no_effect,{erlang,is_integer,1}}}, |