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) { |