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

Side by Side Diff: lib/compiler/implementation/closure.dart

Issue 10910098: Re-apply with a few fixes http://codereview.chromium.org/10913081/: Fix resolution of type paramete… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 3 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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("closureToClassMapper"); 5 #library("closureToClassMapper");
6 6
7 #import("elements/elements.dart"); 7 #import("elements/elements.dart");
8 #import("leg.dart"); 8 #import("leg.dart");
9 #import("scanner/scannerlib.dart"); 9 #import("scanner/scannerlib.dart");
10 #import("tree/tree.dart"); 10 #import("tree/tree.dart");
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 // List of encountered closures. 172 // List of encountered closures.
173 List<FunctionExpression> closures; 173 List<FunctionExpression> closures;
174 174
175 // The variables that have been declared in the current scope. 175 // The variables that have been declared in the current scope.
176 List<Element> scopeVariables; 176 List<Element> scopeVariables;
177 177
178 // Keep track of the mutated variables so that we don't need to box 178 // Keep track of the mutated variables so that we don't need to box
179 // non-mutated variables. 179 // non-mutated variables.
180 Set<Element> mutatedVariables; 180 Set<Element> mutatedVariables;
181 181
182 FunctionElement outermostFunctionElement;
182 FunctionElement currentFunctionElement; 183 FunctionElement currentFunctionElement;
184
183 // The closureData of the currentFunctionElement. 185 // The closureData of the currentFunctionElement.
184 ClosureClassMap closureData; 186 ClosureClassMap closureData;
185 187
186 bool insideClosure = false; 188 bool insideClosure = false;
187 189
188 ClosureTranslator(this.compiler, this.elements, this.closureMappingCache) 190 ClosureTranslator(this.compiler, this.elements, this.closureMappingCache)
189 : capturedVariableMapping = new Map<Element, Element>(), 191 : capturedVariableMapping = new Map<Element, Element>(),
190 closures = <FunctionExpression>[], 192 closures = <FunctionExpression>[],
191 mutatedVariables = new Set<Element>(); 193 mutatedVariables = new Set<Element>();
192 194
(...skipping 18 matching lines...) Expand all
211 ClosureClassMap data = closureMappingCache[closure]; 213 ClosureClassMap data = closureMappingCache[closure];
212 Map<Element, Element> freeVariableMapping = data.freeVariableMapping; 214 Map<Element, Element> freeVariableMapping = data.freeVariableMapping;
213 // We get a copy of the keys and iterate over it, to avoid modifications 215 // We get a copy of the keys and iterate over it, to avoid modifications
214 // to the map while iterating over it. 216 // to the map while iterating over it.
215 freeVariableMapping.getKeys().forEach((Element fromElement) { 217 freeVariableMapping.getKeys().forEach((Element fromElement) {
216 assert(fromElement == freeVariableMapping[fromElement]); 218 assert(fromElement == freeVariableMapping[fromElement]);
217 Element updatedElement = capturedVariableMapping[fromElement]; 219 Element updatedElement = capturedVariableMapping[fromElement];
218 assert(updatedElement !== null); 220 assert(updatedElement !== null);
219 if (fromElement == updatedElement) { 221 if (fromElement == updatedElement) {
220 assert(freeVariableMapping[fromElement] == updatedElement); 222 assert(freeVariableMapping[fromElement] == updatedElement);
221 assert(Elements.isLocal(updatedElement)); 223 assert(Elements.isLocal(updatedElement)
224 || updatedElement.isTypeVariable());
222 // The variable has not been boxed. 225 // The variable has not been boxed.
223 fieldCaptures.add(updatedElement); 226 fieldCaptures.add(updatedElement);
224 } else { 227 } else {
225 // A boxed element. 228 // A boxed element.
226 freeVariableMapping[fromElement] = updatedElement; 229 freeVariableMapping[fromElement] = updatedElement;
227 Element boxElement = updatedElement.enclosingElement; 230 Element boxElement = updatedElement.enclosingElement;
228 assert(boxElement.kind == ElementKind.VARIABLE); 231 assert(boxElement.kind == ElementKind.VARIABLE);
229 fieldCaptures.add(boxElement); 232 fieldCaptures.add(boxElement);
230 } 233 }
231 }); 234 });
(...skipping 11 matching lines...) Expand all
243 Element fieldElement = new ClosureFieldElement(name, closureElement); 246 Element fieldElement = new ClosureFieldElement(name, closureElement);
244 closureElement.backendMembers = 247 closureElement.backendMembers =
245 closureElement.backendMembers.prepend(fieldElement); 248 closureElement.backendMembers.prepend(fieldElement);
246 data.capturedFieldMapping[fieldElement] = capturedElement; 249 data.capturedFieldMapping[fieldElement] = capturedElement;
247 freeVariableMapping[capturedElement] = fieldElement; 250 freeVariableMapping[capturedElement] = fieldElement;
248 } 251 }
249 } 252 }
250 } 253 }
251 254
252 void useLocal(Element element) { 255 void useLocal(Element element) {
253 // TODO(floitsch): replace this with a general solution.
254 Element functionElement = currentFunctionElement;
255 if (functionElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
256 ConstructorBodyElement body = functionElement;
257 functionElement = body.constructor;
258 }
259 // If the element is not declared in the current function and the element 256 // If the element is not declared in the current function and the element
260 // is not the closure itself we need to mark the element as free variable. 257 // is not the closure itself we need to mark the element as free variable.
261 if (element.enclosingElement != functionElement && 258 // Note that the check on [insideClosure] is not just an
262 element != functionElement) { 259 // optimization: factories have type parameters as function
260 // parameters, and type parameters are declared in the class, not
261 // the factory.
262 if (insideClosure &&
263 element.enclosingElement != currentFunctionElement &&
264 element != currentFunctionElement) {
263 assert(closureData.freeVariableMapping[element] == null || 265 assert(closureData.freeVariableMapping[element] == null ||
264 closureData.freeVariableMapping[element] == element); 266 closureData.freeVariableMapping[element] == element);
265 closureData.freeVariableMapping[element] = element; 267 closureData.freeVariableMapping[element] = element;
266 } else if (inTryStatement) { 268 } else if (inTryStatement) {
267 // Don't mark the this-element. This would complicate things in the 269 // Don't mark the this-element. This would complicate things in the
268 // builder. 270 // builder.
269 if (element != closureData.thisElement) { 271 if (element != closureData.thisElement) {
270 // TODO(ngeoffray): only do this if the variable is mutated. 272 // TODO(ngeoffray): only do this if the variable is mutated.
271 closureData.usedVariablesInTry.add(element); 273 closureData.usedVariablesInTry.add(element);
272 } 274 }
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 341
340 visitSendSet(SendSet node) { 342 visitSendSet(SendSet node) {
341 Element element = elements[node]; 343 Element element = elements[node];
342 if (Elements.isLocal(element)) { 344 if (Elements.isLocal(element)) {
343 mutatedVariables.add(element); 345 mutatedVariables.add(element);
344 } 346 }
345 super.visitSendSet(node); 347 super.visitSendSet(node);
346 } 348 }
347 349
348 visitNewExpression(NewExpression node) { 350 visitNewExpression(NewExpression node) {
351 TypeAnnotation annotation = node.send.getTypeAnnotation();
352 DartType type = elements.getType(annotation);
353
349 bool hasTypeVariable(DartType type) { 354 bool hasTypeVariable(DartType type) {
350 if (type is TypeVariableType) { 355 if (type is TypeVariableType) {
351 return true; 356 return true;
352 } else if (type is InterfaceType) { 357 } else if (type is InterfaceType) {
353 InterfaceType ifcType = type; 358 InterfaceType ifcType = type;
354 for (DartType argument in ifcType.arguments) { 359 for (DartType argument in ifcType.arguments) {
355 if (hasTypeVariable(argument)) { 360 if (hasTypeVariable(argument)) {
356 return true; 361 return true;
357 } 362 }
358 } 363 }
359 } 364 }
360 return false; 365 return false;
361 } 366 }
362 TypeAnnotation annotation = node.send.getTypeAnnotation(); 367
363 DartType type = elements.getType(annotation); 368 void analyzeTypeVariables(DartType type) {
364 if (hasTypeVariable(type)) { 369 if (type is TypeVariableType) {
365 // Factories do not use [this] to get the type variables. 370 useLocal(type.element);
366 if (closureData.thisElement !== null) { 371 } else if (type is InterfaceType) {
367 useLocal(closureData.thisElement); 372 InterfaceType ifcType = type;
373 for (DartType argument in ifcType.arguments) {
374 analyzeTypeVariables(argument);
375 }
368 } 376 }
369 } 377 }
378
379 if (outermostFunctionElement.isInstanceMember()
380 || outermostFunctionElement.isGenerativeConstructor()) {
381 if (hasTypeVariable(type)) useLocal(closureData.thisElement);
382 } else if (outermostFunctionElement.isFactoryConstructor()) {
383 analyzeTypeVariables(type);
384 }
385
370 node.visitChildren(this); 386 node.visitChildren(this);
371 } 387 }
372 388
373 // If variables that are declared in the [node] scope are captured and need 389 // If variables that are declared in the [node] scope are captured and need
374 // to be boxed create a box-element and update the [capturingScopes] in the 390 // to be boxed create a box-element and update the [capturingScopes] in the
375 // current [closureData]. 391 // current [closureData].
376 // The boxed variables are updated in the [capturedVariableMapping]. 392 // The boxed variables are updated in the [capturedVariableMapping].
377 void attachCapturedScopeVariables(Node node) { 393 void attachCapturedScopeVariables(Node node) {
378 Element box = null; 394 Element box = null;
379 Map<Element, Element> scopeMapping = new Map<Element, Element>(); 395 Map<Element, Element> scopeMapping = new Map<Element, Element>();
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 const EmptyLink<Element>().prepend(callElement); 504 const EmptyLink<Element>().prepend(callElement);
489 // The nested function's 'this' is the same as the one for the outer 505 // The nested function's 'this' is the same as the one for the outer
490 // function. It could be [null] if we are inside a static method. 506 // function. It could be [null] if we are inside a static method.
491 Element thisElement = closureData.thisElement; 507 Element thisElement = closureData.thisElement;
492 return new ClosureClassMap(element, globalizedElement, 508 return new ClosureClassMap(element, globalizedElement,
493 callElement, thisElement); 509 callElement, thisElement);
494 } 510 }
495 511
496 visitFunctionExpression(FunctionExpression node) { 512 visitFunctionExpression(FunctionExpression node) {
497 Element element = elements[node]; 513 Element element = elements[node];
498 if (element.kind === ElementKind.PARAMETER) { 514 if (element.isParameter()) {
499 // TODO(ahe): This is a hack. This method should *not* call 515 // TODO(ahe): This is a hack. This method should *not* call
500 // visitChildren. 516 // visitChildren.
501 return node.name.accept(this); 517 return node.name.accept(this);
502 } 518 }
503 bool isClosure = (closureData !== null);
504
505 if (isClosure) closures.add(node);
506 519
507 bool oldInsideClosure = insideClosure; 520 bool oldInsideClosure = insideClosure;
508 FunctionElement oldFunctionElement = currentFunctionElement; 521 FunctionElement oldFunctionElement = currentFunctionElement;
509 ClosureClassMap oldClosureData = closureData; 522 ClosureClassMap oldClosureData = closureData;
510 523
511 insideClosure = isClosure; 524 insideClosure = outermostFunctionElement != null;
512 currentFunctionElement = elements[node]; 525 currentFunctionElement = element;
513 if (insideClosure) { 526 if (insideClosure) {
527 closures.add(node);
514 closureData = globalizeClosure(node, element); 528 closureData = globalizeClosure(node, element);
515 } else { 529 } else {
530 outermostFunctionElement = element;
516 Element thisElement = null; 531 Element thisElement = null;
517 // TODO(floitsch): we should not need to look for generative constructors. 532 if (element.isInstanceMember() || element.isGenerativeConstructor()) {
518 // At the moment we store only one ClosureData for both the factory and 533 thisElement = new ThisElement(element);
519 // the body.
520 if (element.isInstanceMember() ||
521 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
522 // TODO(floitsch): currently all variables are considered to be
523 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'.
524 Element thisEnclosingElement = element;
525 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
526 ConstructorBodyElement body = element;
527 thisEnclosingElement = body.constructor;
528 }
529 thisElement = new ThisElement(thisEnclosingElement);
530 } 534 }
531 closureData = new ClosureClassMap(null, null, null, thisElement); 535 closureData = new ClosureClassMap(null, null, null, thisElement);
532 } 536 }
533 closureMappingCache[node] = closureData; 537 closureMappingCache[node] = closureData;
534 538
535 inNewScope(node, () { 539 inNewScope(node, () {
536 // We have to declare the implicit 'this' parameter. 540 // We have to declare the implicit 'this' parameter.
537 if (!insideClosure && closureData.thisElement !== null) { 541 if (!insideClosure && closureData.thisElement !== null) {
538 declareLocal(closureData.thisElement); 542 declareLocal(closureData.thisElement);
539 } 543 }
540 // If we are inside a named closure we have to declare ourselve. For 544 // If we are inside a named closure we have to declare ourselve. For
541 // simplicity we declare the local even if the closure does not have a 545 // simplicity we declare the local even if the closure does not have a
542 // name. 546 // name.
543 // It will simply not be used. 547 // It will simply not be used.
544 if (insideClosure) { 548 if (insideClosure) {
545 declareLocal(element); 549 declareLocal(element);
546 } 550 }
551
552 if (currentFunctionElement.isFactoryConstructor()) {
553 // Declare the type parameters in the scope. Generative
554 // constructors just use 'this'.
555 ClassElement cls = currentFunctionElement.enclosingElement;
556 cls.typeVariables.forEach((TypeVariableType typeVariable) {
557 declareLocal(typeVariable.element);
558 });
559 }
547 560
548 // TODO(ahe): This is problematic. The backend should not repeat 561 // TODO(ahe): This is problematic. The backend should not repeat
549 // the work of the resolver. It is the resolver's job to create 562 // the work of the resolver. It is the resolver's job to create
550 // parameters, etc. Other phases should only visit statements. 563 // parameters, etc. Other phases should only visit statements.
551 // TODO(floitsch): we avoid visiting the initializers on purpose so that 564 // TODO(floitsch): we avoid visiting the initializers on purpose so that
552 // we get an error-message later in the builder. 565 // we get an error-message later in the builder.
553 if (node.parameters !== null) node.parameters.accept(this); 566 if (node.parameters !== null) node.parameters.accept(this);
554 if (node.body !== null) node.body.accept(this); 567 if (node.body !== null) node.body.accept(this);
555 }); 568 });
556 569
(...skipping 26 matching lines...) Expand all
583 } 596 }
584 597
585 visitTryStatement(TryStatement node) { 598 visitTryStatement(TryStatement node) {
586 // TODO(ngeoffray): implement finer grain state. 599 // TODO(ngeoffray): implement finer grain state.
587 bool oldInTryStatement = inTryStatement; 600 bool oldInTryStatement = inTryStatement;
588 inTryStatement = true; 601 inTryStatement = true;
589 node.visitChildren(this); 602 node.visitChildren(this);
590 inTryStatement = oldInTryStatement; 603 inTryStatement = oldInTryStatement;
591 } 604 }
592 } 605 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/elements/elements.dart » ('j') | lib/compiler/implementation/elements/elements.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698