@@ -3092,18 +3092,26 @@ export class Resolver extends DiagnosticEmitter {
3092
3092
let fieldPrototype = < FieldPrototype > member ;
3093
3093
let fieldTypeNode = fieldPrototype . typeNode ;
3094
3094
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
+ ) ;
3105
3108
}
3106
3109
}
3110
+ }
3111
+ if ( ! fieldTypeNode ) {
3112
+ if ( existingField !== null && ! existingField . is ( CommonFlags . PRIVATE ) ) {
3113
+ fieldType = existingField . type ;
3114
+ }
3107
3115
if ( ! fieldType ) {
3108
3116
if ( reportMode == ReportMode . REPORT ) {
3109
3117
this . error (
@@ -3130,12 +3138,83 @@ export class Resolver extends DiagnosticEmitter {
3130
3138
}
3131
3139
}
3132
3140
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
+ }
3133
3208
let fieldInstance = new Field ( fieldPrototype , instance , fieldType ) ;
3134
3209
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
+ }
3139
3218
instance . add ( memberName , fieldInstance ) ; // reports
3140
3219
break ;
3141
3220
}
0 commit comments