222 if (!speculative) { |
222 if (!speculative) { |
223 diagHandler = new Log.DiscardDiagnosticHandler(log); |
223 diagHandler = new Log.DiscardDiagnosticHandler(log); |
224 } |
224 } |
225 try { |
225 try { |
226 new AliveAnalyzer().analyzeTree(env, that, make); |
226 new AliveAnalyzer().analyzeTree(env, that, make); |
227 new LambdaFlowAnalyzer().analyzeTree(env, that, make); |
|
228 } finally { |
227 } finally { |
229 if (!speculative) { |
228 if (!speculative) { |
230 log.popDiagnosticHandler(diagHandler); |
229 log.popDiagnosticHandler(diagHandler); |
231 } |
230 } |
|
231 } |
|
232 } |
|
233 |
|
234 public List<Type> analyzeLambdaThrownTypes(Env<AttrContext> env, JCLambda that, TreeMaker make) { |
|
235 //we need to disable diagnostics temporarily; the problem is that if |
|
236 //a lambda expression contains e.g. an unreachable statement, an error |
|
237 //message will be reported and will cause compilation to skip the flow analyis |
|
238 //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis |
|
239 //related errors, which will allow for more errors to be detected |
|
240 Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); |
|
241 try { |
|
242 new AssignAnalyzer().analyzeTree(env, that, make); |
|
243 LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer(); |
|
244 flowAnalyzer.analyzeTree(env, that, make); |
|
245 return flowAnalyzer.inferredThrownTypes; |
|
246 } finally { |
|
247 log.popDiagnosticHandler(diagHandler); |
232 } |
248 } |
233 } |
249 } |
234 |
250 |
235 /** |
251 /** |
236 * Definite assignment scan mode |
252 * Definite assignment scan mode |
1316 |
1332 |
1317 /** |
1333 /** |
1318 * Specialized pass that performs inference of thrown types for lambdas. |
1334 * Specialized pass that performs inference of thrown types for lambdas. |
1319 */ |
1335 */ |
1320 class LambdaFlowAnalyzer extends FlowAnalyzer { |
1336 class LambdaFlowAnalyzer extends FlowAnalyzer { |
|
1337 List<Type> inferredThrownTypes; |
|
1338 boolean inLambda; |
1321 @Override |
1339 @Override |
1322 public void visitLambda(JCLambda tree) { |
1340 public void visitLambda(JCLambda tree) { |
1323 if (tree.type != null && |
1341 if ((tree.type != null && |
1324 tree.type.isErroneous()) { |
1342 tree.type.isErroneous()) || inLambda) { |
1325 return; |
1343 return; |
1326 } |
1344 } |
1327 List<Type> prevCaught = caught; |
1345 List<Type> prevCaught = caught; |
1328 List<Type> prevThrown = thrown; |
1346 List<Type> prevThrown = thrown; |
1329 ListBuffer<FlowPendingExit> prevPending = pendingExits; |
1347 ListBuffer<FlowPendingExit> prevPending = pendingExits; |
|
1348 inLambda = true; |
1330 try { |
1349 try { |
1331 pendingExits = ListBuffer.lb(); |
1350 pendingExits = ListBuffer.lb(); |
1332 caught = List.of(syms.throwableType); |
1351 caught = List.of(syms.throwableType); |
1333 thrown = List.nil(); |
1352 thrown = List.nil(); |
1334 scan(tree.body); |
1353 scan(tree.body); |
1335 tree.inferredThrownTypes = thrown; |
1354 inferredThrownTypes = thrown; |
1336 } finally { |
1355 } finally { |
1337 pendingExits = prevPending; |
1356 pendingExits = prevPending; |
1338 caught = prevCaught; |
1357 caught = prevCaught; |
1339 thrown = prevThrown; |
1358 thrown = prevThrown; |
1340 } |
1359 inLambda = false; |
|
1360 } |
|
1361 } |
|
1362 @Override |
|
1363 public void visitClassDef(JCClassDecl tree) { |
|
1364 //skip |
1341 } |
1365 } |
1342 } |
1366 } |
1343 |
1367 |
1344 /** |
1368 /** |
1345 * This pass implements (i) definite assignment analysis, which ensures that |
1369 * This pass implements (i) definite assignment analysis, which ensures that |