@@ -1130,7 +1130,7 @@ export class Program extends DiagnosticEmitter {
11301130 break ;
11311131 }
11321132 case NodeKind . InterfaceDeclaration : {
1133- this . initializeInterface ( < InterfaceDeclaration > statement , file , queuedExtends ) ;
1133+ this . initializeInterface ( < InterfaceDeclaration > statement , file , queuedImplements ) ;
11341134 break ;
11351135 }
11361136 case NodeKind . NamespaceDeclaration : {
@@ -1303,64 +1303,45 @@ export class Program extends DiagnosticEmitter {
13031303 }
13041304 }
13051305
1306- // resolve prototypes of extended classes or interfaces
1306+ // resolve prototypes of extended classes
13071307 let resolver = this . resolver ;
13081308 for ( let i = 0 , k = queuedExtends . length ; i < k ; ++ i ) {
13091309 let thisPrototype = queuedExtends [ i ] ;
1310+ assert ( thisPrototype . kind == ElementKind . ClassPrototype ) ;
13101311 let extendsNode = assert ( thisPrototype . extendsNode ) ; // must be present if in queuedExtends
13111312 let baseElement = resolver . resolveTypeName ( extendsNode . name , null , thisPrototype . parent ) ;
13121313 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 ) ) {
13411317 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
13441320 ) ;
13451321 }
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 ;
13581333 } else {
13591334 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 ,
13621338 ) ;
13631339 }
1340+ } else {
1341+ this . error (
1342+ DiagnosticCode . A_class_may_only_extend_another_class ,
1343+ extendsNode . range
1344+ ) ;
13641345 }
13651346 }
13661347
@@ -1399,7 +1380,7 @@ export class Program extends DiagnosticEmitter {
13991380 }
14001381 }
14011382
1402- // resolve prototypes of implemented interfaces
1383+ // resolve prototypes of implemented/extended interfaces
14031384 for ( let i = 0 , k = queuedImplements . length ; i < k ; ++ i ) {
14041385 let thisPrototype = queuedImplements [ i ] ;
14051386 let implementsNodes = assert ( thisPrototype . implementsNodes ) ; // must be present if in queuedImplements
@@ -1411,10 +1392,23 @@ export class Program extends DiagnosticEmitter {
14111392 let interfacePrototype = < InterfacePrototype > interfaceElement ;
14121393 let interfacePrototypes = thisPrototype . interfacePrototypes ;
14131394 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+ }
14151407 } else {
14161408 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 ,
14181412 implementsNode . range
14191413 ) ;
14201414 }
@@ -2474,7 +2468,7 @@ export class Program extends DiagnosticEmitter {
24742468 break ;
24752469 }
24762470 case NodeKind . InterfaceDeclaration : {
2477- element = this . initializeInterface ( < InterfaceDeclaration > declaration , parent , queuedExtends ) ;
2471+ element = this . initializeInterface ( < InterfaceDeclaration > declaration , parent , queuedImplements ) ;
24782472 break ;
24792473 }
24802474 case NodeKind . NamespaceDeclaration : {
@@ -2625,7 +2619,7 @@ export class Program extends DiagnosticEmitter {
26252619 /** Parent element, usually a file or namespace. */
26262620 parent : Element ,
26272621 /** So far queued `extends` clauses. */
2628- queuedExtends : ClassPrototype [ ] ,
2622+ queuedImplements : ClassPrototype [ ] ,
26292623 ) : InterfacePrototype | null {
26302624 let name = declaration . name . text ;
26312625 let element = new InterfacePrototype (
@@ -2638,8 +2632,10 @@ export class Program extends DiagnosticEmitter {
26382632 ) ;
26392633 if ( ! parent . add ( name , element ) ) return null ;
26402634
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 ) ;
26432639
26442640 let memberDeclarations = declaration . members ;
26452641 for ( let i = 0 , k = memberDeclarations . length ; i < k ; ++ i ) {
@@ -2762,7 +2758,7 @@ export class Program extends DiagnosticEmitter {
27622758 break ;
27632759 }
27642760 case NodeKind . InterfaceDeclaration : {
2765- this . initializeInterface ( < InterfaceDeclaration > member , original , queuedExtends ) ;
2761+ this . initializeInterface ( < InterfaceDeclaration > member , original , queuedImplements ) ;
27662762 break ;
27672763 }
27682764 case NodeKind . NamespaceDeclaration : {
@@ -4298,6 +4294,24 @@ export class ClassPrototype extends DeclaredElement {
42984294 return false ;
42994295 }
43004296
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+
43014315 /** Adds an element as an instance member of this one. Returns the previous element if a duplicate. */
43024316 addInstance ( name : string , element : DeclaredElement ) : bool {
43034317 let originalDeclaration = element . declaration ;
@@ -4557,9 +4571,11 @@ export class Class extends TypedElement {
45574571 // Start with the interface itself, adding this class and its extenders to
45584572 // its implementers. Repeat for the interface's bases that are indirectly
45594573 // 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 ] ;
45614576 let extenders = this . extenders ;
45624577 do {
4578+ let nextIface = assert ( ifaceStack . pop ( ) ) ;
45634579 let implementers = nextIface . implementers ;
45644580 if ( ! implementers ) nextIface . implementers = implementers = new Set ( ) ;
45654581 implementers . add ( this ) ;
@@ -4569,8 +4585,19 @@ export class Class extends TypedElement {
45694585 implementers . add ( extender ) ;
45704586 }
45714587 }
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 ) ;
45744601 }
45754602
45764603 /** Adds an interface. */
@@ -4589,7 +4616,7 @@ export class Class extends TypedElement {
45894616 if ( target . isInterface ) {
45904617 if ( this . isInterface ) {
45914618 // targetInterface = thisInterface
4592- return this == target || this . extends ( target ) ;
4619+ return this == target || this . implements ( < Interface > target ) ;
45934620 } else {
45944621 // targetInterface = thisClass
45954622 return this . implements ( < Interface > target ) ;
@@ -4863,7 +4890,7 @@ export class Class extends TypedElement {
48634890 return true ;
48644891 }
48654892
4866- /** Tests if this class or interface extends the given class or interface . */
4893+ /** Tests if this class extends the given class. */
48674894 extends ( other : Class ) : bool {
48684895 return other . hasExtender ( this ) ;
48694896 }
0 commit comments