@@ -1130,7 +1130,7 @@ export class Program extends DiagnosticEmitter {
1130
1130
break ;
1131
1131
}
1132
1132
case NodeKind . InterfaceDeclaration : {
1133
- this . initializeInterface ( < InterfaceDeclaration > statement , file , queuedExtends ) ;
1133
+ this . initializeInterface ( < InterfaceDeclaration > statement , file , queuedImplements ) ;
1134
1134
break ;
1135
1135
}
1136
1136
case NodeKind . NamespaceDeclaration : {
@@ -1303,64 +1303,45 @@ export class Program extends DiagnosticEmitter {
1303
1303
}
1304
1304
}
1305
1305
1306
- // resolve prototypes of extended classes or interfaces
1306
+ // resolve prototypes of extended classes
1307
1307
let resolver = this . resolver ;
1308
1308
for ( let i = 0 , k = queuedExtends . length ; i < k ; ++ i ) {
1309
1309
let thisPrototype = queuedExtends [ i ] ;
1310
+ assert ( thisPrototype . kind == ElementKind . ClassPrototype ) ;
1310
1311
let extendsNode = assert ( thisPrototype . extendsNode ) ; // must be present if in queuedExtends
1311
1312
let baseElement = resolver . resolveTypeName ( extendsNode . name , null , thisPrototype . parent ) ;
1312
1313
if ( ! baseElement ) continue ;
1313
- if ( thisPrototype . kind == ElementKind . ClassPrototype ) {
1314
- if ( baseElement . kind == ElementKind . ClassPrototype ) {
1315
- let basePrototype = < ClassPrototype > baseElement ;
1316
- if ( basePrototype . hasDecorator ( DecoratorFlags . Final ) ) {
1317
- this . error (
1318
- DiagnosticCode . Class_0_is_final_and_cannot_be_extended ,
1319
- extendsNode . range , basePrototype . identifierNode . text
1320
- ) ;
1321
- }
1322
- if (
1323
- basePrototype . hasDecorator ( DecoratorFlags . Unmanaged ) !=
1324
- thisPrototype . hasDecorator ( DecoratorFlags . Unmanaged )
1325
- ) {
1326
- this . error (
1327
- DiagnosticCode . Unmanaged_classes_cannot_extend_managed_classes_and_vice_versa ,
1328
- Range . join ( thisPrototype . identifierNode . range , extendsNode . range )
1329
- ) ;
1330
- }
1331
- if ( ! thisPrototype . extends ( basePrototype ) ) {
1332
- thisPrototype . basePrototype = basePrototype ;
1333
- } else {
1334
- this . error (
1335
- DiagnosticCode . _0_is_referenced_directly_or_indirectly_in_its_own_base_expression ,
1336
- basePrototype . identifierNode . range ,
1337
- basePrototype . identifierNode . text ,
1338
- ) ;
1339
- }
1340
- } else {
1314
+ if ( baseElement . kind == ElementKind . ClassPrototype ) {
1315
+ let basePrototype = < ClassPrototype > baseElement ;
1316
+ if ( basePrototype . hasDecorator ( DecoratorFlags . Final ) ) {
1341
1317
this . error (
1342
- DiagnosticCode . A_class_may_only_extend_another_class ,
1343
- extendsNode . range
1318
+ DiagnosticCode . Class_0_is_final_and_cannot_be_extended ,
1319
+ extendsNode . range , basePrototype . identifierNode . text
1344
1320
) ;
1345
1321
}
1346
- } else if ( thisPrototype . kind == ElementKind . InterfacePrototype ) {
1347
- if ( baseElement . kind == ElementKind . InterfacePrototype ) {
1348
- const basePrototype = < InterfacePrototype > baseElement ;
1349
- if ( ! thisPrototype . extends ( basePrototype ) ) {
1350
- thisPrototype . basePrototype = basePrototype ;
1351
- } else {
1352
- this . error (
1353
- DiagnosticCode . _0_is_referenced_directly_or_indirectly_in_its_own_base_expression ,
1354
- basePrototype . identifierNode . range ,
1355
- basePrototype . identifierNode . text ,
1356
- ) ;
1357
- }
1322
+ if (
1323
+ basePrototype . hasDecorator ( DecoratorFlags . Unmanaged ) !=
1324
+ thisPrototype . hasDecorator ( DecoratorFlags . Unmanaged )
1325
+ ) {
1326
+ this . error (
1327
+ DiagnosticCode . Unmanaged_classes_cannot_extend_managed_classes_and_vice_versa ,
1328
+ Range . join ( thisPrototype . identifierNode . range , extendsNode . range )
1329
+ ) ;
1330
+ }
1331
+ if ( ! thisPrototype . extends ( basePrototype ) ) {
1332
+ thisPrototype . basePrototype = basePrototype ;
1358
1333
} else {
1359
1334
this . error (
1360
- DiagnosticCode . An_interface_can_only_extend_an_interface ,
1361
- extendsNode . range
1335
+ DiagnosticCode . _0_is_referenced_directly_or_indirectly_in_its_own_base_expression ,
1336
+ basePrototype . identifierNode . range ,
1337
+ basePrototype . identifierNode . text ,
1362
1338
) ;
1363
1339
}
1340
+ } else {
1341
+ this . error (
1342
+ DiagnosticCode . A_class_may_only_extend_another_class ,
1343
+ extendsNode . range
1344
+ ) ;
1364
1345
}
1365
1346
}
1366
1347
@@ -1399,7 +1380,7 @@ export class Program extends DiagnosticEmitter {
1399
1380
}
1400
1381
}
1401
1382
1402
- // resolve prototypes of implemented interfaces
1383
+ // resolve prototypes of implemented/extended interfaces
1403
1384
for ( let i = 0 , k = queuedImplements . length ; i < k ; ++ i ) {
1404
1385
let thisPrototype = queuedImplements [ i ] ;
1405
1386
let implementsNodes = assert ( thisPrototype . implementsNodes ) ; // must be present if in queuedImplements
@@ -1411,10 +1392,23 @@ export class Program extends DiagnosticEmitter {
1411
1392
let interfacePrototype = < InterfacePrototype > interfaceElement ;
1412
1393
let interfacePrototypes = thisPrototype . interfacePrototypes ;
1413
1394
if ( ! interfacePrototypes ) thisPrototype . interfacePrototypes = interfacePrototypes = new Array ( ) ;
1414
- interfacePrototypes . push ( interfacePrototype ) ;
1395
+ if (
1396
+ thisPrototype . kind == ElementKind . Interface &&
1397
+ thisPrototype . implements ( interfacePrototype )
1398
+ ) {
1399
+ this . error (
1400
+ DiagnosticCode . _0_is_referenced_directly_or_indirectly_in_its_own_base_expression ,
1401
+ interfacePrototype . identifierNode . range ,
1402
+ interfacePrototype . identifierNode . text ,
1403
+ ) ;
1404
+ } else {
1405
+ interfacePrototypes . push ( interfacePrototype ) ;
1406
+ }
1415
1407
} else {
1416
1408
this . error (
1417
- DiagnosticCode . A_class_can_only_implement_an_interface ,
1409
+ thisPrototype . kind == ElementKind . InterfacePrototype
1410
+ ? DiagnosticCode . An_interface_can_only_extend_an_interface
1411
+ : DiagnosticCode . A_class_can_only_implement_an_interface ,
1418
1412
implementsNode . range
1419
1413
) ;
1420
1414
}
@@ -2474,7 +2468,7 @@ export class Program extends DiagnosticEmitter {
2474
2468
break ;
2475
2469
}
2476
2470
case NodeKind . InterfaceDeclaration : {
2477
- element = this . initializeInterface ( < InterfaceDeclaration > declaration , parent , queuedExtends ) ;
2471
+ element = this . initializeInterface ( < InterfaceDeclaration > declaration , parent , queuedImplements ) ;
2478
2472
break ;
2479
2473
}
2480
2474
case NodeKind . NamespaceDeclaration : {
@@ -2625,7 +2619,7 @@ export class Program extends DiagnosticEmitter {
2625
2619
/** Parent element, usually a file or namespace. */
2626
2620
parent : Element ,
2627
2621
/** So far queued `extends` clauses. */
2628
- queuedExtends : ClassPrototype [ ] ,
2622
+ queuedImplements : ClassPrototype [ ] ,
2629
2623
) : InterfacePrototype | null {
2630
2624
let name = declaration . name . text ;
2631
2625
let element = new InterfacePrototype (
@@ -2638,8 +2632,10 @@ export class Program extends DiagnosticEmitter {
2638
2632
) ;
2639
2633
if ( ! parent . add ( name , element ) ) return null ;
2640
2634
2641
- // remember interfaces that extend another interface
2642
- if ( declaration . extendsType ) queuedExtends . push ( element ) ;
2635
+ // remember interfaces that extend other interfaces
2636
+ // Note: See the corresponding note in parseClassOrInterface (in parser.ts) for
2637
+ // further information as to why implementsTypes is used.
2638
+ if ( declaration . implementsTypes ) queuedImplements . push ( element ) ;
2643
2639
2644
2640
let memberDeclarations = declaration . members ;
2645
2641
for ( let i = 0 , k = memberDeclarations . length ; i < k ; ++ i ) {
@@ -2762,7 +2758,7 @@ export class Program extends DiagnosticEmitter {
2762
2758
break ;
2763
2759
}
2764
2760
case NodeKind . InterfaceDeclaration : {
2765
- this . initializeInterface ( < InterfaceDeclaration > member , original , queuedExtends ) ;
2761
+ this . initializeInterface ( < InterfaceDeclaration > member , original , queuedImplements ) ;
2766
2762
break ;
2767
2763
}
2768
2764
case NodeKind . NamespaceDeclaration : {
@@ -4298,6 +4294,24 @@ export class ClassPrototype extends DeclaredElement {
4298
4294
return false ;
4299
4295
}
4300
4296
4297
+ implements ( other : InterfacePrototype , seen : Set < InterfacePrototype > | null = null ) : bool {
4298
+ if ( this . interfacePrototypes ) {
4299
+ if ( ! seen ) seen = new Set ( ) ;
4300
+ let interfacePrototypes = assert ( this . interfacePrototypes ) ;
4301
+
4302
+ for ( let i = 0 , k = interfacePrototypes . length ; i < k ; ++ i ) {
4303
+ let prototype = unchecked ( interfacePrototypes [ i ] ) ;
4304
+
4305
+ if ( prototype == other ) return true ;
4306
+ if ( seen . has ( prototype ) ) continue ;
4307
+ seen . add ( prototype ) ;
4308
+
4309
+ if ( prototype . implements ( other , seen ) ) return true ;
4310
+ }
4311
+ }
4312
+ return false ;
4313
+ }
4314
+
4301
4315
/** Adds an element as an instance member of this one. Returns the previous element if a duplicate. */
4302
4316
addInstance ( name : string , element : DeclaredElement ) : bool {
4303
4317
let originalDeclaration = element . declaration ;
@@ -4557,9 +4571,11 @@ export class Class extends TypedElement {
4557
4571
// Start with the interface itself, adding this class and its extenders to
4558
4572
// its implementers. Repeat for the interface's bases that are indirectly
4559
4573
// implemented by means of being extended by the interface.
4560
- let nextIface : Interface | null = iface ;
4574
+ // TODO: Maybe add a fast path when `iface` has no bases?
4575
+ let ifaceStack = [ iface ] ;
4561
4576
let extenders = this . extenders ;
4562
4577
do {
4578
+ let nextIface = assert ( ifaceStack . pop ( ) ) ;
4563
4579
let implementers = nextIface . implementers ;
4564
4580
if ( ! implementers ) nextIface . implementers = implementers = new Set ( ) ;
4565
4581
implementers . add ( this ) ;
@@ -4569,8 +4585,19 @@ export class Class extends TypedElement {
4569
4585
implementers . add ( extender ) ;
4570
4586
}
4571
4587
}
4572
- nextIface = < Interface | null > nextIface . base ;
4573
- } while ( nextIface ) ;
4588
+
4589
+ let nextIfaces = nextIface . interfaces ;
4590
+ if ( ! nextIfaces ) continue ;
4591
+
4592
+ let stackIndex = ifaceStack . length ;
4593
+
4594
+ // Calls the internal ensureCapacity() when run in the bootstrapped compiler:
4595
+ ifaceStack . length = stackIndex + nextIfaces . size ;
4596
+
4597
+ for ( let _values = Set_values ( nextIfaces ) , i = 0 , k = _values . length ; i < k ; ++ i ) {
4598
+ ifaceStack [ stackIndex ++ ] = unchecked ( _values [ i ] ) ;
4599
+ }
4600
+ } while ( ifaceStack . length ) ;
4574
4601
}
4575
4602
4576
4603
/** Adds an interface. */
@@ -4589,7 +4616,7 @@ export class Class extends TypedElement {
4589
4616
if ( target . isInterface ) {
4590
4617
if ( this . isInterface ) {
4591
4618
// targetInterface = thisInterface
4592
- return this == target || this . extends ( target ) ;
4619
+ return this == target || this . implements ( < Interface > target ) ;
4593
4620
} else {
4594
4621
// targetInterface = thisClass
4595
4622
return this . implements ( < Interface > target ) ;
@@ -4863,7 +4890,7 @@ export class Class extends TypedElement {
4863
4890
return true ;
4864
4891
}
4865
4892
4866
- /** Tests if this class or interface extends the given class or interface . */
4893
+ /** Tests if this class extends the given class. */
4867
4894
extends ( other : Class ) : bool {
4868
4895
return other . hasExtender ( this ) ;
4869
4896
}
0 commit comments