Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(329)

Side by Side Diff: pkg/kernel/lib/transformations/closure/converter.dart

Issue 2639253003: Handle constructor bodies (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/kernel/lib/transformations/closure/invalidate_closures.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library kernel.transformations.closure.converter; 5 library kernel.transformations.closure.converter;
6 6
7 import '../../ast.dart' 7 import '../../ast.dart'
8 show 8 show
9 Arguments, 9 Arguments,
10 Block, 10 Block,
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 this.tearOffGetterNames = info.tearOffGetterNames; 140 this.tearOffGetterNames = info.tearOffGetterNames;
141 141
142 bool get isOuterMostContext { 142 bool get isOuterMostContext {
143 return currentFunction == null || currentMemberFunction == currentFunction; 143 return currentFunction == null || currentMemberFunction == currentFunction;
144 } 144 }
145 145
146 String get currentFileUri { 146 String get currentFileUri {
147 if (currentMember is Constructor) return currentClass.fileUri; 147 if (currentMember is Constructor) return currentClass.fileUri;
148 if (currentMember is Field) return (currentMember as Field).fileUri; 148 if (currentMember is Field) return (currentMember as Field).fileUri;
149 if (currentMember is Procedure) return (currentMember as Procedure).fileUri; 149 if (currentMember is Procedure) return (currentMember as Procedure).fileUri;
150 throw "No file uri"; 150 throw "No file uri for ${currentMember.runtimeType}";
151 } 151 }
152 152
153 void insert(Statement statement) { 153 void insert(Statement statement) {
154 _currentBlock.statements.insert(_insertionIndex++, statement); 154 _currentBlock.statements.insert(_insertionIndex++, statement);
155 statement.parent = _currentBlock; 155 statement.parent = _currentBlock;
156 } 156 }
157 157
158 TreeNode saveContext(TreeNode f()) { 158 TreeNode saveContext(TreeNode f()) {
159 Block savedBlock = _currentBlock; 159 Block savedBlock = _currentBlock;
160 int savedIndex = _insertionIndex; 160 int savedIndex = _insertionIndex;
161 Context savedContext = context; 161 Context savedContext = context;
162 try { 162 try {
163 return f(); 163 return f();
164 } finally { 164 } finally {
165 _currentBlock = savedBlock; 165 _currentBlock = savedBlock;
166 _insertionIndex = savedIndex; 166 _insertionIndex = savedIndex;
167 context = savedContext; 167 context = savedContext;
168 } 168 }
169 } 169 }
170 170
171 TreeNode visitLibrary(Library node) { 171 TreeNode visitLibrary(Library node) {
172 assert(newLibraryMembers.isEmpty); 172 assert(newLibraryMembers.isEmpty);
173 if (node == contextClass.enclosingLibrary) return node; 173 if (node == contextClass.enclosingLibrary) return node;
174
174 currentLibrary = node; 175 currentLibrary = node;
175 node = super.visitLibrary(node); 176 node = super.visitLibrary(node);
176 for (TreeNode member in newLibraryMembers) { 177 for (TreeNode member in newLibraryMembers) {
177 if (member is Class) { 178 if (member is Class) {
178 node.addClass(member); 179 node.addClass(member);
179 } else { 180 } else {
180 node.addMember(member); 181 node.addMember(member);
181 } 182 }
182 } 183 }
183 newLibraryMembers.clear(); 184 newLibraryMembers.clear();
184 currentLibrary = null; 185 currentLibrary = null;
185 return node; 186 return node;
186 } 187 }
187 188
188 TreeNode visitClass(Class node) { 189 TreeNode visitClass(Class node) {
189 assert(newClassMembers.isEmpty); 190 assert(newClassMembers.isEmpty);
190 currentClass = node; 191 currentClass = node;
191 node = super.visitClass(node); 192 node = super.visitClass(node);
192 newClassMembers.forEach(node.addMember); 193 newClassMembers.forEach(node.addMember);
193 newClassMembers.clear(); 194 newClassMembers.clear();
194 currentClass = null; 195 currentClass = null;
195 return node; 196 return node;
196 } 197 }
197 198
198 TreeNode visitConstructor(Constructor node) { 199 TreeNode visitConstructor(Constructor node) {
199 // TODO(ahe): Convert closures in constructors as well. 200 assert(isEmptyContext);
201
202 currentMember = node;
203
204 FunctionNode function = node.function;
205 if (function.body != null && function.body is! EmptyStatement) {
206 setupContextForFunctionBody(function);
207 VariableDeclaration self = thisAccess[currentMemberFunction];
208 // TODO(karlklose): transform initializers
209 if (self != null) {
210 context.extend(self, new ThisExpression());
211 }
212 node.function.accept(this);
213 resetContext();
214 }
215
200 return node; 216 return node;
201 } 217 }
202 218
203 Expression handleLocalFunction(FunctionNode function) { 219 Expression handleLocalFunction(FunctionNode function) {
204 FunctionNode enclosingFunction = currentFunction; 220 FunctionNode enclosingFunction = currentFunction;
205 Map<TypeParameter, DartType> enclosingTypeSubstitution = typeSubstitution; 221 Map<TypeParameter, DartType> enclosingTypeSubstitution = typeSubstitution;
206 currentFunction = function; 222 currentFunction = function;
207 Statement body = function.body; 223 Statement body = function.body;
208 assert(body != null); 224 assert(body != null);
209 225
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 addFieldForwarder(tearOffName, node); 350 addFieldForwarder(tearOffName, node);
335 } 351 }
336 } 352 }
337 node = super.visitField(node); 353 node = super.visitField(node);
338 context = null; 354 context = null;
339 currentMember = null; 355 currentMember = null;
340 return node; 356 return node;
341 } 357 }
342 358
343 TreeNode visitProcedure(Procedure node) { 359 TreeNode visitProcedure(Procedure node) {
360 assert(isEmptyContext);
361
344 currentMember = node; 362 currentMember = node;
345 assert(_currentBlock == null);
346 assert(_insertionIndex == 0);
347 assert(context == null);
348
349 Statement body = node.function.body;
350 363
351 if (node.isInstanceMember) { 364 if (node.isInstanceMember) {
352 Name tearOffName = tearOffGetterNames[node.name]; 365 Name tearOffName = tearOffGetterNames[node.name];
353 if (tearOffName != null) { 366 if (tearOffName != null) {
354 if (node.isGetter) { 367 if (node.isGetter) {
355 // We rename the getter to avoid an indirection in most cases. 368 // We rename the getter to avoid an indirection in most cases.
356 Name oldName = node.name; 369 Name oldName = node.name;
357 node.name = tearOffName; 370 node.name = tearOffName;
358 addGetterForwarder(oldName, node); 371 addGetterForwarder(oldName, node);
359 } else if (node.kind == ProcedureKind.Method) { 372 } else if (node.kind == ProcedureKind.Method) {
360 addTearOffGetter(tearOffName, node); 373 addTearOffGetter(tearOffName, node);
361 } 374 }
362 } 375 }
363 } 376 }
364 377
365 if (body == null) return node; 378 FunctionNode function = node.function;
379 if (function.body != null) {
380 setupContextForFunctionBody(function);
381 VariableDeclaration self = thisAccess[currentMemberFunction];
382 if (self != null) {
383 context.extend(self, new ThisExpression());
384 }
385 node.transformChildren(this);
386 resetContext();
387 }
366 388
367 currentMemberFunction = node.function; 389 return node;
390 }
368 391
392 void setupContextForFunctionBody(FunctionNode function) {
393 Statement body = function.body;
394 assert(body != null);
395 currentMemberFunction = function;
369 // Ensure that the body is a block which becomes the current block. 396 // Ensure that the body is a block which becomes the current block.
370 if (body is Block) { 397 if (body is Block) {
371 _currentBlock = body; 398 _currentBlock = body;
372 } else { 399 } else {
373 _currentBlock = new Block(<Statement>[body]); 400 _currentBlock = new Block(<Statement>[body]);
374 node.function.body = body.parent = _currentBlock; 401 function.body = body.parent = _currentBlock;
375 } 402 }
376 _insertionIndex = 0; 403 _insertionIndex = 0;
377
378 // Start with no context. This happens after setting up _currentBlock 404 // Start with no context. This happens after setting up _currentBlock
379 // so statements can be emitted into _currentBlock if necessary. 405 // so statements can be emitted into _currentBlock if necessary.
380 context = new NoContext(this); 406 context = new NoContext(this);
407 }
381 408
382 VariableDeclaration self = thisAccess[currentMemberFunction]; 409 void resetContext() {
383 if (self != null) {
384 context.extend(self, new ThisExpression());
385 }
386
387 node.transformChildren(this);
388
389 _currentBlock = null; 410 _currentBlock = null;
390 _insertionIndex = 0; 411 _insertionIndex = 0;
391 context = null; 412 context = null;
392 currentMemberFunction = null; 413 currentMemberFunction = null;
393 currentMember = null; 414 currentMember = null;
394 return node; 415 }
416
417 bool get isEmptyContext {
418 return _currentBlock == null && _insertionIndex == 0 && context == null;
395 } 419 }
396 420
397 TreeNode visitLocalInitializer(LocalInitializer node) { 421 TreeNode visitLocalInitializer(LocalInitializer node) {
398 assert(!capturedVariables.contains(node.variable)); 422 assert(!capturedVariables.contains(node.variable));
399 node.transformChildren(this); 423 node.transformChildren(this);
400 return node; 424 return node;
401 } 425 }
402 426
403 TreeNode visitFunctionNode(FunctionNode node) { 427 TreeNode visitFunctionNode(FunctionNode node) {
404 transformList(node.typeParameters, this, node); 428 transformList(node.typeParameters, this, node);
405 429
406 void extend(VariableDeclaration parameter) { 430 void extend(VariableDeclaration parameter) {
407 context.extend(parameter, new VariableGet(parameter)); 431 context.extend(parameter, new VariableGet(parameter));
408 } 432 }
409 433
410 // TODO: Can parameters contain initializers (e.g., for optional ones) that 434 // TODO: Can parameters contain initializers (e.g., for optional ones) that
411 // need to be closure converted? 435 // need to be closure converted?
412 node.positionalParameters.where(capturedVariables.contains).forEach(extend); 436 node.positionalParameters.where(capturedVariables.contains).forEach(extend);
413 node.namedParameters.where(capturedVariables.contains).forEach(extend); 437 node.namedParameters.where(capturedVariables.contains).forEach(extend);
414 438
415 assert(node.body != null); 439 assert(node.body != null);
416 node.body = node.body.accept(this); 440 node.body = node.body.accept(this);
417 node.body.parent = node; 441 node.body.parent = node;
418 return node; 442 return node;
419 } 443 }
420 444
421 TreeNode visitBlock(Block node) => saveContext(() { 445 TreeNode visitBlock(Block node) {
422 if (_currentBlock != node) { 446 return saveContext(() {
423 _currentBlock = node; 447 if (_currentBlock != node) {
424 _insertionIndex = 0; 448 _currentBlock = node;
449 _insertionIndex = 0;
450 }
451
452 while (_insertionIndex < _currentBlock.statements.length) {
453 assert(_currentBlock == node);
454
455 var original = _currentBlock.statements[_insertionIndex];
456 var transformed = original.accept(this);
457 assert(_currentBlock.statements[_insertionIndex] == original);
458 if (transformed == null) {
459 _currentBlock.statements.removeAt(_insertionIndex);
460 } else {
461 _currentBlock.statements[_insertionIndex++] = transformed;
462 transformed.parent = _currentBlock;
425 } 463 }
464 }
426 465
427 while (_insertionIndex < _currentBlock.statements.length) { 466 return node;
428 assert(_currentBlock == node); 467 });
429 468 }
430 var original = _currentBlock.statements[_insertionIndex];
431 var transformed = original.accept(this);
432 assert(_currentBlock.statements[_insertionIndex] == original);
433 if (transformed == null) {
434 _currentBlock.statements.removeAt(_insertionIndex);
435 } else {
436 _currentBlock.statements[_insertionIndex++] = transformed;
437 transformed.parent = _currentBlock;
438 }
439 }
440
441 return node;
442 });
443 469
444 TreeNode visitVariableDeclaration(VariableDeclaration node) { 470 TreeNode visitVariableDeclaration(VariableDeclaration node) {
445 node.transformChildren(this); 471 node.transformChildren(this);
446 472
447 if (!capturedVariables.contains(node)) return node; 473 if (!capturedVariables.contains(node)) return node;
448 context.extend(node, node.initializer ?? new NullLiteral()); 474 context.extend(node, node.initializer ?? new NullLiteral());
449 475
450 if (node.parent == currentFunction) return node; 476 if (node.parent == currentFunction) {
451 if (node.parent is Block) { 477 return node;
478 } else {
479 assert(node.parent is Block);
452 // When returning null, the parent block will remove this node from its 480 // When returning null, the parent block will remove this node from its
453 // list of statements. 481 // list of statements.
454 // TODO(ahe): I'd like to avoid testing on the parent pointer.
455 return null; 482 return null;
456 } 483 }
457 throw "Unexpected parent for $node: ${node.parent.parent}";
458 } 484 }
459 485
460 TreeNode visitVariableGet(VariableGet node) { 486 TreeNode visitVariableGet(VariableGet node) {
461 return capturedVariables.contains(node.variable) 487 return capturedVariables.contains(node.variable)
462 ? context.lookup(node.variable) 488 ? context.lookup(node.variable)
463 : node; 489 : node;
464 } 490 }
465 491
466 TreeNode visitVariableSet(VariableSet node) { 492 TreeNode visitVariableSet(VariableSet node) {
467 node.transformChildren(this); 493 node.transformChildren(this);
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
783 // TODO(ahe): Remove this method when we don't generate closure classes 809 // TODO(ahe): Remove this method when we don't generate closure classes
784 // anymore. 810 // anymore.
785 void addClosureClassNote(Class closureClass) { 811 void addClosureClassNote(Class closureClass) {
786 closureClass.addMember(new Field(new Name("note"), 812 closureClass.addMember(new Field(new Name("note"),
787 type: coreTypes.stringClass.rawType, 813 type: coreTypes.stringClass.rawType,
788 initializer: new StringLiteral( 814 initializer: new StringLiteral(
789 "This is temporary. The VM doesn't need closure classes."), 815 "This is temporary. The VM doesn't need closure classes."),
790 fileUri: currentFileUri)); 816 fileUri: currentFileUri));
791 } 817 }
792 } 818 }
OLDNEW
« no previous file with comments | « no previous file | pkg/kernel/lib/transformations/closure/invalidate_closures.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698