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

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

Issue 2069903002: Partial fix for call methods #542 (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: fix comment Created 4 years, 6 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') | test/browser/language_tests.js » ('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 d0bdf2043190b9a91a642c7f84ea0751b1be688b..4c723483646594d53e5e30d8a04999bf77258898 100644
--- a/lib/src/compiler/code_generator.dart
+++ b/lib/src/compiler/code_generator.dart
@@ -701,6 +701,10 @@ class CodeGenerator extends GeneralizingAstVisitor
var fields = <FieldDeclaration>[];
var staticFields = <FieldDeclaration>[];
var methods = <MethodDeclaration>[];
+
+ // The "call" method or getter, if one exists. This can also be
+ // "noSuchMethod" method, because nSM could implement "call".
+ ExecutableElement callMethod;
for (var member in node.members) {
if (member is ConstructorDeclaration) {
ctors.add(member);
@@ -708,6 +712,16 @@ class CodeGenerator extends GeneralizingAstVisitor
(member.isStatic ? staticFields : fields).add(member);
} else if (member is MethodDeclaration) {
methods.add(member);
+ var name = member.name.name;
+ if (name == 'call' && !member.isSetter) {
+ callMethod = member.element;
+ } else if (name == 'noSuchMethod' &&
+ !member.isGetter &&
+ !member.isSetter &&
+ // Exclude SDK because we know they don't use nSM to implement call.
+ !classElem.library.source.isInSystemLibrary) {
+ callMethod ??= member.element;
+ }
}
}
@@ -738,7 +752,7 @@ class CodeGenerator extends GeneralizingAstVisitor
_emitSuperHelperSymbols(_superHelperSymbols, body);
// Emit the class, e.g. `core.Object = class Object { ... }`
- _defineClass(classElem, className, classExpr, body);
+ _defineClass(classElem, className, classExpr, callMethod, body);
// Emit things that come after the ES6 `class ... { ... }`.
var jsPeerName = _getJSPeerName(classElem);
@@ -746,7 +760,7 @@ class CodeGenerator extends GeneralizingAstVisitor
_emitClassTypeTests(classElem, className, body);
- _defineNamedConstructors(ctors, body, className);
+ _defineNamedConstructors(ctors, body, className, callMethod);
_emitVirtualFieldSymbols(virtualFieldSymbols, body);
_emitClassSignature(methods, classElem, ctors, extensions, className, body);
_defineExtensionMembers(extensions, className, body);
@@ -764,6 +778,45 @@ class CodeGenerator extends GeneralizingAstVisitor
return _statement(body);
}
+ /// Emits code to support a class with a "call" method and an unnamed
+ /// constructor.
+ ///
+ /// This ensures instances created by the unnamed constructor are functions.
+ /// Named constructors are handled elsewhere, see [_defineNamedConstructors].
+ JS.Expression _emitCallableClass(JS.ClassExpression classExpr,
+ ConstructorElement unnamedCtor, ExecutableElement callMethod) {
+ var ctor = new JS.NamedFunction(
+ classExpr.name, _emitCallableClassConstructor(unnamedCtor, callMethod));
+
+ // Name the constructor function the same as the class.
+ return js.call('dart.callableClass(#, #)', [ctor, classExpr]);
+ }
+
+ JS.Fun _emitCallableClassConstructor(
+ ConstructorElement ctor, ExecutableElement callMethod) {
+ bool dynamicCall = false;
+ if (callMethod is PropertyAccessorElement) {
+ assert(callMethod.isGetter);
+ dynamicCall = callMethod.returnType is! FunctionType;
vsm 2016/06/15 19:52:26 Do we need a dcall here if one of the param types
Jennifer Messerly 2016/06/15 20:16:51 I don't think so. Those dcalls will be handled by
+ } else if (callMethod.name == 'noSuchMethod') {
+ dynamicCall = true;
+ }
+
+ var callCall =
+ dynamicCall ? 'dart.dcall(self, args)' : 'self.call.apply(self, args)';
+ return js.call(
+ r'''function (...args) {
+ const self = this;
+ function call(...args) {
+ return #;
+ }
+ call.__proto__ = this.__proto__;
+ call.#.apply(call, args);
+ return call;
+ }''',
+ [js.call(callCall), _constructorName(ctor)]);
+ }
+
void _emitClassTypeTests(ClassElement classElem, JS.Expression className,
List<JS.Statement> body) {
if (classElem == objectClass) {
@@ -978,12 +1031,26 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
- void _defineClass(ClassElement classElem, JS.Expression className,
- JS.ClassExpression classExpr, List<JS.Statement> body) {
+ void _defineClass(
+ ClassElement classElem,
+ JS.Expression className,
+ JS.ClassExpression classExpr,
+ ExecutableElement callMethod,
+ List<JS.Statement> body) {
+ JS.Expression callableClass;
+ if (callMethod != null && classElem.unnamedConstructor != null) {
+ callableClass = _emitCallableClass(
+ classExpr, classElem.unnamedConstructor, callMethod);
+ }
+
if (classElem.typeParameters.isNotEmpty) {
- body.add(new JS.ClassDeclaration(classExpr));
+ if (callableClass != null) {
+ body.add(js.statement('const # = #;', [classExpr.name, callableClass]));
+ } else {
+ body.add(new JS.ClassDeclaration(classExpr));
+ }
} else {
- body.add(js.statement('# = #;', [className, classExpr]));
+ body.add(js.statement('# = #;', [className, callableClass ?? classExpr]));
}
}
@@ -1400,12 +1467,23 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
- void _defineNamedConstructors(List<ConstructorDeclaration> ctors,
- List<JS.Statement> body, JS.Expression className) {
+ void _defineNamedConstructors(
+ List<ConstructorDeclaration> ctors,
+ List<JS.Statement> body,
+ JS.Expression className,
+ ExecutableElement callMethod) {
+ var code = callMethod != null
+ ? 'dart.defineNamedConstructorCallable(#, #, #);'
+ : 'dart.defineNamedConstructor(#, #)';
+
for (ConstructorDeclaration member in ctors) {
if (member.name != null && member.factoryKeyword == null) {
- body.add(js.statement('dart.defineNamedConstructor(#, #);',
- [className, _constructorName(member.element)]));
+ var args = [className, _constructorName(member.element)];
+ if (callMethod != null) {
+ args.add(_emitCallableClassConstructor(member.element, callMethod));
+ }
+
+ body.add(js.statement(code, args));
}
}
}
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | test/browser/language_tests.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698