OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library analyzer2dart.cps_generator; | |
6 | |
7 import 'package:analyzer/analyzer.dart'; | |
8 | |
9 import 'package:compiler/src/dart_types.dart' as dart2js; | |
10 import 'package:compiler/src/elements/elements.dart' as dart2js; | |
11 import 'package:analyzer/src/generated/source.dart'; | |
12 import 'package:analyzer/src/generated/element.dart' as analyzer; | |
13 | |
14 import 'package:compiler/src/constant_system_dart.dart' | |
15 show DART_CONSTANT_SYSTEM; | |
16 import 'package:compiler/src/cps_ir/cps_ir_nodes.dart' as ir; | |
17 import 'package:compiler/src/cps_ir/cps_ir_builder.dart'; | |
18 import 'package:compiler/src/universe/universe.dart'; | |
19 | |
20 import 'semantic_visitor.dart'; | |
21 import 'element_converter.dart'; | |
22 import 'util.dart'; | |
23 import 'identifier_semantics.dart'; | |
24 | |
25 /// Visitor that converts the AST node of an analyzer element into a CPS ir | |
26 /// node. | |
27 class CpsElementVisitor extends analyzer.SimpleElementVisitor<ir.Node> { | |
28 final ElementConverter converter; | |
29 final AstNode node; | |
30 | |
31 CpsElementVisitor(this.converter, this.node); | |
32 | |
33 @override | |
34 ir.FunctionDefinition visitFunctionElement(analyzer.FunctionElement element) { | |
35 CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); | |
36 FunctionDeclaration functionDeclaration = node; | |
37 return visitor.handleFunctionDeclaration( | |
38 element, functionDeclaration.functionExpression.body); | |
39 } | |
40 | |
41 @override | |
42 ir.FunctionDefinition visitMethodElement(analyzer.MethodElement element) { | |
43 CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); | |
44 MethodDeclaration methodDeclaration = node; | |
45 return visitor.handleFunctionDeclaration(element, methodDeclaration.body); | |
46 } | |
47 | |
48 @override | |
49 ir.FieldDefinition visitTopLevelVariableElement( | |
50 analyzer.TopLevelVariableElement element) { | |
51 CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); | |
52 VariableDeclaration variableDeclaration = node; | |
53 return visitor.handleFieldDeclaration(element, variableDeclaration); | |
54 } | |
55 | |
56 @override | |
57 ir.RootNode visitConstructorElement(analyzer.ConstructorElement element) { | |
58 CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element); | |
59 if (!element.isFactory) { | |
60 ConstructorDeclaration constructorDeclaration = node; | |
61 FunctionBody body; | |
62 if (constructorDeclaration != null) { | |
63 body = constructorDeclaration.body; | |
64 } else { | |
65 assert(element.isSynthetic); | |
66 } | |
67 return visitor.handleConstructorDeclaration(element, body); | |
68 } | |
69 // TODO(johnniwinther): Support factory constructors. | |
70 return null; | |
71 } | |
72 } | |
73 | |
74 /// Visitor that converts analyzer AST nodes into CPS ir nodes. | |
75 class CpsGeneratingVisitor extends SemanticVisitor<ir.Node> | |
76 with IrBuilderMixin<AstNode> { | |
77 /// Promote the type of [irBuilder] to [DartIrBuilder]. | |
78 /// The JS backend requires closure conversion which we do not support yet. | |
79 DartIrBuilder get irBuilder => super.irBuilder; | |
80 final analyzer.Element element; | |
81 final ElementConverter converter; | |
82 | |
83 CpsGeneratingVisitor(this.converter, this.element); | |
84 | |
85 Source get currentSource => element.source; | |
86 | |
87 analyzer.LibraryElement get currentLibrary => element.library; | |
88 | |
89 ir.Node visit(AstNode node) => node.accept(this); | |
90 | |
91 ir.ConstructorDefinition handleConstructorDeclaration( | |
92 analyzer.ConstructorElement constructor, FunctionBody body) { | |
93 dart2js.ConstructorElement element = converter.convertElement(constructor); | |
94 return withBuilder( | |
95 new DartIrBuilder(DART_CONSTANT_SYSTEM, | |
96 element, | |
97 // TODO(johnniwinther): Support closure variables. | |
98 new Set<dart2js.Local>()), | |
99 () { | |
100 irBuilder.buildFunctionHeader( | |
101 constructor.parameters.map(converter.convertElement)); | |
102 // Visit the body directly to avoid processing the signature as | |
103 // expressions. | |
104 // Call to allow for `body == null` in case of synthesized constructors. | |
105 build(body); | |
106 return irBuilder.makeConstructorDefinition(const [], const []); | |
107 }); | |
108 } | |
109 | |
110 ir.FieldDefinition handleFieldDeclaration( | |
111 analyzer.PropertyInducingElement field, VariableDeclaration node) { | |
112 dart2js.FieldElement element = converter.convertElement(field); | |
113 return withBuilder( | |
114 new DartIrBuilder(DART_CONSTANT_SYSTEM, | |
115 element, | |
116 // TODO(johnniwinther): Support closure variables. | |
117 new Set<dart2js.Local>()), | |
118 () { | |
119 irBuilder.buildFieldInitializerHeader(); | |
120 ir.Primitive initializer = build(node.initializer); | |
121 return irBuilder.makeFieldDefinition(initializer); | |
122 }); | |
123 } | |
124 | |
125 ir.FunctionDefinition handleFunctionDeclaration( | |
126 analyzer.ExecutableElement function, FunctionBody body) { | |
127 dart2js.FunctionElement element = converter.convertElement(function); | |
128 return withBuilder( | |
129 new DartIrBuilder(DART_CONSTANT_SYSTEM, | |
130 element, | |
131 // TODO(johnniwinther): Support closure variables. | |
132 new Set<dart2js.Local>()), | |
133 () { | |
134 irBuilder.buildFunctionHeader( | |
135 function.parameters.map(converter.convertElement)); | |
136 // Visit the body directly to avoid processing the signature as | |
137 // expressions. | |
138 visit(body); | |
139 return irBuilder.makeFunctionDefinition(const []); | |
140 }); | |
141 } | |
142 | |
143 @override | |
144 ir.Primitive visitFunctionExpression(FunctionExpression node) { | |
145 return irBuilder.buildFunctionExpression( | |
146 handleFunctionDeclaration(node.element, node.body)); | |
147 } | |
148 | |
149 @override | |
150 ir.FunctionDefinition visitFunctionDeclaration(FunctionDeclaration node) { | |
151 return handleFunctionDeclaration( | |
152 node.element, node.functionExpression.body); | |
153 } | |
154 | |
155 @override | |
156 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { | |
157 FunctionDeclaration functionDeclaration = node.functionDeclaration; | |
158 analyzer.FunctionElement function = functionDeclaration.element; | |
159 dart2js.FunctionElement element = converter.convertElement(function); | |
160 ir.FunctionDefinition definition = handleFunctionDeclaration( | |
161 function, functionDeclaration.functionExpression.body); | |
162 irBuilder.declareLocalFunction(element, definition); | |
163 } | |
164 | |
165 List<ir.Primitive> visitArguments(ArgumentList argumentList) { | |
166 List<ir.Primitive> arguments = <ir.Primitive>[]; | |
167 for (Expression argument in argumentList.arguments) { | |
168 ir.Primitive value = build(argument); | |
169 if (value == null) { | |
170 giveUp(argument, | |
171 'Unsupported argument: $argument (${argument.runtimeType}).'); | |
172 } | |
173 arguments.add(value); | |
174 } | |
175 return arguments; | |
176 } | |
177 | |
178 @override | |
179 ir.Node visitMethodInvocation(MethodInvocation node) { | |
180 // Overridden to avoid eager visits of the receiver and arguments. | |
181 return handleMethodInvocation(node); | |
182 } | |
183 | |
184 @override | |
185 ir.Primitive visitDynamicInvocation(MethodInvocation node, | |
186 AccessSemantics semantics) { | |
187 // TODO(johnniwinther): Handle implicit `this`. | |
188 ir.Primitive receiver = build(semantics.target); | |
189 List<ir.Primitive> arguments = visitArguments(node.argumentList); | |
190 return irBuilder.buildDynamicInvocation( | |
191 receiver, | |
192 createSelectorFromMethodInvocation( | |
193 node.argumentList, node.methodName.name), | |
194 arguments); | |
195 } | |
196 | |
197 @override | |
198 ir.Primitive visitStaticMethodInvocation(MethodInvocation node, | |
199 AccessSemantics semantics) { | |
200 analyzer.Element staticElement = semantics.element; | |
201 dart2js.Element element = converter.convertElement(staticElement); | |
202 List<ir.Primitive> arguments = visitArguments(node.argumentList); | |
203 return irBuilder.buildStaticFunctionInvocation( | |
204 element, | |
205 createCallStructureFromMethodInvocation(node.argumentList), | |
206 arguments); | |
207 } | |
208 | |
209 @override | |
210 ir.Node visitLocalFunctionAccess(AstNode node, AccessSemantics semantics) { | |
211 return handleLocalAccess(node, semantics); | |
212 } | |
213 | |
214 ir.Primitive handleLocalInvocation(MethodInvocation node, | |
215 AccessSemantics semantics) { | |
216 analyzer.Element staticElement = semantics.element; | |
217 dart2js.Element element = converter.convertElement(staticElement); | |
218 List<ir.Definition> arguments = visitArguments(node.argumentList); | |
219 CallStructure callStructure = createCallStructureFromMethodInvocation( | |
220 node.argumentList); | |
221 if (semantics.kind == AccessKind.LOCAL_FUNCTION) { | |
222 return irBuilder.buildLocalFunctionInvocation( | |
223 element, callStructure, arguments); | |
224 } else { | |
225 return irBuilder.buildLocalVariableInvocation( | |
226 element, callStructure, arguments); | |
227 } | |
228 } | |
229 | |
230 @override | |
231 ir.Node visitLocalVariableInvocation(MethodInvocation node, | |
232 AccessSemantics semantics) { | |
233 return handleLocalInvocation(node, semantics); | |
234 } | |
235 | |
236 @override | |
237 ir.Primitive visitLocalFunctionInvocation(MethodInvocation node, | |
238 AccessSemantics semantics) { | |
239 return handleLocalInvocation(node, semantics); | |
240 } | |
241 | |
242 @override | |
243 ir.Primitive visitFunctionExpressionInvocation( | |
244 FunctionExpressionInvocation node) { | |
245 ir.Primitive target = build(node.function); | |
246 List<ir.Definition> arguments = visitArguments(node.argumentList); | |
247 return irBuilder.buildCallInvocation( | |
248 target, | |
249 createCallStructureFromMethodInvocation(node.argumentList), | |
250 arguments); | |
251 } | |
252 | |
253 @override | |
254 ir.Primitive visitInstanceCreationExpression( | |
255 InstanceCreationExpression node) { | |
256 analyzer.Element staticElement = node.staticElement; | |
257 if (staticElement != null) { | |
258 dart2js.Element element = converter.convertElement(staticElement); | |
259 dart2js.DartType type = converter.convertType(node.staticType); | |
260 List<ir.Primitive> arguments = visitArguments(node.argumentList); | |
261 return irBuilder.buildConstructorInvocation( | |
262 element, | |
263 createCallStructureFromMethodInvocation(node.argumentList), | |
264 type, | |
265 arguments); | |
266 } | |
267 return giveUp(node, "Unresolved constructor invocation."); | |
268 } | |
269 | |
270 @override | |
271 ir.Constant visitNullLiteral(NullLiteral node) { | |
272 return irBuilder.buildNullConstant(); | |
273 } | |
274 | |
275 @override | |
276 ir.Constant visitBooleanLiteral(BooleanLiteral node) { | |
277 return irBuilder.buildBooleanConstant(node.value); | |
278 } | |
279 | |
280 @override | |
281 ir.Constant visitDoubleLiteral(DoubleLiteral node) { | |
282 return irBuilder.buildDoubleConstant(node.value); | |
283 } | |
284 | |
285 @override | |
286 ir.Constant visitIntegerLiteral(IntegerLiteral node) { | |
287 return irBuilder.buildIntegerConstant(node.value); | |
288 } | |
289 | |
290 @override | |
291 visitAdjacentStrings(AdjacentStrings node) { | |
292 String value = node.stringValue; | |
293 if (value != null) { | |
294 return irBuilder.buildStringConstant(value); | |
295 } | |
296 giveUp(node, "Non constant adjacent strings."); | |
297 } | |
298 | |
299 @override | |
300 ir.Constant visitSimpleStringLiteral(SimpleStringLiteral node) { | |
301 return irBuilder.buildStringConstant(node.value); | |
302 } | |
303 | |
304 @override | |
305 visitStringInterpolation(StringInterpolation node) { | |
306 giveUp(node, "String interpolation."); | |
307 } | |
308 | |
309 @override | |
310 visitReturnStatement(ReturnStatement node) { | |
311 irBuilder.buildReturn(build(node.expression)); | |
312 } | |
313 | |
314 @override | |
315 ir.Node visitPropertyAccess(PropertyAccess node) { | |
316 // Overridden to avoid eager visits of the receiver. | |
317 return handlePropertyAccess(node); | |
318 } | |
319 | |
320 @override | |
321 ir.Node visitLocalVariableAccess(AstNode node, AccessSemantics semantics) { | |
322 return handleLocalAccess(node, semantics); | |
323 } | |
324 | |
325 @override | |
326 ir.Node visitParameterAccess(AstNode node, AccessSemantics semantics) { | |
327 return handleLocalAccess(node, semantics); | |
328 } | |
329 | |
330 @override | |
331 visitVariableDeclaration(VariableDeclaration node) { | |
332 // TODO(johnniwinther): Handle constant local variables. | |
333 ir.Node initialValue = build(node.initializer); | |
334 irBuilder.declareLocalVariable( | |
335 converter.convertElement(node.element), | |
336 initialValue: initialValue); | |
337 } | |
338 | |
339 dart2js.Element getLocal(AstNode node, AccessSemantics semantics) { | |
340 analyzer.Element element = semantics.element; | |
341 dart2js.Element target = converter.convertElement(element); | |
342 assert(invariant(node, target.isLocal, '$target expected to be local.')); | |
343 return target; | |
344 } | |
345 | |
346 ir.Primitive handleLocalAccess(AstNode node, AccessSemantics semantics) { | |
347 dart2js.Element local = getLocal(node, semantics); | |
348 if (semantics.kind == AccessKind.LOCAL_FUNCTION) { | |
349 return irBuilder.buildLocalFunctionGet(local); | |
350 } else { | |
351 return irBuilder.buildLocalVariableGet(local); | |
352 } | |
353 } | |
354 | |
355 ir.Primitive handleLocalAssignment(AssignmentExpression node, | |
356 AccessSemantics semantics) { | |
357 if (node.operator.lexeme != '=') { | |
358 return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); | |
359 } | |
360 return irBuilder.buildLocalVariableSet( | |
361 getLocal(node, semantics), | |
362 build(node.rightHandSide)); | |
363 } | |
364 | |
365 @override | |
366 ir.Node visitAssignmentExpression(AssignmentExpression node) { | |
367 // Avoid eager visiting of left and right hand side. | |
368 return handleAssignmentExpression(node); | |
369 } | |
370 | |
371 @override | |
372 ir.Node visitLocalVariableAssignment(AssignmentExpression node, | |
373 AccessSemantics semantics) { | |
374 return handleLocalAssignment(node, semantics); | |
375 } | |
376 | |
377 @override | |
378 ir.Node visitParameterAssignment(AssignmentExpression node, | |
379 AccessSemantics semantics) { | |
380 return handleLocalAssignment(node, semantics); | |
381 } | |
382 | |
383 @override | |
384 ir.Node visitStaticFieldAssignment(AssignmentExpression node, | |
385 AccessSemantics semantics) { | |
386 if (node.operator.lexeme != '=') { | |
387 return giveUp(node, 'Assignment operator: ${node.operator.lexeme}'); | |
388 } | |
389 analyzer.Element element = semantics.element; | |
390 dart2js.Element target = converter.convertElement(element); | |
391 // TODO(johnniwinther): Selector information should be computed in the | |
392 // [TreeShaker] and shared with the [CpsGeneratingVisitor]. | |
393 assert(invariant(node, target.isTopLevel || target.isStatic, | |
394 '$target expected to be top-level or static.')); | |
395 return irBuilder.buildStaticFieldSet(target, build(node.rightHandSide)); | |
396 } | |
397 | |
398 @override | |
399 ir.Node visitDynamicAccess(AstNode node, AccessSemantics semantics) { | |
400 // TODO(johnniwinther): Handle implicit `this`. | |
401 ir.Primitive receiver = build(semantics.target); | |
402 return irBuilder.buildDynamicGet(receiver, | |
403 new Selector.getter(semantics.identifier.name, | |
404 converter.convertElement(element.library))); | |
405 } | |
406 | |
407 @override | |
408 ir.Node visitStaticFieldAccess(AstNode node, AccessSemantics semantics) { | |
409 analyzer.Element element = semantics.element; | |
410 dart2js.Element target = converter.convertElement(element); | |
411 // TODO(johnniwinther): Selector information should be computed in the | |
412 // [TreeShaker] and shared with the [CpsGeneratingVisitor]. | |
413 assert(invariant(node, target.isTopLevel || target.isStatic, | |
414 '$target expected to be top-level or static.')); | |
415 return irBuilder.buildStaticFieldLazyGet(target, null); | |
416 } | |
417 | |
418 ir.Primitive handleBinaryExpression(BinaryExpression node, | |
419 String op) { | |
420 ir.Primitive left = build(node.leftOperand); | |
421 ir.Primitive right = build(node.rightOperand); | |
422 Selector selector = new Selector.binaryOperator(op); | |
423 return irBuilder.buildDynamicInvocation( | |
424 left, selector, <ir.Primitive>[right]); | |
425 } | |
426 | |
427 ir.Node handleLazyOperator(BinaryExpression node, {bool isLazyOr: false}) { | |
428 return irBuilder.buildLogicalOperator( | |
429 build(node.leftOperand), | |
430 subbuild(node.rightOperand), | |
431 isLazyOr: isLazyOr); | |
432 } | |
433 | |
434 @override | |
435 ir.Node visitBinaryExpression(BinaryExpression node) { | |
436 // TODO(johnniwinther,paulberry,brianwilkerson): The operator should be | |
437 // available through an enum. | |
438 String op = node.operator.lexeme; | |
439 switch (op) { | |
440 case '||': | |
441 case '&&': | |
442 return handleLazyOperator(node, isLazyOr: op == '||'); | |
443 case '!=': | |
444 return irBuilder.buildNegation(handleBinaryExpression(node, '==')); | |
445 default: | |
446 return handleBinaryExpression(node, op); | |
447 } | |
448 } | |
449 | |
450 @override | |
451 ir.Node visitConditionalExpression(ConditionalExpression node) { | |
452 return irBuilder.buildConditional( | |
453 build(node.condition), | |
454 subbuild(node.thenExpression), | |
455 subbuild(node.elseExpression)); | |
456 } | |
457 | |
458 @override | |
459 visitIfStatement(IfStatement node) { | |
460 irBuilder.buildIf( | |
461 build(node.condition), | |
462 subbuild(node.thenStatement), | |
463 subbuild(node.elseStatement)); | |
464 } | |
465 | |
466 @override | |
467 visitBlock(Block node) { | |
468 irBuilder.buildBlock(node.statements, build); | |
469 } | |
470 | |
471 @override | |
472 ir.Node visitListLiteral(ListLiteral node) { | |
473 dart2js.InterfaceType type = converter.convertType(node.staticType); | |
474 // TODO(johnniwinther): Use `build` instead of `(e) => build(e)` when issue | |
475 // 18630 has been resolved. | |
476 Iterable<ir.Primitive> values = node.elements.map((e) => build(e)); | |
477 return irBuilder.buildListLiteral(type, values); | |
478 } | |
479 | |
480 @override | |
481 ir.Node visitMapLiteral(MapLiteral node) { | |
482 dart2js.InterfaceType type = converter.convertType(node.staticType); | |
483 return irBuilder.buildMapLiteral( | |
484 type, | |
485 node.entries.map((e) => e.key), | |
486 node.entries.map((e) => e.value), | |
487 build); | |
488 } | |
489 | |
490 @override | |
491 visitForStatement(ForStatement node) { | |
492 // TODO(johnniwinther): Support `for` as a jump target. | |
493 List<dart2js.LocalElement> loopVariables = <dart2js.LocalElement>[]; | |
494 SubbuildFunction buildInitializer; | |
495 if (node.variables != null) { | |
496 buildInitializer = subbuild(node.variables); | |
497 for (VariableDeclaration variable in node.variables.variables) { | |
498 loopVariables.add(converter.convertElement(variable.element)); | |
499 } | |
500 } else { | |
501 buildInitializer = subbuild(node.initialization); | |
502 } | |
503 irBuilder.buildFor(buildInitializer: buildInitializer, | |
504 buildCondition: subbuild(node.condition), | |
505 buildBody: subbuild(node.body), | |
506 buildUpdate: subbuildSequence(node.updaters), | |
507 loopVariables: loopVariables); | |
508 } | |
509 | |
510 @override | |
511 visitWhileStatement(WhileStatement node) { | |
512 // TODO(johnniwinther): Support `while` as a jump target. | |
513 irBuilder.buildWhile(buildCondition: subbuild(node.condition), | |
514 buildBody: subbuild(node.body)); | |
515 } | |
516 | |
517 @override | |
518 visitDeclaredIdentifier(DeclaredIdentifier node) { | |
519 giveUp(node, "Unexpected node: DeclaredIdentifier"); | |
520 } | |
521 | |
522 @override | |
523 visitForEachStatement(ForEachStatement node) { | |
524 SubbuildFunction buildVariableDeclaration; | |
525 dart2js.Element variableElement; | |
526 Selector variableSelector; | |
527 if (node.identifier != null) { | |
528 AccessSemantics accessSemantics = | |
529 node.identifier.accept(ACCESS_SEMANTICS_VISITOR); | |
530 if (accessSemantics.kind == AccessKind.DYNAMIC) { | |
531 variableSelector = new Selector.setter( | |
532 node.identifier.name, converter.convertElement(currentLibrary)); | |
533 } else if (accessSemantics.element != null) { | |
534 variableElement = converter.convertElement(accessSemantics.element); | |
535 variableSelector = new Selector.setter( | |
536 variableElement.name, | |
537 converter.convertElement(accessSemantics.element.library)); | |
538 } else { | |
539 giveUp(node, 'For-in of unresolved variable: $accessSemantics'); | |
540 } | |
541 } else { | |
542 assert(invariant( | |
543 node, node.loopVariable != null, "Loop variable expected")); | |
544 variableElement = converter.convertElement(node.loopVariable.element); | |
545 buildVariableDeclaration = (IrBuilder builder) { | |
546 builder.declareLocalVariable(variableElement); | |
547 }; | |
548 } | |
549 // TODO(johnniwinther): Support `for-in` as a jump target. | |
550 irBuilder.buildForIn( | |
551 buildExpression: subbuild(node.iterable), | |
552 buildVariableDeclaration: buildVariableDeclaration, | |
553 variableElement: variableElement, | |
554 variableSelector: variableSelector, | |
555 buildBody: subbuild(node.body)); | |
556 } | |
557 @override | |
558 ir.Primitive visitIsExpression(IsExpression node) { | |
559 return irBuilder.buildTypeOperator( | |
560 visit(node.expression), | |
561 converter.convertType(node.type.type), | |
562 isTypeTest: true, | |
563 isNotCheck: node.notOperator != null); | |
564 } | |
565 | |
566 @override | |
567 ir.Primitive visitAsExpression(AsExpression node) { | |
568 return irBuilder.buildTypeOperator( | |
569 visit(node.expression), | |
570 converter.convertType(node.type.type), | |
571 isTypeTest: false); | |
572 } | |
573 | |
574 @override | |
575 visitTryStatement(TryStatement node) { | |
576 List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[]; | |
577 for (CatchClause catchClause in node.catchClauses) { | |
578 catchClauseInfos.add(new CatchClauseInfo( | |
579 exceptionVariable: converter.convertElement( | |
580 catchClause.exceptionParameter.staticElement), | |
581 buildCatchBlock: subbuild(catchClause.body))); | |
582 | |
583 } | |
584 irBuilder.buildTry( | |
585 tryStatementInfo: new TryStatementInfo(), | |
586 buildTryBlock: subbuild(node.body), | |
587 catchClauseInfos: catchClauseInfos); | |
588 } | |
589 } | |
OLD | NEW |