From 8784fdc88e32979ee2186500735ff4ada6190e15 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 3 Feb 2013 02:48:04 +0100 Subject: Forbid multiple values in Core Erlang sequence arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It does not make sense to return multiple values from a sequence argument and the Kernel Erlang passes can't cope with it. The linting pass now knows how to detect this kind of defunct code and the Core code folding pass is changed to not generate code like that when optimizing away multiple-valued lets in effect mode. Reported-by: José Valim --- lib/compiler/src/core_lint.erl | 2 +- lib/compiler/src/sys_core_fold.erl | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl index 8b688df830..1e8983f594 100644 --- a/lib/compiler/src/core_lint.erl +++ b/lib/compiler/src/core_lint.erl @@ -309,7 +309,7 @@ expr(#c_fun{vars=Vs,body=B}, Def, Rt, St0) -> {Vvs,St1} = variable_list(Vs, St0), return_match(Rt, 1, body(B, union(Vvs, Def), any, St1)); expr(#c_seq{arg=Arg,body=B}, Def, Rt, St0) -> - St1 = expr(Arg, Def, any, St0), %Ignore values + St1 = expr(Arg, Def, 1, St0), body(B, Def, Rt, St1); expr(#c_let{vars=Vs,arg=Arg,body=B}, Def, Rt, St0) -> St1 = body(Arg, Def, let_varcount(Vs), St0), %This is a body diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index d5fec0c869..c35eef58de 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -132,7 +132,12 @@ body(Body, Sub) -> body(#c_values{anno=A,es=Es0}, Ctxt, Sub) -> Es1 = expr_list(Es0, Ctxt, Sub), - #c_values{anno=A,es=Es1}; + case Ctxt of + value -> + #c_values{anno=A,es=Es1}; + effect -> + make_effect_seq(Es1, Sub) + end; body(E, Ctxt, Sub) -> ?ASSERT(verify_scope(E, Sub)), expr(E, Ctxt, Sub). -- cgit v1.2.3 From 5773a7861a1888c8ae6e6f17ca847b121820f248 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 4 Feb 2013 12:15:04 +0100 Subject: Add two tests for unused multiple values in effect context --- lib/compiler/test/Makefile | 1 + lib/compiler/test/core_fold_SUITE.erl | 44 +++++++++++++++++++++- .../test/unused_multiple_values_error.core | 11 ++++++ 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 lib/compiler/test/unused_multiple_values_error.core diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index b9c5be09ce..51b3064589 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -75,6 +75,7 @@ INLINE= \ CORE_MODULES = \ bs_shadowed_size_var \ + unused_multiple_values_error \ nested_call_in_case diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index 53a65d8d17..a479f00221 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -21,7 +21,8 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, t_element/1,setelement/1,t_length/1,append/1,t_apply/1,bifs/1, - eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1]). + eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1, + unused_multiple_values_error/1,unused_multiple_values/1]). -export([foo/0,foo/1,foo/2,foo/3]). @@ -36,7 +37,8 @@ all() -> groups() -> [{p,test_lib:parallel(), [t_element,setelement,t_length,append,t_apply,bifs, - eq,nested_call_in_case,guard_try_catch,coverage]}]. + eq,nested_call_in_case,guard_try_catch,coverage, + unused_multiple_values_error,unused_multiple_values]}]. init_per_suite(Config) -> @@ -283,3 +285,41 @@ cover_is_safe_bool_expr(X) -> end. id(I) -> I. + +unused_multiple_values_error(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + Dir = filename:dirname(code:which(?MODULE)), + Core = filename:join(Dir, "unused_multiple_values_error"), + Opts = [no_copt,clint,return,from_core,{outdir,PrivDir} + |test_lib:opt_opts(?MODULE)], + {error,[{unused_multiple_values_error, + [{core_lint,{return_mismatch,{hello,1}}}]}], + []} = c:c(Core, Opts), + ok. + +unused_multiple_values(Config) when is_list(Config) -> + put(unused_multiple_values, []), + [false] = test_unused_multiple_values(false), + [b,a,{a,b},false] = test_unused_multiple_values({a,b}), + ok. + +test_unused_multiple_values(X) -> + ok = do_unused_multiple_values(X), + get(unused_multiple_values). + +do_unused_multiple_values(X) -> + case do_something(X) of + false -> + A = false; + Res -> + {A,B} = Res, + do_something(A), + do_something(B) + end, + _ThisShouldNotFail = A, + ok. + +do_something(I) -> + put(unused_multiple_values, + [I|get(unused_multiple_values)]), + I. diff --git a/lib/compiler/test/unused_multiple_values_error.core b/lib/compiler/test/unused_multiple_values_error.core new file mode 100644 index 0000000000..e06587c936 --- /dev/null +++ b/lib/compiler/test/unused_multiple_values_error.core @@ -0,0 +1,11 @@ +module 'unused_multiple_values_error' ['hello'/1] + attributes [] +'hello'/1 = + fun (_cor0) -> + do + case _cor0 of + <_cor0> when 'true' -> + <'ok','ok'> + end + 'ok' +end -- cgit v1.2.3