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

Unified Diff: lib/src/compiler/code_generator.dart

Issue 1948563002: allow 'super' in async and finally blocks (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 7 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
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | lib/src/compiler/source_map_printer.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/compiler/code_generator.dart
diff --git a/lib/src/compiler/code_generator.dart b/lib/src/compiler/code_generator.dart
index 255f15931c429f5c653b581e0435d18102ae04d9..73c4eb0fadac046e08820d2887b793cd1304de29 100644
--- a/lib/src/compiler/code_generator.dart
+++ b/lib/src/compiler/code_generator.dart
@@ -118,6 +118,11 @@ class CodeGenerator extends GeneralizingAstVisitor
String _buildRoot;
+ bool _superAllowed = true;
+
+ List<JS.TemporaryId> _superHelperSymbols = <JS.TemporaryId>[];
+ List<JS.Method> _superHelpers = <JS.Method>[];
+
/// Whether we are currently generating code for the body of a `JS()` call.
bool _isInForeignJS = false;
@@ -595,6 +600,7 @@ class CodeGenerator extends GeneralizingAstVisitor
var body = <JS.Statement>[];
var extensions = _extensionsToImplement(classElem);
_initExtensionSymbols(classElem, methods, fields, body);
+ _emitSuperHelperSymbols(_superHelperSymbols, body);
// Emit the class, e.g. `core.Object = class Object { ... }`
_defineClass(classElem, className, classExpr, body);
@@ -619,6 +625,14 @@ class CodeGenerator extends GeneralizingAstVisitor
return _statement(body);
}
+ void _emitSuperHelperSymbols(
+ List<JS.TemporaryId> superHelperSymbols, List<JS.Statement> body) {
+ for (var id in superHelperSymbols) {
+ body.add(js.statement('const # = Symbol(#)', [id, js.string(id.name)]));
+ }
+ superHelperSymbols.clear();
+ }
+
void _registerPropertyOverrides(
ClassElement classElem,
JS.Expression className,
@@ -897,6 +911,10 @@ class CodeGenerator extends GeneralizingAstVisitor
jsMethods.add(_emitIterable(type));
}
+ // Add all of the super helper methods
+ jsMethods.addAll(_superHelpers);
+ _superHelpers.clear();
+
return jsMethods.where((m) => m != null).toList(growable: false);
}
@@ -1630,7 +1648,7 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
- JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) {
+ JS.Method _emitMethodDeclaration(InterfaceType type, MethodDeclaration node) {
if (node.isAbstract) {
return null;
}
@@ -1956,8 +1974,11 @@ class CodeGenerator extends GeneralizingAstVisitor
} else {
_asyncStarController = null;
}
+ var savedSuperAllowed = _superAllowed;
+ _superAllowed = false;
// Visit the body with our async* controller set.
var jsBody = _visit(body);
+ _superAllowed = savedSuperAllowed;
_asyncStarController = savedController;
DartType returnType = _getExpectedReturnType(element);
@@ -2003,8 +2024,12 @@ class CodeGenerator extends GeneralizingAstVisitor
/// function instantiation.
@override
JS.Expression visitSimpleIdentifier(SimpleIdentifier node) {
- return _applyFunctionTypeArguments(
- _emitSimpleIdentifier(node), node.staticElement, node.staticType);
+ var typeArgs = _getTypeArgs(node.staticElement, node.staticType);
+ var simpleId = _emitSimpleIdentifier(node);
+ if (typeArgs == null) {
+ return simpleId;
+ }
+ return js.call('dart.gbind(#, #)', [simpleId, typeArgs]);
}
/// Emits a simple identifier, handling implicit `this` as well as
@@ -2384,8 +2409,59 @@ class CodeGenerator extends GeneralizingAstVisitor
return _emitMethodCall(target, node);
}
- /// Emits a (possibly generic) instance method call.
JS.Expression _emitMethodCall(Expression target, MethodInvocation node) {
+ List<JS.Expression> args = _visit(node.argumentList);
+ var typeArgs = _emitInvokeTypeArguments(node);
+
+ if (target is SuperExpression && !_superAllowed) {
+ return _emitSuperHelperCall(typeArgs, args, target, node);
+ }
+
+ return _emitMethodCallInternal(target, node, args, typeArgs);
+ }
+
+ JS.Expression _emitSuperHelperCall(List<JS.Expression> typeArgs,
+ List<JS.Expression> args, SuperExpression target, MethodInvocation node) {
+ var fakeTypeArgs =
+ typeArgs?.map((_) => new JS.TemporaryId('a'))?.toList(growable: false);
+ var fakeArgs =
+ args.map((_) => new JS.TemporaryId('a')).toList(growable: false);
+ var combinedFakeArgs = <JS.TemporaryId>[];
+ if (fakeTypeArgs != null) {
+ combinedFakeArgs.addAll(fakeTypeArgs);
+ }
+ combinedFakeArgs.addAll(fakeArgs);
+
+ var forwardedCall =
+ _emitMethodCallInternal(target, node, fakeArgs, fakeTypeArgs);
+ var superForwarder = _getSuperHelperFor(
+ node.methodName.name, forwardedCall, combinedFakeArgs);
+
+ var combinedRealArgs = <JS.Expression>[];
+ if (typeArgs != null) {
+ combinedRealArgs.addAll(typeArgs);
+ }
+ combinedRealArgs.addAll(args);
+
+ return js.call('this.#(#)', [superForwarder, combinedRealArgs]);
+ }
+
+ JS.Expression _getSuperHelperFor(String name, JS.Expression forwardedCall,
+ List<JS.Expression> helperArgs) {
+ var helperMethod =
+ new JS.Fun(helperArgs, new JS.Block([new JS.Return(forwardedCall)]));
+ var helperMethodName = new JS.TemporaryId('super\$$name');
+ _superHelperSymbols.add(helperMethodName);
+ _superHelpers.add(new JS.Method(helperMethodName, helperMethod));
+ return helperMethodName;
+ }
+
+ /// Emits a (possibly generic) instance method call.
+ JS.Expression _emitMethodCallInternal(
+ Expression target,
+ MethodInvocation node,
+ List<JS.Expression> args,
+ List<JS.Expression> typeArgs) {
var type = getStaticType(target);
var name = node.methodName.name;
var element = node.methodName.staticElement;
@@ -2393,8 +2469,6 @@ class CodeGenerator extends GeneralizingAstVisitor
var memberName = _emitMemberName(name, type: type, isStatic: isStatic);
JS.Expression jsTarget = _visit(target);
- var typeArgs = _emitInvokeTypeArguments(node);
- List<JS.Expression> args = _visit(node.argumentList);
if (DynamicInvoke.get(target)) {
if (typeArgs != null) {
return js.call('dart.dgsend(#, #, #, #)',
@@ -2410,6 +2484,7 @@ class CodeGenerator extends GeneralizingAstVisitor
}
jsTarget = new JS.PropertyAccess(jsTarget, memberName);
+
if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs);
if (DynamicInvoke.get(node.methodName)) {
@@ -3544,8 +3619,45 @@ class CodeGenerator extends GeneralizingAstVisitor
if (member is PropertyAccessorElement) {
member = (member as PropertyAccessorElement).variable;
}
+ String memberName = memberId.name;
+ var typeArgs = _getTypeArgs(member, resultType);
+
+ if (target is SuperExpression && !_superAllowed) {
+ return _emitSuperHelperAccess(target, member, memberName, typeArgs);
+ }
+ return _emitAccessInternal(target, member, memberName, typeArgs);
+ }
+
+ JS.Expression _emitSuperHelperAccess(SuperExpression target, Element member,
+ String memberName, List<JS.Expression> typeArgs) {
+ var fakeTypeArgs =
+ typeArgs?.map((_) => new JS.TemporaryId('a'))?.toList(growable: false);
+
+ var forwardedAccess =
+ _emitAccessInternal(target, member, memberName, fakeTypeArgs);
+ var superForwarder = _getSuperHelperFor(
+ memberName, forwardedAccess, fakeTypeArgs ?? const []);
+
+ return js.call('this.#(#)', [superForwarder, typeArgs ?? const []]);
+ }
+
+ List<JS.Expression> _getTypeArgs(Element member, DartType instantiated) {
+ DartType type;
+ if (member is ExecutableElement) {
+ type = member.type;
+ } else if (member is VariableElement) {
+ type = member.type;
+ }
+
+ // TODO(jmesserly): handle explicitly passed type args.
+ if (type == null) return null;
+ return _emitFunctionTypeArguments(type, instantiated);
+ }
+
+ JS.Expression _emitAccessInternal(Expression target, Element member,
+ String memberName, List<JS.Expression> typeArgs) {
bool isStatic = member is ClassMemberElement && member.isStatic;
- var name = _emitMemberName(memberId.name,
+ var name = _emitMemberName(memberName,
type: getStaticType(target), isStatic: isStatic);
if (DynamicInvoke.get(target)) {
return js.call('dart.dload(#, #)', [_visit(target), name]);
@@ -3565,34 +3677,19 @@ class CodeGenerator extends GeneralizingAstVisitor
// Tear-off methods: explicitly bind it.
if (isSuper) {
result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]);
- } else if (_isObjectMemberCall(target, memberId.name)) {
+ } else if (_isObjectMemberCall(target, memberName)) {
result = js.call('dart.bind(#, #, dart.#)', [jsTarget, name, name]);
} else {
result = js.call('dart.bind(#, #)', [jsTarget, name]);
}
- } else if (_isObjectMemberCall(target, memberId.name)) {
+ } else if (_isObjectMemberCall(target, memberName)) {
result = js.call('dart.#(#)', [name, jsTarget]);
} else {
result = js.call('#.#', [jsTarget, name]);
}
- return _applyFunctionTypeArguments(result, member, resultType);
- }
-
- /// If this is an inferred instantiation of a generic function/method, this
- /// will add the inferred type arguments.
- JS.Expression _applyFunctionTypeArguments(
- JS.Expression result, Element member, DartType instantiated) {
- DartType type;
- if (member is ExecutableElement) {
- type = member.type;
- } else if (member is VariableElement) {
- type = member.type;
+ if (typeArgs == null) {
+ return result;
}
-
- // TODO(jmesserly): handle explicitly passed type args.
- if (type == null) return result;
- var typeArgs = _emitFunctionTypeArguments(type, instantiated);
- if (typeArgs == null) return result;
return js.call('dart.gbind(#, #)', [result, typeArgs]);
}
@@ -3790,8 +3887,12 @@ class CodeGenerator extends GeneralizingAstVisitor
@override
visitTryStatement(TryStatement node) {
- return new JS.Try(_visit(node.body), _visitCatch(node.catchClauses),
- _visit(node.finallyBlock));
+ var savedSuperAllowed = _superAllowed;
+ _superAllowed = false;
+ var finallyBlock = _visit(node.finallyBlock);
+ _superAllowed = savedSuperAllowed;
+ return new JS.Try(
+ _visit(node.body), _visitCatch(node.catchClauses), finallyBlock);
}
_visitCatch(NodeList<CatchClause> clauses) {
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | lib/src/compiler/source_map_printer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698