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

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

Powered by Google App Engine
This is Rietveld 408576698