@@ -1440,7 +1440,7 @@ export class Program extends DiagnosticEmitter {
14401440 }
14411441 if ( interfacePrototypes ) {
14421442 for ( let j = 0 , l = interfacePrototypes . length ; j < l ; ++ j ) {
1443- this . processOverrides ( thisPrototype , interfacePrototypes [ j ] ) ;
1443+ this . processImplements ( thisPrototype , interfacePrototypes [ j ] ) ;
14441444 }
14451445 }
14461446 }
@@ -1497,6 +1497,124 @@ export class Program extends DiagnosticEmitter {
14971497 }
14981498 }
14991499
1500+ private processImplements ( thisPrototype : ClassPrototype , interfacePrototype : InterfacePrototype ) : void {
1501+ let interfaceInstanceMembers = interfacePrototype . instanceMembers ;
1502+ if ( interfaceInstanceMembers ) {
1503+ for ( let _values = Map_values ( interfaceInstanceMembers ) , i = 0 , k = _values . length ; i < k ; ++ i ) {
1504+ let interfaceMember = unchecked ( _values [ i ] ) ;
1505+ const implMember = this . searchImplementation ( thisPrototype , interfaceMember . name ) ;
1506+ if ( ! implMember ) continue ;
1507+ this . doProcessImplementation ( thisPrototype , implMember , interfacePrototype , interfaceMember ) ;
1508+ }
1509+ }
1510+ const interfaceBasePrototype = interfacePrototype . basePrototype ;
1511+ if ( interfaceBasePrototype ) {
1512+ assert ( interfaceBasePrototype . kind == ElementKind . InterfacePrototype ) ;
1513+ this . processImplements ( thisPrototype , < InterfacePrototype > interfaceBasePrototype ) ;
1514+ }
1515+ }
1516+
1517+ private searchImplementation ( thisPrototype : ClassPrototype , name : string ) : DeclaredElement | null {
1518+ let currentPrototype : ClassPrototype | null = thisPrototype ;
1519+ while ( currentPrototype ) {
1520+ let currentInstanceMembers = currentPrototype . instanceMembers ;
1521+ if ( currentInstanceMembers && currentInstanceMembers . has ( name ) ) {
1522+ return assert ( currentInstanceMembers . get ( name ) ) ;
1523+ }
1524+ currentPrototype = currentPrototype . basePrototype ;
1525+ }
1526+ return null ;
1527+ }
1528+
1529+ private doProcessImplementation (
1530+ thisClass : ClassPrototype ,
1531+ implMember : DeclaredElement ,
1532+ interfacePrototype : InterfacePrototype ,
1533+ interfaceMember : DeclaredElement
1534+ ) : void {
1535+ if ( implMember . kind == ElementKind . FunctionPrototype && interfaceMember . kind == ElementKind . FunctionPrototype ) {
1536+ const implMethod = < FunctionPrototype > implMember ;
1537+ const interfaceMethod = < FunctionPrototype > interfaceMember ;
1538+ if ( ! implMethod . visibilityEquals ( interfaceMethod ) ) {
1539+ this . errorRelated (
1540+ DiagnosticCode . Overload_signatures_must_all_be_public_private_or_protected ,
1541+ implMethod . declaration . name . range ,
1542+ interfaceMethod . declaration . name . range
1543+ ) ;
1544+ }
1545+ interfaceMethod . addUnboundImplementations ( thisClass , implMethod ) ;
1546+ interfaceMethod . setOverrideFlag ( ) ;
1547+ } else if (
1548+ implMember . kind == ElementKind . PropertyPrototype &&
1549+ interfaceMember . kind == ElementKind . PropertyPrototype
1550+ ) {
1551+ const implProperty = < PropertyPrototype > implMember ;
1552+ const interfaceProperty = < PropertyPrototype > interfaceMember ;
1553+ if ( ! implProperty . visibilityEquals ( interfaceProperty ) ) {
1554+ this . errorRelated (
1555+ DiagnosticCode . Overload_signatures_must_all_be_public_private_or_protected ,
1556+ implProperty . declaration . name . range ,
1557+ interfaceProperty . declaration . name . range
1558+ ) ;
1559+ }
1560+ if ( interfaceProperty . parent . kind != ElementKind . InterfacePrototype ) {
1561+ // Interface fields/properties can be impled by either, but other
1562+ // members must match to retain compatiblity with TS/JS.
1563+ const implIsField = implProperty . isField ;
1564+ if ( implIsField != interfaceProperty . isField ) {
1565+ if ( implIsField ) {
1566+ // base is property
1567+ this . errorRelated (
1568+ DiagnosticCode . _0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property ,
1569+ implProperty . declaration . name . range ,
1570+ interfaceProperty . declaration . name . range ,
1571+ implProperty . name ,
1572+ interfacePrototype . internalName ,
1573+ thisClass . internalName
1574+ ) ;
1575+ } else {
1576+ // this is property, base is field
1577+ this . errorRelated (
1578+ DiagnosticCode . _0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor ,
1579+ implProperty . declaration . name . range ,
1580+ interfaceProperty . declaration . name . range ,
1581+ implProperty . name ,
1582+ interfacePrototype . internalName ,
1583+ thisClass . internalName
1584+ ) ;
1585+ }
1586+ return ;
1587+ } else if ( implIsField ) {
1588+ // base is also field
1589+ // Fields don't override other fields and can only be redeclared
1590+ return ;
1591+ }
1592+ }
1593+ interfaceProperty . set ( CommonFlags . Overridden ) ;
1594+ const interfaceGetter = interfaceProperty . getterPrototype ;
1595+ if ( interfaceGetter ) {
1596+ const implGetter = implProperty . getterPrototype ;
1597+ if ( implGetter ) interfaceGetter . addUnboundImplementations ( thisClass , implGetter ) ;
1598+ interfaceGetter . setOverrideFlag ( ) ;
1599+ }
1600+ const interfaceSetter = interfaceProperty . setterPrototype ;
1601+ if ( interfaceSetter && implProperty . setterPrototype ) {
1602+ const implSetter = implProperty . setterPrototype ;
1603+ if ( implSetter ) interfaceSetter . addUnboundImplementations ( thisClass , implSetter ) ;
1604+ interfaceSetter . setOverrideFlag ( ) ;
1605+ }
1606+ } else {
1607+ this . errorRelated (
1608+ DiagnosticCode . Property_0_in_type_1_is_not_assignable_to_the_same_property_in_base_type_2 ,
1609+ implMember . declaration . name . range ,
1610+ interfaceMember . declaration . name . range ,
1611+ implMember . name ,
1612+ thisClass . internalName ,
1613+ interfacePrototype . internalName
1614+ ) ;
1615+ }
1616+ }
1617+
15001618 /** Processes overridden members by this class in a base class. */
15011619 private processOverrides (
15021620 thisPrototype : ClassPrototype ,
@@ -1526,7 +1644,7 @@ export class Program extends DiagnosticEmitter {
15261644 for ( let i = 0 , k = baseInterfacePrototypes . length ; i < k ; ++ i ) {
15271645 let baseInterfacePrototype = baseInterfacePrototypes [ i ] ;
15281646 if ( baseInterfacePrototype != basePrototype ) {
1529- this . processOverrides ( thisPrototype , baseInterfacePrototype ) ;
1647+ this . processImplements ( thisPrototype , baseInterfacePrototype ) ;
15301648 }
15311649 }
15321650 }
@@ -3667,6 +3785,8 @@ export class FunctionPrototype extends DeclaredElement {
36673785 instances : Map < string , Function > | null = null ;
36683786 /** Methods overriding this one, if any. These are unbound. */
36693787 unboundOverrides : Set < FunctionPrototype > | null = null ;
3788+ /** Methods implement this one, if any. These are unbound. */
3789+ unboundImplementations : Map < ClassPrototype , FunctionPrototype > | null = null ;
36703790
36713791 /** Clones of this prototype that are bound to specific classes. */
36723792 private boundPrototypes : Map < Class , FunctionPrototype > | null = null ;
@@ -3731,6 +3851,7 @@ export class FunctionPrototype extends DeclaredElement {
37313851 bound . flags = this . flags ;
37323852 bound . operatorKind = this . operatorKind ;
37333853 bound . unboundOverrides = this . unboundOverrides ;
3854+ bound . unboundImplementations = this . unboundImplementations ;
37343855 // NOTE: this.instances holds instances per bound class / unbound
37353856 boundPrototypes . set ( classInstance , bound ) ;
37363857 return bound ;
@@ -3750,6 +3871,24 @@ export class FunctionPrototype extends DeclaredElement {
37503871 else assert ( ! instances . has ( instanceKey ) ) ;
37513872 instances . set ( instanceKey , instance ) ;
37523873 }
3874+
3875+
3876+ setOverrideFlag ( ) : void {
3877+ this . set ( CommonFlags . Overridden ) ;
3878+ let instances = this . instances ;
3879+ if ( instances ) {
3880+ for ( let _values = Map_values ( instances ) , a = 0 , b = _values . length ; a < b ; ++ a ) {
3881+ let instance = _values [ a ] ;
3882+ instance . set ( CommonFlags . Overridden ) ;
3883+ }
3884+ }
3885+ }
3886+
3887+ addUnboundImplementations ( thisClass : ClassPrototype , implementMember : DeclaredElement ) : void {
3888+ let unboundImplementations = this . unboundImplementations ;
3889+ if ( ! unboundImplementations ) this . unboundImplementations = unboundImplementations = new Map ( ) ;
3890+ unboundImplementations . set ( thisClass , < FunctionPrototype > implementMember ) ;
3891+ }
37533892}
37543893
37553894/** A resolved function. */
0 commit comments