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

Unified Diff: pkg/compiler/lib/src/js_model/closure_visitors.dart

Issue 3009903002: Pass in `this` as a free variable to the closure class (Closed)
Patch Set: . Created 3 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/js_model/closure_visitors.dart
diff --git a/pkg/compiler/lib/src/js_model/closure_visitors.dart b/pkg/compiler/lib/src/js_model/closure_visitors.dart
index f27c6dd20a3f1e970714019e6ed4eea99b9c1f7e..c9466cf01a225b4ec05a5d9acc54484e862454ee 100644
--- a/pkg/compiler/lib/src/js_model/closure_visitors.dart
+++ b/pkg/compiler/lib/src/js_model/closure_visitors.dart
@@ -177,6 +177,42 @@ class CapturedScopeBuilder extends ir.Visitor {
}
}
+ @override
+ void visitThisExpression(ir.ThisExpression thisExpression) {
+ if (_hasThisLocal) _registerNeedsThis();
+ }
+
+ @override
+ void visitTypeParameter(ir.TypeParameter typeParameter) {
+ ir.TreeNode context = _executableContext;
+ if (_isInsideClosure && context is ir.Procedure && context.isFactory) {
+ // This is a closure in a factory constructor. Since there is no
+ // [:this:], we have to mark the type arguments as free variables to
+ // capture them in the closure.
+ // TODO(efortuna): Implement for in the case of RTI.
+ // useTypeVariableAsLocal(typeParameter.bound);
+ }
+
+ if (_executableContext is ir.Member &&
+ _executableContext is! ir.Field &&
+ _hasThisLocal) {
+ // In checked mode, using a type variable in a type annotation may lead
+ // to a runtime type check that needs to access the type argument and
+ // therefore the closure needs a this-element, if it is not in a field
+ // initializer; field initializers are evaluated in a context where
+ // the type arguments are available in locals.
+ _registerNeedsThis();
+ }
+ }
+
+ /// Add `this` as a variable that needs to be accessed (and thus may become a
+ /// free/captured variable.
+ void _registerNeedsThis() {
+ if (_isInsideClosure) {
+ _currentScopeInfo.freeVariables.add(const ThisVariable());
Johnni Winther 2017/08/31 07:24:38 Add a `needsThis` property on [KernelScopeInfo] in
Emily Fortuna 2017/08/31 17:40:52 Done.
+ }
+ }
+
@override
void visitForStatement(ir.ForStatement node) {
List<ir.VariableDeclaration> boxedLoopVariables =
@@ -303,3 +339,85 @@ class CapturedScopeBuilder extends ir.Visitor {
visitInvokable(functionDeclaration);
}
}
+
+/// A fake sentinel "ir" node place holder representing the usage of `this`
+/// inside closures that occur inside members.
+class ThisVariable implements ir.VariableDeclaration {
+ const ThisVariable();
+
+ bool get isConst => true;
+ set isConst(bool constVal) =>
+ throw new UnsupportedError("ThisVariable.setIsConst");
+ bool get isFinal => true;
+ set isFinal(bool finalValue) =>
+ throw new UnsupportedError("ThisVariable.setIsFinal");
+ bool get isCovariant => false;
+ set isCovariant(bool covariant) =>
+ throw new UnsupportedError("ThisVariable.setIsCovariant");
+ bool get isFieldFormal => false;
+ set isFieldFormal(bool formal) =>
+ throw new UnsupportedError("ThisVariable.setIsFieldFormal");
+ String get name => 'this';
+ set name(String name) => throw new UnsupportedError("ThisVariable.setName");
+ set type(ir.DartType type) => throw new UnsupportedError("ThisVariable.type");
+ int get fileOffset => throw new UnsupportedError("ThisVariable.fileOffset");
+ set fileOffset(int offset) =>
+ throw new UnsupportedError("ThisVariable.setFileOffset");
+
+ int get binaryOffsetNoTag =>
+ throw new UnsupportedError("ThisVariable.binaryOffsetNoTag");
+ set binaryOffsetNoTag(int offset) =>
+ throw new UnsupportedError("ThisVariable.binaryOffsetNoTag");
+
+ int get fileEqualsOffset =>
+ throw new UnsupportedError("ThisVariable.fileEqualsOffset");
+ set fileEqualsOffset(int offset) =>
+ throw new UnsupportedError("ThisVariable.setFileEqualsOffset");
+
+ int get flags => throw new UnsupportedError("ThisVariable.flags");
+ set flags(int flags) => throw new UnsupportedError("ThisVariable.flags");
+
+ ir.DartType get type =>
+ throw new UnsupportedError("Sentinel this does not have a type.");
+
+ ir.TreeNode get parent =>
+ throw new UnsupportedError("Sentinel this does not have a parent.");
+
+ set parent(ir.TreeNode parent) =>
+ throw new UnsupportedError("Sentinel this does not have a parent.");
+
+ ir.Expression get initializer => null;
+ set initializer(ir.Expression expression) =>
+ throw new UnsupportedError("ThisVariable.setInitializer");
+
+ accept(ir.StatementVisitor v) => throw new UnsupportedError(
+ "ThisVariable should not be walked in AST traversal");
+ accept1(ir.StatementVisitor1 v, arg) => throw new UnsupportedError(
+ "ThisVariable should not be walked in AST traversal");
+
+ visitChildren(ir.Visitor v) {
+ throw new UnsupportedError(
+ "ThisVariable should not be walked in AST traversal");
+ }
+
+ transformChildren(ir.Transformer v) {
+ throw new UnsupportedError(
+ "ThisVariable should not be walked in AST traversal");
+ }
+
+ void replaceChild(ir.TreeNode child, ir.TreeNode replacement) =>
+ throw new UnsupportedError("ThisVariable.replaceChild");
+
+ void replaceWith(ir.TreeNode replacement) =>
+ throw new UnsupportedError("ThisVariable.replaceWith");
+
+ void remove() => throw new UnsupportedError("ThisVariable.remove");
+
+ ir.Program get enclosingProgram =>
+ throw new UnsupportedError("ThisVariable.enclosingProgram");
+
+ ir.Location get location =>
+ throw new UnsupportedError("ThisVariable.location");
+
+ String toString() => 'thisVariable';
+}

Powered by Google App Engine
This is Rietveld 408576698