@@ -754,14 +754,13 @@ class CodeGenerator extends GeneralizingAstVisitor
754754 JS .Statement visitEnumDeclaration (EnumDeclaration node) {
755755 var element = node.element;
756756 var type = element.type;
757- var name = js.string (type.name);
758757
759758 // Generate a class per section 13 of the spec.
760759 // TODO(vsm): Generate any accompanying metadata
761760
762761 // Create constructor and initialize index
763- var constructor = new JS .Method (
764- name, js.call ('function(index) { this.index = index; }' ) as JS .Fun );
762+ var constructor = new JS .Method (_propertyName ( 'new' ),
763+ js.call ('function(index) { this.index = index; }' ) as JS .Fun );
765764 var fields = new List <FieldElement >.from (
766765 element.fields.where ((f) => f.type == type));
767766
@@ -916,7 +915,28 @@ class CodeGenerator extends GeneralizingAstVisitor
916915 // Iff no constructor is specified for a class C, it implicitly has a
917916 // default constructor `C() : super() {}`, unless C is class Object.
918917 var jsMethods = < JS .Method > [];
919- if (ctors.isEmpty && ! isObject) {
918+ if (isObject) {
919+ // Implements Dart constructor behavior.
920+ //
921+ // Because of ES6 constructor restrictions (`this` is not available until
922+ // `super` is called), we cannot emit an actual ES6 `constructor` on our
923+ // classes and preserve the Dart initialization order.
924+ //
925+ // Instead we use the same trick as named constructors, and do them as
926+ // instance methods that perform initialization.
927+ //
928+ // Therefore, dart:core Object gets the one real `constructor` and
929+ // immediately bounces to the `new() { ... }` initializer, letting us
930+ // bypass the ES6 restrictions.
931+ //
932+ // TODO(jmesserly): we'll need to rethink this.
933+ // See <https://github.com/dart-lang/dev_compiler/issues/51>.
934+ // This level of indirection will hurt performance.
935+ jsMethods.add (new JS .Method (
936+ _propertyName ('constructor' ),
937+ js.call ('function(...args) { return this.new.apply(this, args); }' )
938+ as JS .Fun ));
939+ } else if (ctors.isEmpty) {
920940 jsMethods.add (_emitImplicitConstructor (node, fields, virtualFields));
921941 }
922942
@@ -1117,7 +1137,7 @@ class CodeGenerator extends GeneralizingAstVisitor
11171137 for (ConstructorDeclaration member in ctors) {
11181138 if (member.name != null && member.factoryKeyword == null ) {
11191139 body.add (js.statement ('dart.defineNamedConstructor(#, #);' ,
1120- [className, _emitMemberName (member.name.name, isStatic : true )]));
1140+ [className, _constructorName (member.element )]));
11211141 }
11221142 }
11231143 }
@@ -1320,15 +1340,14 @@ class CodeGenerator extends GeneralizingAstVisitor
13201340 var superCall = _superConstructorCall (node.element);
13211341 if (fields.isEmpty && superCall == null ) return null ;
13221342
1323- dynamic body = _initializeFields (node, fields, virtualFields);
1343+ var initFields = _initializeFields (node, fields, virtualFields);
1344+ List <JS .Statement > body = [initFields];
13241345 if (superCall != null ) {
1325- body = [
1326- [body, superCall]
1327- ];
1346+ body.add (superCall);
13281347 }
13291348 var name = _constructorName (node.element.unnamedConstructor);
13301349 return annotate (
1331- new JS .Method (name, js.call ('function() { #; }' , body) as JS .Fun ),
1350+ new JS .Method (name, js.call ('function() { #; }' , [ body] ) as JS .Fun ),
13321351 node,
13331352 node.element);
13341353 }
@@ -1382,36 +1401,10 @@ class CodeGenerator extends GeneralizingAstVisitor
13821401 }
13831402
13841403 // Code generation for Object's constructor.
1385- JS .Block body;
1386- if (isObject &&
1387- node.body is EmptyFunctionBody &&
1388- node.constKeyword != null &&
1389- node.name == null ) {
1390- // Implements Dart constructor behavior. Because of V8 `super`
1391- // [constructor restrictions]
1392- // (https://code.google.com/p/v8/issues/detail?id=3330#c65)
1393- // we cannot currently emit actual ES6 constructors with super calls.
1394- // Instead we use the same trick as named constructors, and do them as
1395- // instance methods that perform initialization.
1396- // TODO(jmesserly): we'll need to rethink this once the ES6 spec and V8
1397- // settles. See <https://github.com/dart-lang/dev_compiler/issues/51>.
1398- // Performance of this pattern is likely to be bad.
1399- name = _propertyName ('constructor' );
1400- // Mark the parameter as no-rename.
1401- body = js.statement ('''{
1402- // Get the class name for this instance.
1403- let name = this.constructor.name;
1404- // Call the default constructor.
1405- let result = void 0;
1406- if (name in this) result = this[name].apply(this, arguments);
1407- return result === void 0 ? this : result;
1408- }''' ) as JS .Block ;
1409- } else {
1410- var savedFunction = _currentFunction;
1411- _currentFunction = node.body;
1412- body = _emitConstructorBody (node, fields, virtualFields);
1413- _currentFunction = savedFunction;
1414- }
1404+ var savedFunction = _currentFunction;
1405+ _currentFunction = node.body;
1406+ var body = _emitConstructorBody (node, fields, virtualFields);
1407+ _currentFunction = savedFunction;
14151408
14161409 // We generate constructors as initializer methods in the class;
14171410 // this allows use of `super` for instance methods/properties.
@@ -1424,16 +1417,11 @@ class CodeGenerator extends GeneralizingAstVisitor
14241417
14251418 JS .Expression _constructorName (ConstructorElement ctor) {
14261419 var name = ctor.name;
1427- if (name != '' ) {
1428- return _emitMemberName (name, isStatic: true );
1420+ if (name == '' ) {
1421+ // Default constructors (factory or not) use `new` as their name.
1422+ return _propertyName ('new' );
14291423 }
1430-
1431- // Factory default constructors use `new` as their name, for readability
1432- // Other default constructors use the class name, as they aren't called
1433- // from call sites, but rather from Object's constructor.
1434- // TODO(jmesserly): revisit in the context of Dart metaclasses, and cleaning
1435- // up constructors to integrate more closely with ES6.
1436- return _propertyName (ctor.isFactory ? 'new' : ctor.enclosingElement.name);
1424+ return _emitMemberName (name, isStatic: true );
14371425 }
14381426
14391427 JS .Block _emitConstructorBody (
@@ -1487,30 +1475,40 @@ class CodeGenerator extends GeneralizingAstVisitor
14871475 @override
14881476 JS .Statement visitRedirectingConstructorInvocation (
14891477 RedirectingConstructorInvocation node) {
1490- var name = _constructorName (node.staticElement);
1491- return js.statement ('this.#(#);' , [name, _visit (node.argumentList)]);
1478+ var ctor = node.staticElement;
1479+ var cls = ctor.enclosingElement as ClassElement ;
1480+ // We can't dispatch to the constructor with `this.new` as that might hit a
1481+ // derived class constructor with the same name.
1482+ return js.statement ('#.prototype.#.call(this, #);' , [
1483+ new JS .Identifier (cls.name),
1484+ _constructorName (ctor),
1485+ _visit (node.argumentList)
1486+ ]);
14921487 }
14931488
14941489 JS .Statement _superConstructorCall (ClassElement element,
14951490 [SuperConstructorInvocation node]) {
1491+ if (element.supertype == null ) {
1492+ assert (element.type.isObject || options.unsafeForceCompile);
1493+ return null ;
1494+ }
1495+
14961496 ConstructorElement superCtor;
14971497 if (node != null ) {
14981498 superCtor = node.staticElement;
14991499 } else {
15001500 // Get the supertype's unnamed constructor.
15011501 superCtor = element.supertype.element.unnamedConstructor;
1502- if (superCtor == null ) {
1503- // This will only happen if the code has errors:
1504- // we're trying to generate an implicit constructor for a type where
1505- // we don't have a default constructor in the supertype.
1506- assert (options.unsafeForceCompile);
1507- return null ;
1508- }
15091502 }
15101503
15111504 if (superCtor == null ) {
1512- print ('Error generating: ${element .displayName }' );
1505+ // This will only happen if the code has errors:
1506+ // we're trying to generate an implicit constructor for a type where
1507+ // we don't have a default constructor in the supertype.
1508+ assert (options.unsafeForceCompile);
1509+ return null ;
15131510 }
1511+
15141512 if (superCtor.name == '' && ! _shouldCallUnnamedSuperCtor (element)) {
15151513 return null ;
15161514 }
@@ -3071,7 +3069,6 @@ class CodeGenerator extends GeneralizingAstVisitor
30713069 JS .Expression emitNew () {
30723070 JS .Expression ctor;
30733071 bool isFactory = false ;
3074- // var element = node.staticElement;
30753072 if (element == null ) {
30763073 // TODO(jmesserly): this only happens if we had a static error.
30773074 // Should we generate a throw instead?
0 commit comments