diff options
-rw-r--r-- | erts/emulator/beam/utils.c | 6 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_bif0.c | 39 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_bif0.tab | 3 | ||||
-rw-r--r-- | erts/emulator/test/map_SUITE.erl | 19 | ||||
-rw-r--r-- | lib/compiler/src/compile.erl | 2 | ||||
-rw-r--r-- | lib/compiler/src/sys_core_fold.erl | 12 | ||||
-rw-r--r-- | lib/compiler/src/sys_pre_expand.erl | 7 | ||||
-rw-r--r-- | lib/compiler/src/v3_core.erl | 11 | ||||
-rw-r--r-- | lib/compiler/test/fun_SUITE.erl | 8 | ||||
-rw-r--r-- | lib/compiler/test/map_SUITE.erl | 11 | ||||
-rw-r--r-- | lib/compiler/test/record_SUITE.erl | 8 | ||||
-rw-r--r-- | lib/kernel/src/hipe_unified_loader.erl | 24 | ||||
-rw-r--r-- | lib/ssl/doc/src/ssl.xml | 28 | ||||
-rw-r--r-- | lib/ssl/src/ssl.erl | 8 | ||||
-rw-r--r-- | lib/ssl/test/ssl_basic_SUITE.erl | 14 | ||||
-rw-r--r-- | lib/stdlib/src/qlc_pt.erl | 11 | ||||
-rw-r--r-- | lib/stdlib/test/qlc_SUITE.erl | 19 |
17 files changed, 182 insertions, 48 deletions
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 5b43d25e3c..738f793020 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -2125,7 +2125,11 @@ tailrecur_ne: if (!is_boxed(b) || *boxed_val_rel(b,b_base) != *aa) goto not_equal; bb = map_val_rel(b,b_base); - if ((sz = map_get_size((map_t*)aa)) == 0) goto pop_next; + sz = map_get_size((map_t*)aa); + + if (sz != map_get_size((map_t*)bb)) goto not_equal; + if (sz == 0) goto pop_next; + aa += 2; bb += 2; sz += 1; /* increment for tuple-keys */ diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index fa99c817f0..2497d51df1 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -1101,9 +1101,9 @@ BIF_RETTYPE hipe_bifs_make_fun_3(BIF_ALIST_3) #endif /* - * args: Nativecodeaddress, Module, {Uniq, Index, BeamAddress} + * args: Module, {Uniq, Index, BeamAddress} */ -BIF_RETTYPE hipe_bifs_make_fe_3(BIF_ALIST_3) +BIF_RETTYPE hipe_bifs_get_fe_2(BIF_ALIST_2) { Eterm mod; Uint index; @@ -1111,20 +1111,15 @@ BIF_RETTYPE hipe_bifs_make_fe_3(BIF_ALIST_3) void *beam_address; ErlFunEntry *fe; Eterm *tp; - void *native_address; - - native_address = term_to_address(BIF_ARG_1); - if (!native_address) - BIF_ERROR(BIF_P, BADARG); - if (is_not_atom(BIF_ARG_2)) + if (is_not_atom(BIF_ARG_1)) BIF_ERROR(BIF_P, BADARG); - mod = BIF_ARG_2; + mod = BIF_ARG_1; - if (is_not_tuple(BIF_ARG_3) || - (arityval(*tuple_val(BIF_ARG_3)) != 3)) + if (is_not_tuple(BIF_ARG_2) || + (arityval(*tuple_val(BIF_ARG_2)) != 3)) BIF_ERROR(BIF_P, BADARG); - tp = tuple_val(BIF_ARG_3); + tp = tuple_val(BIF_ARG_2); if (term_to_Uint(tp[1], &uniq) == 0) BIF_ERROR(BIF_P, BADARG); if (term_to_Uint(tp[2], &index) == 0) @@ -1144,10 +1139,28 @@ BIF_RETTYPE hipe_bifs_make_fe_3(BIF_ALIST_3) printf("no fun entry for %s %ld:%ld\n", atom_buf, uniq, index); BIF_ERROR(BIF_P, BADARG); } + BIF_RET(address_to_term((void *)fe, BIF_P)); +} + +/* + * args: FE, Nativecodeaddress + */ +BIF_RETTYPE hipe_bifs_set_native_address_in_fe_2(BIF_ALIST_2) +{ + ErlFunEntry *fe; + void *native_address; + + fe = (ErlFunEntry *)term_to_address(BIF_ARG_1); + if (!fe) + BIF_ERROR(BIF_P, BADARG); + native_address = term_to_address(BIF_ARG_2); + if (!native_address) + BIF_ERROR(BIF_P, BADARG); + fe->native_address = native_address; if (erts_refc_dectest(&fe->refc, 0) == 0) erts_erase_fun_entry(fe); - BIF_RET(address_to_term((void *)fe, BIF_P)); + BIF_RET(am_true); } #if 0 /* XXX: unused */ diff --git a/erts/emulator/hipe/hipe_bif0.tab b/erts/emulator/hipe/hipe_bif0.tab index ce641365e9..2514b1c3a5 100644 --- a/erts/emulator/hipe/hipe_bif0.tab +++ b/erts/emulator/hipe/hipe_bif0.tab @@ -69,7 +69,8 @@ bif hipe_bifs:atom_to_word/1 bif hipe_bifs:term_to_word/1 #bif hipe_bifs:make_fun/3 -bif hipe_bifs:make_fe/3 +bif hipe_bifs:get_fe/2 +bif hipe_bifs:set_native_address_in_fe/2 #bif hipe_bifs:make_native_stub/2 bif hipe_bifs:find_na_or_make_stub/2 diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl index 8cc5621181..753d6f7727 100644 --- a/erts/emulator/test/map_SUITE.erl +++ b/erts/emulator/test/map_SUITE.erl @@ -29,6 +29,7 @@ t_guard_receive/1, t_guard_fun/1, t_list_comprehension/1, t_map_sort_literals/1, + t_map_equal/1, %t_size/1, t_map_size/1, @@ -74,6 +75,7 @@ all() -> [ t_update_assoc,t_update_exact, t_guard_bifs, t_guard_sequence, t_guard_update, t_guard_receive,t_guard_fun, t_list_comprehension, + t_map_equal, t_map_sort_literals, %% Specific Map BIFs @@ -450,6 +452,23 @@ t_map_sort_literals(Config) when is_list(Config) -> ok. +t_map_equal(Config) when is_list(Config) -> + true = id(#{}) =:= id(#{}), + false = id(#{}) =:= id(#{a=>1}), + false = id(#{a=>1}) =:= id(#{}), + true = id(#{ "a" => "hi", b => 134 }) =:= id(#{ b => 134,"a" => "hi"}), + + false = id(#{ a => 1 }) =:= id(#{ a => 2}), + false = id(#{ a => 2 }) =:= id(#{ a => 1}), + false = id(#{ a => 2, b => 1 }) =:= id(#{ a => 1, b => 3}), + false = id(#{ a => 1, b => 1 }) =:= id(#{ a => 1, b => 3}), + + true = id(#{ a => 1 }) =:= id(#{ a => 1}), + true = id(#{ "a" => 2 }) =:= id(#{ "a" => 2}), + true = id(#{ "a" => 2, b => 3 }) =:= id(#{ "a" => 2, b => 3}), + true = id(#{ a => 1, b => 3, c => <<"wat">> }) =:= id(#{ a => 1, b => 3, c=><<"wat">>}), + ok. + %% BIFs t_bif_map_get(Config) when is_list(Config) -> diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index b88f9792a5..9030dd998b 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -246,7 +246,7 @@ format_error_reason({Reason, Stack}) when is_list(Stack) -> end, FormatFun = fun (Term, _) -> io_lib:format("~tp", [Term]) end, [io_lib:format("~tp", [Reason]),"\n\n", - lib:format_stacktrace(1, erlang:get_stacktrace(), StackFun, FormatFun)]; + lib:format_stacktrace(1, Stack, StackFun, FormatFun)]; format_error_reason(Reason) -> io_lib:format("~tp", [Reason]). diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index eb9c302334..4ef345f563 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -2346,10 +2346,16 @@ is_safe_bool_expr(Core, Sub) -> is_safe_bool_expr_1(Core, Sub, gb_sets:empty()). is_safe_bool_expr_1(#c_call{module=#c_literal{val=erlang}, - name=#c_literal{val=is_record}, - args=[_,_]}, - _Sub, _BoolVars) -> + name=#c_literal{val=is_record}, + args=[A,#c_literal{val=Tag},#c_literal{val=Size}]}, + Sub, _BoolVars) when is_atom(Tag), is_integer(Size) -> + is_safe_simple(A, Sub); +is_safe_bool_expr_1(#c_call{module=#c_literal{val=erlang}, + name=#c_literal{val=is_record}}, + _Sub, _BoolVars) -> %% The is_record/2 BIF is NOT allowed in guards. + %% The is_record/3 BIF where its second argument is not an atom or its third + %% is not an integer is NOT allowed in guards. %% %% NOTE: Calls like is_record(Expr, LiteralTag), where LiteralTag %% is a literal atom referring to a defined record, have already diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl index 9998043013..91a46a20fe 100644 --- a/lib/compiler/src/sys_pre_expand.erl +++ b/lib/compiler/src/sys_pre_expand.erl @@ -331,9 +331,10 @@ expr({tuple,Line,Es0}, St0) -> expr({map,Line,Es0}, St0) -> {Es1,St1} = expr_list(Es0, St0), {{map,Line,Es1},St1}; -expr({map,Line,Var,Es0}, St0) -> - {Es1,St1} = expr_list(Es0, St0), - {{map,Line,Var,Es1},St1}; +expr({map,Line,E0,Es0}, St0) -> + {E1,St1} = expr(E0, St0), + {Es1,St2} = expr_list(Es0, St1), + {{map,Line,E1,Es1},St2}; expr({map_field_assoc,Line,K0,V0}, St0) -> {K,St1} = expr(K0, St0), {V,St2} = expr(V0, St1), diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index a50b46bd7b..d3db395995 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -623,7 +623,7 @@ expr({call,Lc,{atom,Lf,F},As0}, St0) -> Op = #c_var{anno=lineno_anno(Lf, St1),name={F,length(As1)}}, {#iapply{anno=#a{anno=lineno_anno(Lc, St1)},op=Op,args=As1},Aps,St1}; expr({call,L,FunExp,As0}, St0) -> - {Fun,Fps,St1} = safe(FunExp, St0), + {Fun,Fps,St1} = safe_fun(length(As0), FunExp, St0), {As1,Aps,St2} = safe_list(As0, St1), Lanno = lineno_anno(L, St2), {#iapply{anno=#a{anno=Lanno},op=Fun,args=As1},Fps ++ Aps,St2}; @@ -1408,6 +1408,15 @@ safe(E0, St0) -> {Se,Sps,St2} = force_safe(E1, St1), {Se,Eps ++ Sps,St2}. +safe_fun(A0, E0, St0) -> + case safe(E0, St0) of + {#c_var{name={_,A1}}=E1,Eps,St1} when A1 =/= A0 -> + {V,St2} = new_var(St1), + {V,Eps ++ [#iset{var=V,arg=E1}],St2}; + Result -> + Result + end. + safe_list(Es, St) -> foldr(fun (E, {Ces,Esp,St0}) -> {Ce,Ep,St1} = safe(E, St0), diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl index e35692efd1..25b7f677b5 100644 --- a/lib/compiler/test/fun_SUITE.erl +++ b/lib/compiler/test/fun_SUITE.erl @@ -21,7 +21,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, test1/1,overwritten_fun/1,otp_7202/1,bif_fun/1, - external/1,eep37/1]). + external/1,eep37/1,badarity/1]). %% Internal export. -export([call_me/1]). @@ -32,7 +32,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> test_lib:recompile(?MODULE), - [test1,overwritten_fun,otp_7202,bif_fun,external,eep37]. + [test1,overwritten_fun,otp_7202,bif_fun,external,eep37,badarity]. groups() -> []. @@ -206,5 +206,9 @@ eep37(Config) when is_list(Config) -> 50 = UnusedName(8), ok. +badarity(Config) when is_list(Config) -> + {'EXIT',{{badarity,{_,[]}},_}} = (catch (fun badarity/1)()), + ok. + id(I) -> I. diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl index f47a94e033..3639192a51 100644 --- a/lib/compiler/test/map_SUITE.erl +++ b/lib/compiler/test/map_SUITE.erl @@ -42,7 +42,8 @@ t_build_and_match_val/1, %% errors in 17.0-rc1 - t_update_values/1 + t_update_values/1, + t_expand_map_update/1 ]). suite() -> []. @@ -68,7 +69,8 @@ all() -> [ t_build_and_match_val, %% errors in 17.0-rc1 - t_update_values + t_update_values, + t_expand_map_update ]. groups() -> []. @@ -273,6 +275,11 @@ t_update_values(Config) when is_list(Config) -> end, {none, none, #{val1=>none,val2=>none}},List), ok. +t_expand_map_update(Config) when is_list(Config) -> + M = #{<<"hello">> => <<"world">>}#{<<"hello">> := <<"les gens">>}, + #{<<"hello">> := <<"les gens">>} = M, + ok. + check_val(#{val1:=V1, val2:=V2},V1,V2) -> ok. get_val(#{ "wazzup" := _, val := V}) -> V; diff --git a/lib/compiler/test/record_SUITE.erl b/lib/compiler/test/record_SUITE.erl index c9f5a2053e..f736e14bf6 100644 --- a/lib/compiler/test/record_SUITE.erl +++ b/lib/compiler/test/record_SUITE.erl @@ -369,6 +369,14 @@ record_test_3(Config) when is_list(Config) -> ?line false = is_record(id(#barf{}), id(barf), id(42)), ?line false = is_record(id(#barf{}), id(foo), id(6)), + Rec = id(#barf{}), + Good = id(barf), + Bad = id(foo), + Size = id(6), + + true = is_record(Rec, Good, Size) orelse error, + error = is_record(Rec, Bad, Size) orelse error, + ok. record_access_in_guards(Config) when is_list(Config) -> diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index e111cb800e..976d5e35cb 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -203,6 +203,7 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) -> "please regenerate native code for this runtime system\n", [Mod]), bad_crc; true -> + put(closures_to_patch, []), %% Create data segment {ConstAddr,ConstMap2} = create_data_segment(ConstAlign, ConstSize, ConstMap), @@ -224,14 +225,23 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) -> %% Patch all dynamic references in the code. %% Function calls, Atoms, Constants, System calls ok = patch(Refs, CodeAddress, ConstMap2, Addresses, TrampolineMap), + %% Tell the system where the loaded funs are. %% (patches the BEAM code to redirect to native.) case Beam of [] -> + %% This module was previously loaded as BEAM code during system + %% start-up before the code server has started (-enable-native-libs + %% is active), so we must now patch the pre-existing entries in the + %% fun table with the native code addresses for all closures. + lists:foreach(fun({FE, DestAddress}) -> + hipe_bifs:set_native_address_in_fe(FE, DestAddress) + end, erase(closures_to_patch)), export_funs(Addresses), ok; BeamBinary when is_binary(BeamBinary) -> %% Find all closures in the code. + [] = erase(closures_to_patch), %Clean up, assertion. ClosurePatches = find_closure_patches(Refs), AddressesOfClosuresToPatch = calculate_addresses(ClosurePatches, CodeAddress, Addresses), @@ -245,6 +255,9 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) -> %% The call to export_funs/1 above updated the native addresses %% for the targets, so passing 'Addresses' is not needed. redirect(ReferencesToPatch), + %% Final clean up. + _ = erase(hipe_patch_closures), + _ = erase(hipe_assert_code_area), ?debug_msg("****************Loader Finished****************\n", []), {module,Mod} % for compatibility with code:load_file/1 end. @@ -562,12 +575,17 @@ patch_closure(DestMFA, Uniq, Index, Address, Addresses) -> case get(hipe_patch_closures) of false -> []; % This is taken care of when registering the module. - true -> % We are not loading a module patch these closures + true -> + %% We are replacing a previosly loaded BEAM module with native code, + %% so we must reference the pre-existing entries in the fun table + %% from the native code. We must delay actually patching the native + %% address into the fun entry to ensure that the native code cannot + %% be called until it has been completely fixed up. RemoteOrLocal = local, % closure code refs are local DestAddress = get_native_address(DestMFA, Addresses, RemoteOrLocal), BEAMAddress = hipe_bifs:fun_to_address(DestMFA), - FE = hipe_bifs:make_fe(DestAddress, mod(DestMFA), - {Uniq, Index, BEAMAddress}), + FE = hipe_bifs:get_fe(mod(DestMFA), {Uniq, Index, BEAMAddress}), + put(closures_to_patch, [{FE,DestAddress}|get(closures_to_patch)]), ?debug_msg("Patch FE(~w) to 0x~.16b->0x~.16b (emu:0x~.16b)\n", [DestMFA, FE, DestAddress, BEAMAddress]), ?ASSERT(assert_local_patch(Address)), diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 910dca3889..4bc1a9a644 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1999</year><year>2013</year> + <year>1999</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -184,12 +184,6 @@ <item> The DER encoded trusted certificates. If this option is supplied it will override the cacertfile option.</item> - <tag>{cacertfile, path()}</tag> - <item>Path to file containing PEM encoded - CA certificates (trusted certificates used for verifying a peer - certificate). May be omitted if you do not want to verify - the peer.</item> - <tag>{ciphers, ciphers()}</tag> <item>The cipher suites that should be supported. The function <c>cipher_suites/0</c> can be used to find all ciphers that are @@ -354,7 +348,13 @@ fun(srp, Username :: string(), UserState :: term()) -> <item>Specifies if client should try to reuse sessions when possible. </item> - + + <tag>{cacertfile, path()}</tag> + <item>The path to a file containing PEM encoded CA certificates. The CA + certificates are used during server authentication and when building the + client certificate chain. + </item> + <tag>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()]}}</tag> <tag>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()], Default :: binary()}}</tag> <item> @@ -403,7 +403,17 @@ fun(srp, Username :: string(), UserState :: term()) -> meaning in the server than in the client.</p> <taglist> - + + <tag>{cacertfile, path()}</tag> + <item>The path to a file containing PEM encoded CA + certificates. The CA certificates are used to build the server + certificate chain, and for client authentication. Also the CAs + are used in the list of acceptable client CAs passed to the + client when a certificate is requested. May be omitted if there + is no need to verify the client and if there are not any + intermediate CAs for the server certificate. + </item> + <tag>{dh, der_encoded()}</tag> <item>The DER encoded Diffie Hellman parameters. If this option is supplied it will override the dhfile option. diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index c3bdeb1a54..d46c05c5f3 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -557,6 +557,7 @@ do_connect(Address, Port, handle_options(Opts0, _Role) -> Opts = proplists:expand([{binary, [{mode, binary}]}, {list, [{mode, list}]}], Opts0), + assert_proplist(Opts), ReuseSessionFun = fun(_, _, _, _) -> true end, DefaultVerifyNoneFun = @@ -1042,3 +1043,10 @@ connection_sup(dtls_connection) -> binary_filename(FileName) -> Enc = file:native_name_encoding(), unicode:characters_to_binary(FileName, unicode, Enc). + +assert_proplist([]) -> + true; +assert_proplist([{Key,_} | Rest]) when is_atom(Key) -> + assert_proplist(Rest); +assert_proplist([Value | _]) -> + throw({option_not_a_key_value_tuple, Value}). diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 523760aba6..64a93440c7 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -96,6 +96,7 @@ basic_tests() -> options_tests() -> [der_input, misc_ssl_options, + ssl_options_not_proplist, socket_options, invalid_inet_get_option, invalid_inet_get_option_not_list, @@ -990,7 +991,7 @@ misc_ssl_options(Config) when is_list(Config) -> ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - %% Chek that ssl options not tested elsewhere are filtered away e.i. not passed to inet. + %% Check that ssl options not tested elsewhere are filtered away e.i. not passed to inet. TestOpts = [{depth, 1}, {key, undefined}, {password, []}, @@ -1018,6 +1019,17 @@ misc_ssl_options(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- +ssl_options_not_proplist() -> + [{doc,"Test what happens if an option is not a key value tuple"}]. + +ssl_options_not_proplist(Config) when is_list(Config) -> + BadOption = {client_preferred_next_protocols, + client, [<<"spdy/3">>,<<"http/1.1">>], <<"http/1.1">>}, + {option_not_a_key_value_tuple, BadOption} = + ssl:connect("twitter.com", 443, [binary, {active, false}, + BadOption]). + +%%-------------------------------------------------------------------- versions() -> [{doc,"Test API function versions/0"}]. diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl index c26764eb18..b6bb758dfb 100644 --- a/lib/stdlib/src/qlc_pt.erl +++ b/lib/stdlib/src/qlc_pt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2013. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1218,13 +1218,14 @@ lu_skip(ColConstants, FilterData, PatternFrame, PatternVars, %% column, the filter will not be skipped. %% (an example: {X=1} <- ..., X =:= 1). length(D = Cols -- PatternColumns) =:= 1, - Frame <- SFs, - begin + {{_,Col} = Column, Constants} <- D, + %% Check that the following holds for all frames. + lists:all( + fun(Frame) -> %% The column is compared/matched against a constant. %% If there are no more comparisons/matches then %% the filter can be replaced by the lookup of %% the constant. - [{{_,Col} = Column, Constants}] = D, {VarI, FrameI} = unify_column(Frame, PV, Col, BindFun, Imported), VarValues = deref_skip(VarI, FrameI, LookupOp, Imported), @@ -1253,7 +1254,7 @@ lu_skip(ColConstants, FilterData, PatternFrame, PatternVars, length(VarValues) =< 1 andalso (Constants -- LookedUpConstants =:= []) andalso bindings_is_subset(Frame, F2, Imported) - end], + end, SFs)], ColFils = family_list(ColFil), %% The skip tag 'all' means that all filters are covered by the lookup. %% It does not imply that there is only one generator as is the case diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl index 2846657c09..37fbb5267b 100644 --- a/lib/stdlib/test/qlc_SUITE.erl +++ b/lib/stdlib/test/qlc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2013. All Rights Reserved. +%% Copyright Ericsson AB 2004-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -72,7 +72,7 @@ otp_5644/1, otp_5195/1, otp_6038_bug/1, otp_6359/1, otp_6562/1, otp_6590/1, otp_6673/1, otp_6964/1, otp_7114/1, otp_7238/1, - otp_7232/1, otp_7552/1, otp_6674/1, otp_7714/1, + otp_7232/1, otp_7552/1, otp_6674/1, otp_7714/1, otp_11758/1, manpage/1, @@ -142,7 +142,7 @@ groups() -> {tickets, [], [otp_5644, otp_5195, otp_6038_bug, otp_6359, otp_6562, otp_6590, otp_6673, otp_6964, otp_7114, otp_7232, - otp_7238, otp_7552, otp_6674, otp_7714]}, + otp_7238, otp_7552, otp_6674, otp_7714, otp_11758]}, {compat, [], [backward, forward]}]. init_per_suite(Config) -> @@ -6670,6 +6670,19 @@ otp_7714(Config) when is_list(Config) -> ets:delete(E2)">>], ?line run(Config, Ts). +otp_11758(doc) -> + "OTP-11758. Bug."; +otp_11758(suite) -> []; +otp_11758(Config) when is_list(Config) -> + Ts = [<<"T = ets:new(r, [{keypos, 2}]), + L = [{rrr, xxx, aaa}, {rrr, yyy, bbb}], + true = ets:insert(T, L), + QH = qlc:q([{rrr, B, C} || {rrr, B, C} <- ets:table(T), + (B =:= xxx) or (B =:= yyy) and (C =:= aaa)]), + [{rrr,xxx,aaa}] = qlc:e(QH), + ets:delete(T)">>], + run(Config, Ts). + otp_6674(doc) -> "OTP-6674. match/comparison."; otp_6674(suite) -> []; |