@@ -1129,7 +1129,7 @@ export class Program extends DiagnosticEmitter {
11291129 break ;
11301130 }
11311131 case NodeKind . InterfaceDeclaration : {
1132- this . initializeInterface ( < InterfaceDeclaration > statement , file , queuedExtends ) ;
1132+ this . initializeInterface ( < InterfaceDeclaration > statement , file , queuedImplements ) ;
11331133 break ;
11341134 }
11351135 case NodeKind . NamespaceDeclaration : {
@@ -1302,64 +1302,45 @@ export class Program extends DiagnosticEmitter {
13021302 }
13031303 }
13041304
1305- // resolve prototypes of extended classes or interfaces
1305+ // resolve prototypes of extended classes
13061306 let resolver = this . resolver ;
13071307 for ( let i = 0 , k = queuedExtends . length ; i < k ; ++ i ) {
13081308 let thisPrototype = queuedExtends [ i ] ;
1309+ assert ( thisPrototype . kind == ElementKind . ClassPrototype ) ;
13091310 let extendsNode = assert ( thisPrototype . extendsNode ) ; // must be present if in queuedExtends
13101311 let baseElement = resolver . resolveTypeName ( extendsNode . name , thisPrototype . parent ) ;
13111312 if ( ! baseElement ) continue ;
1312- if ( thisPrototype . kind == ElementKind . ClassPrototype ) {
1313- if ( baseElement . kind == ElementKind . ClassPrototype ) {
1314- let basePrototype = < ClassPrototype > baseElement ;
1315- if ( basePrototype . hasDecorator ( DecoratorFlags . Final ) ) {
1316- this . error (
1317- DiagnosticCode . Class_0_is_final_and_cannot_be_extended ,
1318- extendsNode . range , basePrototype . identifierNode . text
1319- ) ;
1320- }
1321- if (
1322- basePrototype . hasDecorator ( DecoratorFlags . Unmanaged ) !=
1323- thisPrototype . hasDecorator ( DecoratorFlags . Unmanaged )
1324- ) {
1325- this . error (
1326- DiagnosticCode . Unmanaged_classes_cannot_extend_managed_classes_and_vice_versa ,
1327- Range . join ( thisPrototype . identifierNode . range , extendsNode . range )
1328- ) ;
1329- }
1330- if ( ! thisPrototype . extends ( basePrototype ) ) {
1331- thisPrototype . basePrototype = basePrototype ;
1332- } else {
1333- this . error (
1334- DiagnosticCode . _0_is_referenced_directly_or_indirectly_in_its_own_base_expression ,
1335- basePrototype . identifierNode . range ,
1336- basePrototype . identifierNode . text ,
1337- ) ;
1338- }
1339- } else {
1313+ if ( baseElement . kind == ElementKind . ClassPrototype ) {
1314+ let basePrototype = < ClassPrototype > baseElement ;
1315+ if ( basePrototype . hasDecorator ( DecoratorFlags . Final ) ) {
13401316 this . error (
1341- DiagnosticCode . A_class_may_only_extend_another_class ,
1342- extendsNode . range
1317+ DiagnosticCode . Class_0_is_final_and_cannot_be_extended ,
1318+ extendsNode . range , basePrototype . identifierNode . text
13431319 ) ;
13441320 }
1345- } else if ( thisPrototype . kind == ElementKind . InterfacePrototype ) {
1346- if ( baseElement . kind == ElementKind . InterfacePrototype ) {
1347- const basePrototype = < InterfacePrototype > baseElement ;
1348- if ( ! thisPrototype . extends ( basePrototype ) ) {
1349- thisPrototype . basePrototype = basePrototype ;
1350- } else {
1351- this . error (
1352- DiagnosticCode . _0_is_referenced_directly_or_indirectly_in_its_own_base_expression ,
1353- basePrototype . identifierNode . range ,
1354- basePrototype . identifierNode . text ,
1355- ) ;
1356- }
1321+ if (
1322+ basePrototype . hasDecorator ( DecoratorFlags . Unmanaged ) !=
1323+ thisPrototype . hasDecorator ( DecoratorFlags . Unmanaged )
1324+ ) {
1325+ this . error (
1326+ DiagnosticCode . Unmanaged_classes_cannot_extend_managed_classes_and_vice_versa ,
1327+ Range . join ( thisPrototype . identifierNode . range , extendsNode . range )
1328+ ) ;
1329+ }
1330+ if ( ! thisPrototype . extends ( basePrototype ) ) {
1331+ thisPrototype . basePrototype = basePrototype ;
13571332 } else {
13581333 this . error (
1359- DiagnosticCode . An_interface_can_only_extend_an_interface ,
1360- extendsNode . range
1334+ DiagnosticCode . _0_is_referenced_directly_or_indirectly_in_its_own_base_expression ,
1335+ basePrototype . identifierNode . range ,
1336+ basePrototype . identifierNode . text ,
13611337 ) ;
13621338 }
1339+ } else {
1340+ this . error (
1341+ DiagnosticCode . A_class_may_only_extend_another_class ,
1342+ extendsNode . range
1343+ ) ;
13631344 }
13641345 }
13651346
@@ -1398,7 +1379,7 @@ export class Program extends DiagnosticEmitter {
13981379 }
13991380 }
14001381
1401- // resolve prototypes of implemented interfaces
1382+ // resolve prototypes of implemented/extended interfaces
14021383 for ( let i = 0 , k = queuedImplements . length ; i < k ; ++ i ) {
14031384 let thisPrototype = queuedImplements [ i ] ;
14041385 let implementsNodes = assert ( thisPrototype . implementsNodes ) ; // must be present if in queuedImplements
@@ -1410,10 +1391,23 @@ export class Program extends DiagnosticEmitter {
14101391 let interfacePrototype = < InterfacePrototype > interfaceElement ;
14111392 let interfacePrototypes = thisPrototype . interfacePrototypes ;
14121393 if ( ! interfacePrototypes ) thisPrototype . interfacePrototypes = interfacePrototypes = new Array ( ) ;
1413- interfacePrototypes . push ( interfacePrototype ) ;
1394+ if (
1395+ thisPrototype . kind == ElementKind . Interface &&
1396+ thisPrototype . implements ( interfacePrototype )
1397+ ) {
1398+ this . error (
1399+ DiagnosticCode . _0_is_referenced_directly_or_indirectly_in_its_own_base_expression ,
1400+ interfacePrototype . identifierNode . range ,
1401+ interfacePrototype . identifierNode . text ,
1402+ ) ;
1403+ } else {
1404+ interfacePrototypes . push ( interfacePrototype ) ;
1405+ }
14141406 } else {
14151407 this . error (
1416- DiagnosticCode . A_class_can_only_implement_an_interface ,
1408+ thisPrototype . kind == ElementKind . InterfacePrototype
1409+ ? DiagnosticCode . An_interface_can_only_extend_an_interface
1410+ : DiagnosticCode . A_class_can_only_implement_an_interface ,
14171411 implementsNode . range
14181412 ) ;
14191413 }
@@ -2473,7 +2467,7 @@ export class Program extends DiagnosticEmitter {
24732467 break ;
24742468 }
24752469 case NodeKind . InterfaceDeclaration : {
2476- element = this . initializeInterface ( < InterfaceDeclaration > declaration , parent , queuedExtends ) ;
2470+ element = this . initializeInterface ( < InterfaceDeclaration > declaration , parent , queuedImplements ) ;
24772471 break ;
24782472 }
24792473 case NodeKind . NamespaceDeclaration : {
@@ -2624,7 +2618,7 @@ export class Program extends DiagnosticEmitter {
26242618 /** Parent element, usually a file or namespace. */
26252619 parent : Element ,
26262620 /** So far queued `extends` clauses. */
2627- queuedExtends : ClassPrototype [ ] ,
2621+ queuedImplements : ClassPrototype [ ] ,
26282622 ) : InterfacePrototype | null {
26292623 let name = declaration . name . text ;
26302624 let element = new InterfacePrototype (
@@ -2637,8 +2631,10 @@ export class Program extends DiagnosticEmitter {
26372631 ) ;
26382632 if ( ! parent . add ( name , element ) ) return null ;
26392633
2640- // remember interfaces that extend another interface
2641- if ( declaration . extendsType ) queuedExtends . push ( element ) ;
2634+ // remember interfaces that extend other interfaces
2635+ // Note: See the corresponding note in parseClassOrInterface (in parser.ts) for
2636+ // further information as to why implementsTypes is used.
2637+ if ( declaration . implementsTypes ) queuedImplements . push ( element ) ;
26422638
26432639 let memberDeclarations = declaration . members ;
26442640 for ( let i = 0 , k = memberDeclarations . length ; i < k ; ++ i ) {
@@ -2757,7 +2753,7 @@ export class Program extends DiagnosticEmitter {
27572753 break ;
27582754 }
27592755 case NodeKind . InterfaceDeclaration : {
2760- this . initializeInterface ( < InterfaceDeclaration > member , original , queuedExtends ) ;
2756+ this . initializeInterface ( < InterfaceDeclaration > member , original , queuedImplements ) ;
27612757 break ;
27622758 }
27632759 case NodeKind . NamespaceDeclaration : {
@@ -4270,6 +4266,24 @@ export class ClassPrototype extends DeclaredElement {
42704266 return false ;
42714267 }
42724268
4269+ implements ( other : InterfacePrototype , seen : Set < InterfacePrototype > | null = null ) : bool {
4270+ if ( this . interfacePrototypes ) {
4271+ if ( ! seen ) seen = new Set ( ) ;
4272+ let interfacePrototypes = assert ( this . interfacePrototypes ) ;
4273+
4274+ for ( let i = 0 , k = interfacePrototypes . length ; i < k ; ++ i ) {
4275+ let prototype = unchecked ( interfacePrototypes [ i ] ) ;
4276+
4277+ if ( prototype == other ) return true ;
4278+ if ( seen . has ( prototype ) ) continue ;
4279+ seen . add ( prototype ) ;
4280+
4281+ if ( prototype . implements ( other , seen ) ) return true ;
4282+ }
4283+ }
4284+ return false ;
4285+ }
4286+
42734287 /** Adds an element as an instance member of this one. Returns the previous element if a duplicate. */
42744288 addInstance ( name : string , element : DeclaredElement ) : bool {
42754289 let originalDeclaration = element . declaration ;
@@ -4529,9 +4543,11 @@ export class Class extends TypedElement {
45294543 // Start with the interface itself, adding this class and its extenders to
45304544 // its implementers. Repeat for the interface's bases that are indirectly
45314545 // implemented by means of being extended by the interface.
4532- let nextIface : Interface | null = iface ;
4546+ // TODO: Maybe add a fast path when `iface` has no bases?
4547+ let ifaceStack = [ iface ] ;
45334548 let extenders = this . extenders ;
45344549 do {
4550+ let nextIface = assert ( ifaceStack . pop ( ) ) ;
45354551 let implementers = nextIface . implementers ;
45364552 if ( ! implementers ) nextIface . implementers = implementers = new Set ( ) ;
45374553 implementers . add ( this ) ;
@@ -4541,8 +4557,19 @@ export class Class extends TypedElement {
45414557 implementers . add ( extender ) ;
45424558 }
45434559 }
4544- nextIface = < Interface | null > nextIface . base ;
4545- } while ( nextIface ) ;
4560+
4561+ let nextIfaces = nextIface . interfaces ;
4562+ if ( ! nextIfaces ) continue ;
4563+
4564+ let stackIndex = ifaceStack . length ;
4565+
4566+ // Calls the internal ensureCapacity() when run in the bootstrapped compiler:
4567+ ifaceStack . length = stackIndex + nextIfaces . size ;
4568+
4569+ for ( let _values = Set_values ( nextIfaces ) , i = 0 , k = _values . length ; i < k ; ++ i ) {
4570+ ifaceStack [ stackIndex ++ ] = unchecked ( _values [ i ] ) ;
4571+ }
4572+ } while ( ifaceStack . length ) ;
45464573 }
45474574
45484575 /** Adds an interface. */
@@ -4561,7 +4588,7 @@ export class Class extends TypedElement {
45614588 if ( target . isInterface ) {
45624589 if ( this . isInterface ) {
45634590 // targetInterface = thisInterface
4564- return this == target || this . extends ( target ) ;
4591+ return this == target || this . implements ( < Interface > target ) ;
45654592 } else {
45664593 // targetInterface = thisClass
45674594 return this . implements ( < Interface > target ) ;
@@ -4835,7 +4862,7 @@ export class Class extends TypedElement {
48354862 return true ;
48364863 }
48374864
4838- /** Tests if this class or interface extends the given class or interface . */
4865+ /** Tests if this class extends the given class. */
48394866 extends ( other : Class ) : bool {
48404867 return other . hasExtender ( this ) ;
48414868 }
0 commit comments