1 package gnu.expr;
2 import gnu.bytecode.Type;
3 import gnu.kawa.functions.Convert;
4 
5 /** Sets up the firstChild/nextSibling links of each LambdaExp.
6  * Setup 'outer' links of ScopeExp and its sub-classes.
7  * Also generates a class name for each ClassExp and registers each class.
8  * Also, if lambda is bound to a unique declaration, make that its name.
9  *
10  * This pass also checks for unreachable code, which happens if a
11  * neverReturns expression is followed dynamically by another expression.
12  * Doing this check after InlineCalls allows benefiting from data-flow; OTOH
13  * checking for unreachable code this late yields less precise type inference,
14  * but only when there actually is unreachable code, which is bogus anyway.
15  */
16 
17 public class ChainLambdas extends ExpExpVisitor<ScopeExp> {
chainLambdas(Expression exp, Compilation comp)18     public static void chainLambdas (Expression exp, Compilation comp) {
19         ChainLambdas visitor = new ChainLambdas();
20         visitor.setContext(comp);
21         visitor.visit(exp, null);
22     }
23 
maybeWarnUnreachable(Expression exp)24     protected void maybeWarnUnreachable(Expression exp) {
25         if (! unreachableCodeSeen && comp.warnUnreachable())
26             comp.error('w', "unreachable code", exp);
27         unreachableCodeSeen = true;
28     }
29 
30     /** True if we've seen (reported) unreachable code in this procedure. */
31     boolean unreachableCodeSeen;
32 
visitBeginExp(BeginExp exp, ScopeExp scope)33     protected Expression visitBeginExp(BeginExp exp, ScopeExp scope) {
34         int neverReturnsIndex = -1;
35         int last = exp.length - 1;
36         for (int i = 0;  i <= last;  i++) {
37             Expression e = visit(exp.exps[i], scope);
38             exp.exps[i] = e;
39             if (e.neverReturns() && neverReturnsIndex < 0) {
40                 neverReturnsIndex = i;
41                 if (i < last)
42                     maybeWarnUnreachable(exp.exps[i+1]);
43             }
44         }
45         if (neverReturnsIndex >= 0) {
46             exp.type = Type.neverReturnsType;
47             exp.length = neverReturnsIndex + 1;
48         }
49         return exp;
50     }
51 
visitApplyExp(ApplyExp exp, ScopeExp scope)52     protected Expression visitApplyExp(ApplyExp exp, ScopeExp scope) {
53         Expression f = visit(exp.func, scope);
54         Expression[] args = exp.args;
55         int nargs = args.length;
56         exp.func = f;
57         if (f.neverReturns()) {
58             maybeWarnUnreachable(nargs > 0 ? args[0] : exp);
59             return f;
60         }
61         for (int i = 0; i < nargs;  i++) {
62             Expression e = visit(args[i], scope);
63             if (e.neverReturns()
64                 // It seems best to silently allow converting never-returns
65                 // to any type.  For example it useful for stub procedures
66                 // that throw an "unimplemented" exception.
67                 && ! (f.valueIfConstant() instanceof Convert)) {
68                 Expression[] xargs = new Expression[i+2];
69                 xargs[0] = exp.func;
70                 System.arraycopy(args, 0, xargs, 1, i+1);
71                 if (i+1 < nargs || ! exp.isAppendValues()) {
72                     if (! unreachableCodeSeen && comp.warnUnreachable()) {
73                         comp.error('w', "unreachable procedure call", exp);
74                         comp.error('i', "this operand never finishes", args[i]);
75                     }
76                     unreachableCodeSeen = true;
77                 }
78                 BeginExp bexp = new BeginExp(xargs);
79                 bexp.type = Type.neverReturnsType;
80                 return bexp;
81             }
82             args[i] = e;
83         }
84         return exp;
85     }
86 
visitSetExp(SetExp sexp, ScopeExp scope)87     protected Expression visitSetExp(SetExp sexp, ScopeExp scope) {
88         Expression r = super.visitSetExp(sexp, scope);
89         if (r == sexp) {
90             Expression rval = sexp.getNewValue();
91             if (rval.neverReturns()) {
92                 maybeWarnUnreachable(sexp);
93                 return rval;
94             }
95         }
96         return r;
97     }
98 
visitIfExp(IfExp exp, ScopeExp scope)99     protected Expression visitIfExp(IfExp exp, ScopeExp scope) {
100         Expression e = visit(exp.test, scope);
101         if (e.neverReturns()) {
102             maybeWarnUnreachable(exp.then_clause);
103             return e;
104         }
105         exp.then_clause = visit(exp.then_clause, scope);
106         if (exp.else_clause != null) {
107             exp.else_clause = visit(exp.else_clause, scope);
108             if (exp.then_clause.neverReturns()
109                 && exp.else_clause.neverReturns())
110                 exp.type = Type.neverReturnsType;
111         }
112         return exp;
113     }
114 
visitCaseExp(CaseExp exp, ScopeExp scope)115     protected Expression visitCaseExp(CaseExp exp, ScopeExp scope) {
116 
117         Expression e = visit(exp.key, scope);
118         if (e.neverReturns()) {
119             for (int i = 0; i < exp.clauses.length; i++) {
120                 maybeWarnUnreachable(exp.clauses[i].exp);
121             }
122             maybeWarnUnreachable(exp.elseClause.exp);
123             return e;
124         }
125 
126         boolean neverReturns = true;
127         for (int i = 0; i < exp.clauses.length; i++) {
128             exp.clauses[i].exp = visit(exp.clauses[i].exp, scope);
129             if (!exp.clauses[i].exp.neverReturns()) {
130                 neverReturns = false;
131             }
132         }
133         if (exp.elseClause != null) {
134             exp.elseClause.exp = visit(exp.elseClause.exp, scope);
135             if (!exp.elseClause.exp.neverReturns())
136                 neverReturns = false;
137         }
138 
139         if (neverReturns)
140             exp.type = Type.neverReturnsType;
141 
142         return exp;
143     }
144 
visitScopeExp(ScopeExp exp, ScopeExp scope)145   protected Expression visitScopeExp (ScopeExp exp, ScopeExp scope)
146   {
147     exp.setOuter(scope);
148     exp.visitChildren(this, exp);
149     exp.setIndexes();
150     if (exp.mustCompile())
151       comp.mustCompileHere();
152     return exp;
153   }
154 
visitLetExp(LetExp exp, ScopeExp scope)155   protected Expression visitLetExp (LetExp exp, ScopeExp scope)
156   {
157     exp.setOuter(scope);
158     int count = 0;
159     for (Declaration decl = exp.firstDecl(); decl != null; decl = decl.nextDecl())
160       {
161           Expression init = decl.getInitValue();
162           Expression e = visit(init, exp);
163           count++;
164           if (e.neverReturns()) {
165               if (! unreachableCodeSeen && comp.warnUnreachable())
166                   comp.error('w', "initialization of "+decl.getName()+" never finishes", init);
167               unreachableCodeSeen = true;
168               Expression[] exps = new Expression[count];
169               int i = 0;
170               Declaration end = decl.nextDecl();
171               for (Declaration d = exp.firstDecl(); d != end; d = d.nextDecl())
172                   exps[i++] = d.getInitValue();
173               return BeginExp.canonicalize(exps);
174           }
175           decl.setInitValue(e);
176       }
177     exp.body = visit(exp.body, exp);
178     exp.setIndexes();
179     if (exp.mustCompile())
180       comp.mustCompileHere();
181     return exp;
182   }
183 
visitLambdaExp(LambdaExp exp, ScopeExp scope)184   protected Expression visitLambdaExp (LambdaExp exp, ScopeExp scope)
185   {
186     boolean unreachableSaved = unreachableCodeSeen;
187     unreachableCodeSeen = false;
188     LambdaExp parent = currentLambda;
189     if (parent != null && ! (parent instanceof ClassExp))
190         parent.pushChild(exp);
191 
192     exp.setOuter(scope);
193     exp.firstChild = null;
194     exp.visitChildrenOnly(this, exp);
195     exp.visitProperties(this, exp);
196 
197     // Put list of children in proper order.
198     exp.reverseChildList();
199 
200     if (exp.getName() == null && exp.nameDecl != null)
201       exp.setName(exp.nameDecl.getName());
202     exp.setIndexes();
203     if (exp.mustCompile())
204       comp.mustCompileHere();
205     unreachableCodeSeen = unreachableSaved;
206     return exp;
207   }
208 
visitClassExp(ClassExp exp, ScopeExp scope)209   protected Expression visitClassExp (ClassExp exp, ScopeExp scope)
210   {
211     LambdaExp parent = currentLambda;
212     if (parent != null && ! (parent instanceof ClassExp))
213         parent.pushChild(exp);
214 
215     visitScopeExp(exp, scope);
216 
217     return exp;
218   }
219 }
220