@@ -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