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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | test/browser/language_tests.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'dart:collection' show HashMap, HashSet; 5 import 'dart:collection' show HashMap, HashSet;
6 import 'dart:math' show min, max; 6 import 'dart:math' show min, max;
7 7
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
(...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 if (findAnnotation(classElem, isPublicJSAnnotation) != null) return null; 694 if (findAnnotation(classElem, isPublicJSAnnotation) != null) return null;
695 695
696 // If this is a JavaScript type, emit it now and then exit. 696 // If this is a JavaScript type, emit it now and then exit.
697 var jsTypeDef = _emitJsType(classElem); 697 var jsTypeDef = _emitJsType(classElem);
698 if (jsTypeDef != null) return jsTypeDef; 698 if (jsTypeDef != null) return jsTypeDef;
699 699
700 var ctors = <ConstructorDeclaration>[]; 700 var ctors = <ConstructorDeclaration>[];
701 var fields = <FieldDeclaration>[]; 701 var fields = <FieldDeclaration>[];
702 var staticFields = <FieldDeclaration>[]; 702 var staticFields = <FieldDeclaration>[];
703 var methods = <MethodDeclaration>[]; 703 var methods = <MethodDeclaration>[];
704
705 // The "call" method or getter, if one exists. This can also be
706 // "noSuchMethod" method, because nSM could implement "call".
707 ExecutableElement callMethod;
704 for (var member in node.members) { 708 for (var member in node.members) {
705 if (member is ConstructorDeclaration) { 709 if (member is ConstructorDeclaration) {
706 ctors.add(member); 710 ctors.add(member);
707 } else if (member is FieldDeclaration) { 711 } else if (member is FieldDeclaration) {
708 (member.isStatic ? staticFields : fields).add(member); 712 (member.isStatic ? staticFields : fields).add(member);
709 } else if (member is MethodDeclaration) { 713 } else if (member is MethodDeclaration) {
710 methods.add(member); 714 methods.add(member);
715 var name = member.name.name;
716 if (name == 'call' && !member.isSetter) {
717 callMethod = member.element;
718 } else if (name == 'noSuchMethod' &&
719 !member.isGetter &&
720 !member.isSetter &&
721 // Exclude SDK because we know they don't use nSM to implement call.
722 !classElem.library.source.isInSystemLibrary) {
723 callMethod ??= member.element;
724 }
711 } 725 }
712 } 726 }
713 727
714 JS.Expression className; 728 JS.Expression className;
715 if (classElem.typeParameters.isNotEmpty) { 729 if (classElem.typeParameters.isNotEmpty) {
716 // Generic classes will be defined inside a function that closes over the 730 // Generic classes will be defined inside a function that closes over the
717 // type parameter. So we can use their local variable name directly. 731 // type parameter. So we can use their local variable name directly.
718 className = new JS.Identifier(classElem.name); 732 className = new JS.Identifier(classElem.name);
719 } else { 733 } else {
720 className = _emitTopLevelName(classElem); 734 className = _emitTopLevelName(classElem);
(...skipping 10 matching lines...) Expand all
731 var classExpr = _emitClassExpression(classElem, 745 var classExpr = _emitClassExpression(classElem,
732 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), 746 _emitClassMethods(node, ctors, fields, superclasses, virtualFields),
733 fields: allFields); 747 fields: allFields);
734 748
735 var body = <JS.Statement>[]; 749 var body = <JS.Statement>[];
736 var extensions = _extensionsToImplement(classElem); 750 var extensions = _extensionsToImplement(classElem);
737 _initExtensionSymbols(classElem, methods, fields, body); 751 _initExtensionSymbols(classElem, methods, fields, body);
738 _emitSuperHelperSymbols(_superHelperSymbols, body); 752 _emitSuperHelperSymbols(_superHelperSymbols, body);
739 753
740 // Emit the class, e.g. `core.Object = class Object { ... }` 754 // Emit the class, e.g. `core.Object = class Object { ... }`
741 _defineClass(classElem, className, classExpr, body); 755 _defineClass(classElem, className, classExpr, callMethod, body);
742 756
743 // Emit things that come after the ES6 `class ... { ... }`. 757 // Emit things that come after the ES6 `class ... { ... }`.
744 var jsPeerName = _getJSPeerName(classElem); 758 var jsPeerName = _getJSPeerName(classElem);
745 _setBaseClass(classElem, className, jsPeerName, body); 759 _setBaseClass(classElem, className, jsPeerName, body);
746 760
747 _emitClassTypeTests(classElem, className, body); 761 _emitClassTypeTests(classElem, className, body);
748 762
749 _defineNamedConstructors(ctors, body, className); 763 _defineNamedConstructors(ctors, body, className, callMethod);
750 _emitVirtualFieldSymbols(virtualFieldSymbols, body); 764 _emitVirtualFieldSymbols(virtualFieldSymbols, body);
751 _emitClassSignature(methods, classElem, ctors, extensions, className, body); 765 _emitClassSignature(methods, classElem, ctors, extensions, className, body);
752 _defineExtensionMembers(extensions, className, body); 766 _defineExtensionMembers(extensions, className, body);
753 _emitClassMetadata(node.metadata, className, body); 767 _emitClassMetadata(node.metadata, className, body);
754 768
755 JS.Statement classDef = _statement(body); 769 JS.Statement classDef = _statement(body);
756 var typeFormals = classElem.typeParameters; 770 var typeFormals = classElem.typeParameters;
757 if (typeFormals.isNotEmpty) { 771 if (typeFormals.isNotEmpty) {
758 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); 772 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef);
759 } 773 }
760 774
761 body = <JS.Statement>[classDef]; 775 body = <JS.Statement>[classDef];
762 _emitStaticFields(staticFields, staticFieldOverrides, classElem, body); 776 _emitStaticFields(staticFields, staticFieldOverrides, classElem, body);
763 _registerExtensionType(classElem, jsPeerName, body); 777 _registerExtensionType(classElem, jsPeerName, body);
764 return _statement(body); 778 return _statement(body);
765 } 779 }
766 780
781 /// Emits code to support a class with a "call" method and an unnamed
782 /// constructor.
783 ///
784 /// This ensures instances created by the unnamed constructor are functions.
785 /// Named constructors are handled elsewhere, see [_defineNamedConstructors].
786 JS.Expression _emitCallableClass(JS.ClassExpression classExpr,
787 ConstructorElement unnamedCtor, ExecutableElement callMethod) {
788 var ctor = new JS.NamedFunction(
789 classExpr.name, _emitCallableClassConstructor(unnamedCtor, callMethod));
790
791 // Name the constructor function the same as the class.
792 return js.call('dart.callableClass(#, #)', [ctor, classExpr]);
793 }
794
795 JS.Fun _emitCallableClassConstructor(
796 ConstructorElement ctor, ExecutableElement callMethod) {
797 bool dynamicCall = false;
798 if (callMethod is PropertyAccessorElement) {
799 assert(callMethod.isGetter);
800 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
801 } else if (callMethod.name == 'noSuchMethod') {
802 dynamicCall = true;
803 }
804
805 var callCall =
806 dynamicCall ? 'dart.dcall(self, args)' : 'self.call.apply(self, args)';
807 return js.call(
808 r'''function (...args) {
809 const self = this;
810 function call(...args) {
811 return #;
812 }
813 call.__proto__ = this.__proto__;
814 call.#.apply(call, args);
815 return call;
816 }''',
817 [js.call(callCall), _constructorName(ctor)]);
818 }
819
767 void _emitClassTypeTests(ClassElement classElem, JS.Expression className, 820 void _emitClassTypeTests(ClassElement classElem, JS.Expression className,
768 List<JS.Statement> body) { 821 List<JS.Statement> body) {
769 if (classElem == objectClass) { 822 if (classElem == objectClass) {
770 // We rely on ES6 static inheritance. All types that are represented by 823 // We rely on ES6 static inheritance. All types that are represented by
771 // class constructor functions will see these definitions, with [this] 824 // class constructor functions will see these definitions, with [this]
772 // being bound to the class constructor. 825 // being bound to the class constructor.
773 826
774 // The 'instanceof' checks don't work for primitive types (which have fast 827 // The 'instanceof' checks don't work for primitive types (which have fast
775 // definitions below) and don't work for native types. In those cases we 828 // definitions below) and don't work for native types. In those cases we
776 // fall through to the general purpose checking code. 829 // fall through to the general purpose checking code.
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
971 virtualFields[field.element] = virtualField; 1024 virtualFields[field.element] = virtualField;
972 virtualFieldSymbols.add(js.statement( 1025 virtualFieldSymbols.add(js.statement(
973 'const # = Symbol(#.name + "." + #.toString());', 1026 'const # = Symbol(#.name + "." + #.toString());',
974 [virtualField, className, fieldName])); 1027 [virtualField, className, fieldName]));
975 } 1028 }
976 } 1029 }
977 } 1030 }
978 } 1031 }
979 } 1032 }
980 1033
981 void _defineClass(ClassElement classElem, JS.Expression className, 1034 void _defineClass(
982 JS.ClassExpression classExpr, List<JS.Statement> body) { 1035 ClassElement classElem,
1036 JS.Expression className,
1037 JS.ClassExpression classExpr,
1038 ExecutableElement callMethod,
1039 List<JS.Statement> body) {
1040 JS.Expression callableClass;
1041 if (callMethod != null && classElem.unnamedConstructor != null) {
1042 callableClass = _emitCallableClass(
1043 classExpr, classElem.unnamedConstructor, callMethod);
1044 }
1045
983 if (classElem.typeParameters.isNotEmpty) { 1046 if (classElem.typeParameters.isNotEmpty) {
984 body.add(new JS.ClassDeclaration(classExpr)); 1047 if (callableClass != null) {
1048 body.add(js.statement('const # = #;', [classExpr.name, callableClass]));
1049 } else {
1050 body.add(new JS.ClassDeclaration(classExpr));
1051 }
985 } else { 1052 } else {
986 body.add(js.statement('# = #;', [className, classExpr])); 1053 body.add(js.statement('# = #;', [className, callableClass ?? classExpr]));
987 } 1054 }
988 } 1055 }
989 1056
990 void _emitVirtualFieldSymbols( 1057 void _emitVirtualFieldSymbols(
991 List<JS.Statement> virtualFields, List<JS.Statement> body) { 1058 List<JS.Statement> virtualFields, List<JS.Statement> body) {
992 body.addAll(virtualFields); 1059 body.addAll(virtualFields);
993 } 1060 }
994 1061
995 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { 1062 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) {
996 return typeFormals 1063 return typeFormals
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after
1393 body.add(js.statement( 1460 body.add(js.statement(
1394 'dart.setExtensionBaseClass(#, #);', [className, newBaseClass])); 1461 'dart.setExtensionBaseClass(#, #);', [className, newBaseClass]));
1395 } else if (_hasDeferredSupertype.contains(classElem)) { 1462 } else if (_hasDeferredSupertype.contains(classElem)) {
1396 var newBaseClass = _emitType(classElem.type.superclass, 1463 var newBaseClass = _emitType(classElem.type.superclass,
1397 nameType: false, subClass: classElem, className: className); 1464 nameType: false, subClass: classElem, className: className);
1398 body.add( 1465 body.add(
1399 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); 1466 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass]));
1400 } 1467 }
1401 } 1468 }
1402 1469
1403 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, 1470 void _defineNamedConstructors(
1404 List<JS.Statement> body, JS.Expression className) { 1471 List<ConstructorDeclaration> ctors,
1472 List<JS.Statement> body,
1473 JS.Expression className,
1474 ExecutableElement callMethod) {
1475 var code = callMethod != null
1476 ? 'dart.defineNamedConstructorCallable(#, #, #);'
1477 : 'dart.defineNamedConstructor(#, #)';
1478
1405 for (ConstructorDeclaration member in ctors) { 1479 for (ConstructorDeclaration member in ctors) {
1406 if (member.name != null && member.factoryKeyword == null) { 1480 if (member.name != null && member.factoryKeyword == null) {
1407 body.add(js.statement('dart.defineNamedConstructor(#, #);', 1481 var args = [className, _constructorName(member.element)];
1408 [className, _constructorName(member.element)])); 1482 if (callMethod != null) {
1483 args.add(_emitCallableClassConstructor(member.element, callMethod));
1484 }
1485
1486 body.add(js.statement(code, args));
1409 } 1487 }
1410 } 1488 }
1411 } 1489 }
1412 1490
1413 /// Emits static fields for a class, and initialize them eagerly if possible, 1491 /// Emits static fields for a class, and initialize them eagerly if possible,
1414 /// otherwise define them as lazy properties. 1492 /// otherwise define them as lazy properties.
1415 void _emitStaticFields( 1493 void _emitStaticFields(
1416 List<FieldDeclaration> staticFields, 1494 List<FieldDeclaration> staticFields,
1417 Set<FieldElement> staticFieldOverrides, 1495 Set<FieldElement> staticFieldOverrides,
1418 ClassElement classElem, 1496 ClassElement classElem,
(...skipping 3714 matching lines...) Expand 10 before | Expand all | Expand 10 after
5133 } 5211 }
5134 5212
5135 bool isLibraryPrefix(Expression node) => 5213 bool isLibraryPrefix(Expression node) =>
5136 node is SimpleIdentifier && node.staticElement is PrefixElement; 5214 node is SimpleIdentifier && node.staticElement is PrefixElement;
5137 5215
5138 LibraryElement _getLibrary(AnalysisContext c, String uri) => 5216 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
5139 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 5217 c.computeLibraryElement(c.sourceFactory.forUri(uri));
5140 5218
5141 bool _isDartRuntime(LibraryElement l) => 5219 bool _isDartRuntime(LibraryElement l) =>
5142 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 5220 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« 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