@@ -3092,18 +3092,26 @@ export class Resolver extends DiagnosticEmitter {
30923092 let fieldPrototype = < FieldPrototype > member ;
30933093 let fieldTypeNode = fieldPrototype . typeNode ;
30943094 let fieldType : Type | null = null ;
3095- // TODO: handle duplicate non-private fields specifically?
3096- if ( ! fieldTypeNode ) {
3097- if ( base ) {
3098- let baseMembers = base . members ;
3099- if ( baseMembers !== null && baseMembers . has ( fieldPrototype . name ) ) {
3100- let baseField = assert ( baseMembers . get ( fieldPrototype . name ) ) ;
3101- if ( ! baseField . is ( CommonFlags . PRIVATE ) ) {
3102- assert ( baseField . kind == ElementKind . FIELD ) ;
3103- fieldType = ( < Field > baseField ) . type ;
3104- }
3095+ let existingField : Field | null = null ;
3096+ if ( base ) {
3097+ let baseMembers = base . members ;
3098+ if ( baseMembers !== null && baseMembers . has ( fieldPrototype . name ) ) {
3099+ let baseField = assert ( baseMembers . get ( fieldPrototype . name ) ) ;
3100+ if ( baseField . kind == ElementKind . FIELD ) {
3101+ existingField = < Field > baseField ;
3102+ } else {
3103+ this . errorRelated (
3104+ DiagnosticCode . Duplicate_identifier_0 ,
3105+ fieldPrototype . identifierNode . range , baseField . identifierNode . range ,
3106+ fieldPrototype . name
3107+ ) ;
31053108 }
31063109 }
3110+ }
3111+ if ( ! fieldTypeNode ) {
3112+ if ( existingField !== null && ! existingField . is ( CommonFlags . PRIVATE ) ) {
3113+ fieldType = existingField . type ;
3114+ }
31073115 if ( ! fieldType ) {
31083116 if ( reportMode == ReportMode . REPORT ) {
31093117 this . error (
@@ -3130,12 +3138,83 @@ export class Resolver extends DiagnosticEmitter {
31303138 }
31313139 }
31323140 if ( ! fieldType ) break ; // did report above
3141+ if ( existingField !== null ) {
3142+ // visibility checks
3143+ /*
3144+ existingField visibility on top
3145+ +==================+=========+===========+=========+
3146+ | Visibility Table | Private | Protected | Public |
3147+ +==================+=========+===========+=========+
3148+ | Private | error | error | error |
3149+ +------------------+---------+-----------+---------+
3150+ | Protected | error | allowed | error |
3151+ +------------------+---------+-----------+---------+
3152+ | Public | error | allowed | allowed |
3153+ +------------------+---------+-----------+---------+
3154+ */
3155+
3156+ let baseClass = < Class > base ;
3157+
3158+ // handle cases row-by-row
3159+ if ( fieldPrototype . is ( CommonFlags . PRIVATE ) ) {
3160+ if ( existingField . is ( CommonFlags . PRIVATE ) ) {
3161+ this . errorRelated (
3162+ DiagnosticCode . Types_have_separate_declarations_of_a_private_property_0 ,
3163+ fieldPrototype . identifierNode . range , existingField . identifierNode . range ,
3164+ fieldPrototype . name
3165+ ) ;
3166+ } else {
3167+ this . errorRelated (
3168+ DiagnosticCode . Property_0_is_private_in_type_1_but_not_in_type_2 ,
3169+ fieldPrototype . identifierNode . range , existingField . identifierNode . range ,
3170+ fieldPrototype . name , instance . internalName , baseClass . internalName
3171+ ) ;
3172+ }
3173+ } else if ( fieldPrototype . is ( CommonFlags . PROTECTED ) ) {
3174+ if ( existingField . is ( CommonFlags . PRIVATE ) ) {
3175+ this . errorRelated (
3176+ DiagnosticCode . Property_0_is_private_in_type_1_but_not_in_type_2 ,
3177+ fieldPrototype . identifierNode . range , existingField . identifierNode . range ,
3178+ fieldPrototype . name , baseClass . internalName , instance . internalName
3179+ ) ;
3180+ } else if ( ! existingField . is ( CommonFlags . PROTECTED ) ) {
3181+ // may be implicitly public
3182+ this . errorRelated (
3183+ DiagnosticCode . Property_0_is_protected_in_type_1_but_public_in_type_2 ,
3184+ fieldPrototype . identifierNode . range , existingField . identifierNode . range ,
3185+ fieldPrototype . name , instance . internalName , baseClass . internalName
3186+ ) ;
3187+ }
3188+ } else {
3189+ // fieldPrototype is public here
3190+ if ( existingField . is ( CommonFlags . PRIVATE ) ) {
3191+ this . errorRelated (
3192+ DiagnosticCode . Property_0_is_private_in_type_1_but_not_in_type_2 ,
3193+ fieldPrototype . identifierNode . range , existingField . identifierNode . range ,
3194+ fieldPrototype . name , baseClass . internalName , instance . internalName
3195+ ) ;
3196+ }
3197+ }
3198+
3199+ // assignability
3200+ if ( ! fieldType . isStrictlyAssignableTo ( existingField . type ) ) {
3201+ this . errorRelated (
3202+ DiagnosticCode . Property_0_in_type_1_is_not_assignable_to_the_same_property_in_base_type_2 ,
3203+ fieldPrototype . identifierNode . range , existingField . identifierNode . range ,
3204+ fieldPrototype . name , instance . internalName , baseClass . internalName
3205+ ) ;
3206+ }
3207+ }
31333208 let fieldInstance = new Field ( fieldPrototype , instance , fieldType ) ;
31343209 assert ( isPowerOf2 ( fieldType . byteSize ) ) ;
3135- let mask = fieldType . byteSize - 1 ;
3136- if ( memoryOffset & mask ) memoryOffset = ( memoryOffset | mask ) + 1 ;
3137- fieldInstance . memoryOffset = memoryOffset ;
3138- memoryOffset += fieldType . byteSize ;
3210+ if ( existingField !== null ) {
3211+ fieldInstance . memoryOffset = existingField . memoryOffset ;
3212+ } else {
3213+ let mask = fieldType . byteSize - 1 ;
3214+ if ( memoryOffset & mask ) memoryOffset = ( memoryOffset | mask ) + 1 ;
3215+ fieldInstance . memoryOffset = memoryOffset ;
3216+ memoryOffset += fieldType . byteSize ;
3217+ }
31393218 instance . add ( memberName , fieldInstance ) ; // reports
31403219 break ;
31413220 }
0 commit comments