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