@@ -754,14 +754,13 @@ class CodeGenerator extends GeneralizingAstVisitor
754
754
JS .Statement visitEnumDeclaration (EnumDeclaration node) {
755
755
var element = node.element;
756
756
var type = element.type;
757
- var name = js.string (type.name);
758
757
759
758
// Generate a class per section 13 of the spec.
760
759
// TODO(vsm): Generate any accompanying metadata
761
760
762
761
// 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 );
765
764
var fields = new List <FieldElement >.from (
766
765
element.fields.where ((f) => f.type == type));
767
766
@@ -916,7 +915,28 @@ class CodeGenerator extends GeneralizingAstVisitor
916
915
// Iff no constructor is specified for a class C, it implicitly has a
917
916
// default constructor `C() : super() {}`, unless C is class Object.
918
917
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) {
920
940
jsMethods.add (_emitImplicitConstructor (node, fields, virtualFields));
921
941
}
922
942
@@ -1117,7 +1137,7 @@ class CodeGenerator extends GeneralizingAstVisitor
1117
1137
for (ConstructorDeclaration member in ctors) {
1118
1138
if (member.name != null && member.factoryKeyword == null ) {
1119
1139
body.add (js.statement ('dart.defineNamedConstructor(#, #);' ,
1120
- [className, _emitMemberName (member.name.name, isStatic : true )]));
1140
+ [className, _constructorName (member.element )]));
1121
1141
}
1122
1142
}
1123
1143
}
@@ -1320,15 +1340,14 @@ class CodeGenerator extends GeneralizingAstVisitor
1320
1340
var superCall = _superConstructorCall (node.element);
1321
1341
if (fields.isEmpty && superCall == null ) return null ;
1322
1342
1323
- dynamic body = _initializeFields (node, fields, virtualFields);
1343
+ var initFields = _initializeFields (node, fields, virtualFields);
1344
+ List <JS .Statement > body = [initFields];
1324
1345
if (superCall != null ) {
1325
- body = [
1326
- [body, superCall]
1327
- ];
1346
+ body.add (superCall);
1328
1347
}
1329
1348
var name = _constructorName (node.element.unnamedConstructor);
1330
1349
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 ),
1332
1351
node,
1333
1352
node.element);
1334
1353
}
@@ -1382,36 +1401,10 @@ class CodeGenerator extends GeneralizingAstVisitor
1382
1401
}
1383
1402
1384
1403
// 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;
1415
1408
1416
1409
// We generate constructors as initializer methods in the class;
1417
1410
// this allows use of `super` for instance methods/properties.
@@ -1424,16 +1417,11 @@ class CodeGenerator extends GeneralizingAstVisitor
1424
1417
1425
1418
JS .Expression _constructorName (ConstructorElement ctor) {
1426
1419
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' );
1429
1423
}
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 );
1437
1425
}
1438
1426
1439
1427
JS .Block _emitConstructorBody (
@@ -1487,30 +1475,40 @@ class CodeGenerator extends GeneralizingAstVisitor
1487
1475
@override
1488
1476
JS .Statement visitRedirectingConstructorInvocation (
1489
1477
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
+ ]);
1492
1487
}
1493
1488
1494
1489
JS .Statement _superConstructorCall (ClassElement element,
1495
1490
[SuperConstructorInvocation node]) {
1491
+ if (element.supertype == null ) {
1492
+ assert (element.type.isObject || options.unsafeForceCompile);
1493
+ return null ;
1494
+ }
1495
+
1496
1496
ConstructorElement superCtor;
1497
1497
if (node != null ) {
1498
1498
superCtor = node.staticElement;
1499
1499
} else {
1500
1500
// Get the supertype's unnamed constructor.
1501
1501
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
- }
1509
1502
}
1510
1503
1511
1504
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 ;
1513
1510
}
1511
+
1514
1512
if (superCtor.name == '' && ! _shouldCallUnnamedSuperCtor (element)) {
1515
1513
return null ;
1516
1514
}
@@ -3071,7 +3069,6 @@ class CodeGenerator extends GeneralizingAstVisitor
3071
3069
JS .Expression emitNew () {
3072
3070
JS .Expression ctor;
3073
3071
bool isFactory = false ;
3074
- // var element = node.staticElement;
3075
3072
if (element == null ) {
3076
3073
// TODO(jmesserly): this only happens if we had a static error.
3077
3074
// Should we generate a throw instead?
0 commit comments