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

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

Issue 10913081: Fix resolution of type parameters in static context, and the use of type parameters in closures. (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
« no previous file with comments | « no previous file | lib/compiler/implementation/elements/elements.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) 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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 Element fieldElement = new ClosureFieldElement(name, closureElement); 245 Element fieldElement = new ClosureFieldElement(name, closureElement);
244 closureElement.backendMembers = 246 closureElement.backendMembers =
245 closureElement.backendMembers.prepend(fieldElement); 247 closureElement.backendMembers.prepend(fieldElement);
246 data.capturedFieldMapping[fieldElement] = capturedElement; 248 data.capturedFieldMapping[fieldElement] = capturedElement;
247 freeVariableMapping[capturedElement] = fieldElement; 249 freeVariableMapping[capturedElement] = fieldElement;
248 } 250 }
249 } 251 }
250 } 252 }
251 253
252 void useLocal(Element element) { 254 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 255 // 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. 256 // is not the closure itself we need to mark the element as free variable.
261 if (element.enclosingElement != functionElement && 257 // Note that the check on [insideClosure] is not just an
262 element != functionElement) { 258 // optimization: factories have type parameters as function
259 // parameters, and type parameters are declared in the class, not
260 // the factory.
261 if (insideClosure &&
262 element.enclosingElement != currentFunctionElement &&
263 element != currentFunctionElement) {
263 assert(closureData.freeVariableMapping[element] == null || 264 assert(closureData.freeVariableMapping[element] == null ||
264 closureData.freeVariableMapping[element] == element); 265 closureData.freeVariableMapping[element] == element);
265 closureData.freeVariableMapping[element] = element; 266 closureData.freeVariableMapping[element] = element;
266 } else if (inTryStatement) { 267 } else if (inTryStatement) {
267 // Don't mark the this-element. This would complicate things in the 268 // Don't mark the this-element. This would complicate things in the
268 // builder. 269 // builder.
269 if (element != closureData.thisElement) { 270 if (element != closureData.thisElement) {
270 // TODO(ngeoffray): only do this if the variable is mutated. 271 // TODO(ngeoffray): only do this if the variable is mutated.
271 closureData.usedVariablesInTry.add(element); 272 closureData.usedVariablesInTry.add(element);
272 } 273 }
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 340
340 visitSendSet(SendSet node) { 341 visitSendSet(SendSet node) {
341 Element element = elements[node]; 342 Element element = elements[node];
342 if (Elements.isLocal(element)) { 343 if (Elements.isLocal(element)) {
343 mutatedVariables.add(element); 344 mutatedVariables.add(element);
344 } 345 }
345 super.visitSendSet(node); 346 super.visitSendSet(node);
346 } 347 }
347 348
348 visitNewExpression(NewExpression node) { 349 visitNewExpression(NewExpression node) {
350 TypeAnnotation annotation = node.send.getTypeAnnotation();
351 DartType type = elements.getType(annotation);
352
349 bool hasTypeVariable(DartType type) { 353 bool hasTypeVariable(DartType type) {
350 if (type is TypeVariableType) { 354 if (type is TypeVariableType) {
351 return true; 355 return true;
352 } else if (type is InterfaceType) { 356 } else if (type is InterfaceType) {
353 InterfaceType ifcType = type; 357 InterfaceType ifcType = type;
354 for (DartType argument in ifcType.arguments) { 358 for (DartType argument in ifcType.arguments) {
355 if (hasTypeVariable(argument)) { 359 if (hasTypeVariable(argument)) {
356 return true; 360 return true;
357 } 361 }
358 } 362 }
359 } 363 }
360 return false; 364 return false;
361 } 365 }
362 TypeAnnotation annotation = node.send.getTypeAnnotation(); 366
363 DartType type = elements.getType(annotation); 367 void analyzeTypeVariables(DartType type) {
364 if (hasTypeVariable(type)) { 368 if (type is TypeVariableType) {
365 // Factories do not use [this] to get the type variables. 369 useLocal(type.element);
366 if (closureData.thisElement !== null) { 370 } else if (type is InterfaceType) {
367 useLocal(closureData.thisElement); 371 InterfaceType ifcType = type;
372 for (DartType argument in ifcType.arguments) {
373 analyzeTypeVariables(argument);
374 }
368 } 375 }
369 } 376 }
377
378 if (outermostFunctionElement.isInstanceMember()
379 || outermostFunctionElement.isGenerativeConstructor()) {
380 if (hasTypeVariable(type)) useLocal(closureData.thisElement);
381 } else if (outermostFunctionElement.isFactoryConstructor()) {
382 analyzeTypeVariables(type);
383 }
384
370 node.visitChildren(this); 385 node.visitChildren(this);
371 } 386 }
372 387
373 // If variables that are declared in the [node] scope are captured and need 388 // 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 389 // to be boxed create a box-element and update the [capturingScopes] in the
375 // current [closureData]. 390 // current [closureData].
376 // The boxed variables are updated in the [capturedVariableMapping]. 391 // The boxed variables are updated in the [capturedVariableMapping].
377 void attachCapturedScopeVariables(Node node) { 392 void attachCapturedScopeVariables(Node node) {
378 Element box = null; 393 Element box = null;
379 Map<Element, Element> scopeMapping = new Map<Element, Element>(); 394 Map<Element, Element> scopeMapping = new Map<Element, Element>();
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 const EmptyLink<Element>().prepend(callElement); 472 const EmptyLink<Element>().prepend(callElement);
458 // The nested function's 'this' is the same as the one for the outer 473 // The nested function's 'this' is the same as the one for the outer
459 // function. It could be [null] if we are inside a static method. 474 // function. It could be [null] if we are inside a static method.
460 Element thisElement = closureData.thisElement; 475 Element thisElement = closureData.thisElement;
461 return new ClosureClassMap(element, globalizedElement, 476 return new ClosureClassMap(element, globalizedElement,
462 callElement, thisElement); 477 callElement, thisElement);
463 } 478 }
464 479
465 visitFunctionExpression(FunctionExpression node) { 480 visitFunctionExpression(FunctionExpression node) {
466 Element element = elements[node]; 481 Element element = elements[node];
467 if (element.kind === ElementKind.PARAMETER) { 482 if (element.isParameter()) {
468 // TODO(ahe): This is a hack. This method should *not* call 483 // TODO(ahe): This is a hack. This method should *not* call
469 // visitChildren. 484 // visitChildren.
470 return node.name.accept(this); 485 return node.name.accept(this);
471 } 486 }
472 bool isClosure = (closureData !== null);
473
474 if (isClosure) closures.add(node);
475 487
476 bool oldInsideClosure = insideClosure; 488 bool oldInsideClosure = insideClosure;
477 FunctionElement oldFunctionElement = currentFunctionElement; 489 FunctionElement oldFunctionElement = currentFunctionElement;
478 ClosureClassMap oldClosureData = closureData; 490 ClosureClassMap oldClosureData = closureData;
479 491
480 insideClosure = isClosure; 492 insideClosure = outermostFunctionElement != null;
481 currentFunctionElement = elements[node]; 493 currentFunctionElement = element;
482 if (insideClosure) { 494 if (insideClosure) {
495 closures.add(node);
483 closureData = globalizeClosure(node, element); 496 closureData = globalizeClosure(node, element);
484 } else { 497 } else {
498 outermostFunctionElement = element;
485 Element thisElement = null; 499 Element thisElement = null;
486 // TODO(floitsch): we should not need to look for generative constructors. 500 if (element.isInstanceMember() || element.isGenerativeConstructor()) {
487 // At the moment we store only one ClosureData for both the factory and 501 thisElement = new ThisElement(element);
488 // the body.
489 if (element.isInstanceMember() ||
490 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
491 // TODO(floitsch): currently all variables are considered to be
492 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'.
493 Element thisEnclosingElement = element;
494 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
495 ConstructorBodyElement body = element;
496 thisEnclosingElement = body.constructor;
497 }
498 thisElement = new ThisElement(thisEnclosingElement);
499 } 502 }
500 closureData = new ClosureClassMap(null, null, null, thisElement); 503 closureData = new ClosureClassMap(null, null, null, thisElement);
501 } 504 }
502 closureMappingCache[node] = closureData; 505 closureMappingCache[node] = closureData;
503 506
504 inNewScope(node, () { 507 inNewScope(node, () {
505 // We have to declare the implicit 'this' parameter. 508 // We have to declare the implicit 'this' parameter.
506 if (!insideClosure && closureData.thisElement !== null) { 509 if (!insideClosure && closureData.thisElement !== null) {
507 declareLocal(closureData.thisElement); 510 declareLocal(closureData.thisElement);
508 } 511 }
509 // If we are inside a named closure we have to declare ourselve. For 512 // If we are inside a named closure we have to declare ourselve. For
510 // simplicity we declare the local even if the closure does not have a 513 // simplicity we declare the local even if the closure does not have a
511 // name. 514 // name.
512 // It will simply not be used. 515 // It will simply not be used.
513 if (insideClosure) { 516 if (insideClosure) {
514 declareLocal(element); 517 declareLocal(element);
515 } 518 }
519
520 if (currentFunctionElement.isFactoryConstructor()) {
521 // Declare the type parameters in the scope. Generative
522 // constructors just use 'this'.
523 ClassElement cls = currentFunctionElement.enclosingElement;
524 cls.typeVariables.forEach((TypeVariableType typeVariable) {
525 declareLocal(typeVariable.element);
526 });
527 }
516 528
517 // TODO(ahe): This is problematic. The backend should not repeat 529 // TODO(ahe): This is problematic. The backend should not repeat
518 // the work of the resolver. It is the resolver's job to create 530 // the work of the resolver. It is the resolver's job to create
519 // parameters, etc. Other phases should only visit statements. 531 // parameters, etc. Other phases should only visit statements.
520 // TODO(floitsch): we avoid visiting the initializers on purpose so that 532 // TODO(floitsch): we avoid visiting the initializers on purpose so that
521 // we get an error-message later in the builder. 533 // we get an error-message later in the builder.
522 if (node.parameters !== null) node.parameters.accept(this); 534 if (node.parameters !== null) node.parameters.accept(this);
523 if (node.body !== null) node.body.accept(this); 535 if (node.body !== null) node.body.accept(this);
524 }); 536 });
525 537
(...skipping 26 matching lines...) Expand all
552 } 564 }
553 565
554 visitTryStatement(TryStatement node) { 566 visitTryStatement(TryStatement node) {
555 // TODO(ngeoffray): implement finer grain state. 567 // TODO(ngeoffray): implement finer grain state.
556 bool oldInTryStatement = inTryStatement; 568 bool oldInTryStatement = inTryStatement;
557 inTryStatement = true; 569 inTryStatement = true;
558 node.visitChildren(this); 570 node.visitChildren(this);
559 inTryStatement = oldInTryStatement; 571 inTryStatement = oldInTryStatement;
560 } 572 }
561 } 573 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/elements/elements.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698