diff options
author | Hans Bolinder <[email protected]> | 2018-08-27 13:14:29 +0200 |
---|---|---|
committer | Hans Bolinder <[email protected]> | 2018-08-28 08:27:52 +0200 |
commit | fd9b5ae4193fbab66093c88728c0dbeaa3b57312 (patch) | |
tree | fd3f8b46afb4b5745f0f9a02b2498cad7826bedc /lib/compiler | |
parent | 00401985f1c9227b6e94309ae5526c2ebf341527 (diff) | |
download | otp-fd9b5ae4193fbab66093c88728c0dbeaa3b57312.tar.gz otp-fd9b5ae4193fbab66093c88728c0dbeaa3b57312.tar.bz2 otp-fd9b5ae4193fbab66093c88728c0dbeaa3b57312.zip |
dialyzer: Improve handling of complex guards
See also https://bugs.erlang.org/browse/ERL-680.
The right associative short circuit expressions 'andalso' and 'orelse'
are expanded by the Compiler (see v3_core) into 'case' expressions. If
parentheses are used to enforce left associativeness, variables are
introduced, and the time needed by Dialyzer increases exponentially.
Rather than trying to fix Dialyzer itself, v3_core now rewrites
repeated use of 'andalso' ('orelse') into right associative
expressions before creating the 'case' expressions.
Diffstat (limited to 'lib/compiler')
-rw-r--r-- | lib/compiler/src/v3_core.erl | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 3b746ab5bf..c9517c3e51 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -328,14 +328,16 @@ gexpr({protect,Line,Arg}, Bools0, St0) -> Anno = lineno_anno(Line, St), {#iprotect{anno=#a{anno=Anno},body=Eps++[E]},[],Bools0,St} end; -gexpr({op,L,'andalso',E1,E2}, Bools, St0) -> +gexpr({op,_,'andalso',_,_}=E0, Bools, St0) -> + {op,L,'andalso',E1,E2} = right_assoc(E0, 'andalso', St0), Anno = lineno_anno(L, St0), {#c_var{name=V0},St} = new_var(Anno, St0), V = {var,L,V0}, False = {atom,L,false}, E = make_bool_switch_guard(L, E1, V, E2, False), gexpr(E, Bools, St); -gexpr({op,L,'orelse',E1,E2}, Bools, St0) -> +gexpr({op,_,'orelse',_,_}=E0, Bools, St0) -> + {op,L,'orelse',E1,E2} = right_assoc(E0, 'orelse', St0), Anno = lineno_anno(L, St0), {#c_var{name=V0},St} = new_var(Anno, St0), V = {var,L,V0}, @@ -2054,6 +2056,19 @@ fail_clause(Pats, Anno, Arg) -> body=[#iprimop{anno=#a{anno=Anno},name=#c_literal{val=match_fail}, args=[Arg]}]}. +%% Optimization for Dialyzer. +right_assoc(E, Op, St) -> + case member(dialyzer, St#core.opts) of + true -> + right_assoc2(E, Op); + false -> + E + end. + +right_assoc2({op,L1,Op,{op,L2,Op,E1,E2},E3}, Op) -> + right_assoc2({op,L2,Op,E1,{op,L1,Op,E2,E3}}, Op); +right_assoc2(E, _Op) -> E. + annotate_tuple(A, Es, St) -> case member(dialyzer, St#core.opts) of true -> |