Index: pkg/compiler/lib/src/closure.dart |
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart |
index 5bdd71b6038b2462da84182c986a4cf119f19a6c..44fcc597ac039edf58f5376b60500ac5a9568348 100644 |
--- a/pkg/compiler/lib/src/closure.dart |
+++ b/pkg/compiler/lib/src/closure.dart |
@@ -84,13 +84,13 @@ class ScopeInfo { |
/// Also parameters to a `sync*` generator must be boxed, because of the way |
/// we rewrite sync* functions. See also comments in |
/// [ClosureClassMap.useLocal]. |
- bool localIsUsedInTryOrSync(Local variable) => false; |
+ bool variableIsUsedInTryOrSync(Local variable) => false; |
/// Loop through each variable that has been defined in this scope, modified |
/// anywhere (this scope or another scope) and used in another scope. Because |
/// it is used in another scope, these variables need to be "boxed", creating |
/// a thin wrapper around accesses to these variables so that accesses get |
- /// the correct updated value. The variables in localsUsedInTryOrSync may |
+ /// the correct updated value. The variables in variablesUsedInTryOrSync may |
/// be included in this set. |
/// |
/// In the case of loops, this is the set of iteration variables (or any |
@@ -100,6 +100,9 @@ class ScopeInfo { |
/// True if [variable] has been mutated and is also used in another scope. |
bool isBoxed(Local variable) => false; |
+ |
+ /// True if this scope declares any variables that need to be boxed. |
+ bool get hasBoxedVariables => false; |
} |
/// Class representing the usage of a scope that has been captured in the |
@@ -138,27 +141,6 @@ class ClosureScope extends ScopeInfo { |
/// each iteration, by boxing the iteration variable[s]. |
class LoopClosureScope extends ClosureScope { |
const LoopClosureScope(); |
- |
- /// True if this loop scope declares in the first part of the loop |
- /// `for (<here>;...;...)` any variables that need to be boxed. |
- bool get hasBoxedLoopVariables => false; |
- |
- /// The set of iteration variables (or variables declared in the for loop |
- /// expression (`for (<here>; ... ; ...)`) that need to be boxed to snapshot |
- /// their value. These variables are also included in the set of |
- /// `forEachBoxedVariable` method. The distinction between these two sets is |
- /// in this example: |
- /// |
- /// run(f) => f(); |
- /// var a; |
- /// for (int i = 0; i < 3; i++) { |
- /// var b = 3; |
- /// a = () => b = i; |
- /// } |
- /// |
- /// `i` would be a part of the boxedLoopVariables AND boxedVariables, but b |
- /// would only be a part of boxedVariables. |
- List<Local> get boxedLoopVariables => const <Local>[]; |
} |
/// Class that describes the actual mechanics of how the converted, rewritten |
@@ -665,10 +647,18 @@ class ClosureScopeImpl implements ClosureScope, LoopClosureScope { |
bool get requiresContextBox => capturedVariables.keys.isNotEmpty; |
void forEachBoxedVariable(f(Local local, FieldEntity field)) { |
- capturedVariables.forEach(f); |
+ if (capturedVariables.isNotEmpty) { |
+ capturedVariables.forEach(f); |
+ } else { |
+ for (Local l in boxedLoopVariables) { |
+ // The boxes for loop variables are constructed on-demand per-iteration |
+ // in the locals handler. |
+ f(l, null); |
+ } |
+ } |
} |
- bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; |
+ bool get hasBoxedVariables => !capturedVariables.isEmpty; |
bool isBoxed(Local variable) { |
return capturedVariables.containsKey(variable); |
@@ -680,8 +670,8 @@ class ClosureScopeImpl implements ClosureScope, LoopClosureScope { |
} |
// Should not be called. Added to make the new interface happy. |
- bool localIsUsedInTryOrSync(Local variable) => |
- throw new UnsupportedError("ClosureScopeImpl.localIsUsedInTryOrSync"); |
+ bool variableIsUsedInTryOrSync(Local variable) => |
+ throw new UnsupportedError("ClosureScopeImpl.variableIsUsedInTryOrSync"); |
// Should not be called. Added to make the new interface happy. |
Local get thisLocal => |
@@ -751,11 +741,14 @@ class ClosureClassMap implements ClosureRepresentationInfo { |
/// Also parameters to a `sync*` generator must be boxed, because of the way |
/// we rewrite sync* functions. See also comments in [useLocal]. |
// TODO(johnniwinther): Add variables to this only if the variable is mutated. |
- final Set<Local> localsUsedInTryOrSync = new Set<Local>(); |
+ final Set<Local> variablesUsedInTryOrSync = new Set<Local>(); |
ClosureClassMap(this.closureEntity, this.closureClassEntity, this.callMethod, |
this.thisLocal); |
+ bool get hasBoxedVariables => |
+ throw new UnsupportedError("ClosureClassMap.hasBoxedVariables"); |
+ |
List<Local> get createdFieldEntities { |
List<Local> fields = <Local>[]; |
if (closureClassEntity == null) return const <Local>[]; |
@@ -782,8 +775,8 @@ class ClosureClassMap implements ClosureRepresentationInfo { |
FieldEntity get thisFieldEntity => freeVariableMap[thisLocal]; |
- bool localIsUsedInTryOrSync(Local variable) => |
- localsUsedInTryOrSync.contains(variable); |
+ bool variableIsUsedInTryOrSync(Local variable) => |
+ variablesUsedInTryOrSync.contains(variable); |
Local getLocalVariableForClosureField(ClosureFieldElement field) { |
return field.local; |
@@ -1032,13 +1025,13 @@ class ClosureTranslator extends Visitor { |
if (variable != closureData.thisLocal && |
variable != closureData.closureEntity && |
variable is! TypeVariableLocal) { |
- closureData.localsUsedInTryOrSync.add(variable); |
+ closureData.variablesUsedInTryOrSync.add(variable); |
} |
} else if (variable is LocalParameterElement && |
variable.functionDeclaration.asyncMarker == AsyncMarker.SYNC_STAR) { |
// Parameters in a sync* function are shared between each Iterator created |
// by the Iterable returned by the function, therefore they must be boxed. |
- closureData.localsUsedInTryOrSync.add(variable); |
+ closureData.variablesUsedInTryOrSync.add(variable); |
} |
} |