From c89ada7517420ce9065840ea857a0009418ce2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 11 Feb 2014 08:31:37 +0100 Subject: Teach sys_core_fold:eval_case/2 to cope with handwritten Core Erlang Starting in e12b7d5331c58b41db06cadfa4af75b78b62a2b1, sys_core_fold:eval_case/2 will crash on handwritten but legal Core Erlang programs such as: case let = Arg in {'x',Var} of {x,X} -> X end The problem is that the only clause *is* guaranteed to match, but cerl_clauses:match_list/2 does not understand that; all it can say is that the clause *may* match. In those circumstances, we will need to keep the case. Also make sure that we keep the case if the guard is something else than 'true'. That is not strictly necessary, because in a legal Core Erlang program the guard in the last clause in a case must always evaluate to 'true', so removing the guard test would still leave the program correct. Keeping the guard, however, will make it somewhat easier to debug an incorrect Core Erlang program. (The unsafe_case test case has guard test in the only clause in a case, so we don't need to write a new test case to test that.) Reported-by: Anthony Ramine --- lib/compiler/src/sys_core_fold.erl | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'lib/compiler/src/sys_core_fold.erl') diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 99721f767d..500d431afe 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -1940,7 +1940,9 @@ opt_bool_case_guard(Arg, [#c_clause{pats=[#c_literal{val=false}]}=Fc,Tc]) -> %% last clause is guaranteed to match so if there is only one clause %% with a pattern containing only variables then rewrite to a let. -eval_case(#c_case{arg=E,clauses=[#c_clause{pats=Ps0,body=B}]}, Sub) -> +eval_case(#c_case{arg=E,clauses=[#c_clause{pats=Ps0, + guard=#c_literal{val=true}, + body=B}]}=Case, Sub) -> Es = case cerl:is_c_values(E) of true -> cerl:values_es(E); false -> [E] @@ -1964,11 +1966,19 @@ eval_case(#c_case{arg=E,clauses=[#c_clause{pats=Ps0,body=B}]}, Sub) -> %% let = in ... %% Vs = make_vars([], length(Es)), - {true,Bs} = cerl_clauses:match_list(Ps0, Vs), - {Ps,As} = unzip(Bs), - InnerLet = cerl:c_let(Ps, core_lib:make_values(As), B), - Let = cerl:c_let(Vs, E, InnerLet), - expr(Let, sub_new(Sub)); + case cerl_clauses:match_list(Ps0, Vs) of + {false,_} -> + %% This can only happen if the Core Erlang code is + %% handwritten or generated by another code generator + %% than v3_core. Assuming that the Core Erlang program + %% is correct, the clause will always match at run-time. + Case; + {true,Bs} -> + {Ps,As} = unzip(Bs), + InnerLet = cerl:c_let(Ps, core_lib:make_values(As), B), + Let = cerl:c_let(Vs, E, InnerLet), + expr(Let, sub_new(Sub)) + end; eval_case(Case, _) -> Case. %% case_opt(CaseArg, [Clause]) -> {CaseArg,[Clause]}. -- cgit v1.2.3