@@ -1941,6 +1941,11 @@ namespace {
1941
1941
void recordTypeWitness (AssociatedTypeDecl *assocType, Type type,
1942
1942
TypeDecl *typeDecl, bool performRedeclarationCheck);
1943
1943
1944
+ // / Enforce restrictions on non-final classes witnessing requirements
1945
+ // / involving the protocol 'Self' type.
1946
+ void checkNonFinalClassWitness (ValueDecl *requirement,
1947
+ ValueDecl *witness);
1948
+
1944
1949
// / Resolve a (non-type) witness via name lookup.
1945
1950
ResolveWitnessResult resolveWitnessViaLookup (ValueDecl *requirement);
1946
1951
@@ -3035,6 +3040,115 @@ getAdopteeSelfSameTypeConstraint(ClassDecl *selfClass, ValueDecl *witness) {
3035
3040
return None;
3036
3041
}
3037
3042
3043
+ void ConformanceChecker::checkNonFinalClassWitness (ValueDecl *requirement,
3044
+ ValueDecl *witness) {
3045
+ auto *classDecl = Adoptee->getClassOrBoundGenericClass ();
3046
+
3047
+ // If we have an initializer requirement and the conforming type
3048
+ // is a non-final class, the witness must be 'required'.
3049
+ // We exempt Objective-C initializers from this requirement
3050
+ // because there is no equivalent to 'required' in Objective-C.
3051
+ if (auto ctor = dyn_cast<ConstructorDecl>(witness)) {
3052
+ if (!ctor->isRequired () &&
3053
+ !ctor->getDeclContext ()->getAsProtocolOrProtocolExtensionContext () &&
3054
+ !ctor->hasClangNode ()) {
3055
+ // FIXME: We're not recovering (in the AST), so the Fix-It
3056
+ // should move.
3057
+ diagnoseOrDefer (requirement, false ,
3058
+ [ctor, requirement](NormalProtocolConformance *conformance) {
3059
+ bool inExtension = isa<ExtensionDecl>(ctor->getDeclContext ());
3060
+ auto &diags = ctor->getASTContext ().Diags ;
3061
+ auto diag = diags.diagnose (ctor->getLoc (),
3062
+ diag::witness_initializer_not_required,
3063
+ requirement->getFullName (),
3064
+ inExtension,
3065
+ conformance->getType ());
3066
+ if (!ctor->isImplicit () && !inExtension)
3067
+ diag.fixItInsert (ctor->getStartLoc (), " required " );
3068
+ });
3069
+ }
3070
+ }
3071
+
3072
+ // Check whether this requirement uses Self in a way that might
3073
+ // prevent conformance from succeeding.
3074
+ auto selfKind = Proto->findProtocolSelfReferences (requirement,
3075
+ /* allowCovariantParameters=*/ false ,
3076
+ /* skipAssocTypes=*/ true );
3077
+
3078
+ if (selfKind.other ) {
3079
+ // References to Self in a position where subclasses cannot do
3080
+ // the right thing. Complain if the adoptee is a non-final
3081
+ // class.
3082
+ diagnoseOrDefer (requirement, false ,
3083
+ [witness, requirement](NormalProtocolConformance *conformance) {
3084
+ auto proto = conformance->getProtocol ();
3085
+ auto &diags = proto->getASTContext ().Diags ;
3086
+ diags.diagnose (witness->getLoc (), diag::witness_self_non_subtype,
3087
+ proto->getDeclaredType (), requirement->getFullName (),
3088
+ conformance->getType ());
3089
+ });
3090
+ } else if (selfKind.result ) {
3091
+ // The reference to Self occurs in the result type. A non-final class
3092
+ // can satisfy this requirement with a method that returns Self.
3093
+
3094
+ // If the function has a dynamic Self, it's okay.
3095
+ if (auto func = dyn_cast<FuncDecl>(witness)) {
3096
+ if (!func->hasDynamicSelf ()) {
3097
+ diagnoseOrDefer (requirement, false ,
3098
+ [witness, requirement](NormalProtocolConformance *conformance) {
3099
+ auto proto = conformance->getProtocol ();
3100
+ auto &diags = proto->getASTContext ().Diags ;
3101
+ diags.diagnose (witness->getLoc (),
3102
+ diag::witness_requires_dynamic_self,
3103
+ requirement->getFullName (),
3104
+ conformance->getType (),
3105
+ proto->getDeclaredType ());
3106
+ });
3107
+ }
3108
+
3109
+ // Constructors conceptually also have a dynamic Self
3110
+ // return type, so they're okay.
3111
+ } else if (!isa<ConstructorDecl>(witness)) {
3112
+ diagnoseOrDefer (requirement, false ,
3113
+ [witness, requirement](NormalProtocolConformance *conformance) {
3114
+ auto proto = conformance->getProtocol ();
3115
+ auto &diags = proto->getASTContext ().Diags ;
3116
+ diags.diagnose (witness->getLoc (), diag::witness_self_non_subtype,
3117
+ proto->getDeclaredType (),
3118
+ requirement->getFullName (),
3119
+ conformance->getType ());
3120
+ });
3121
+ }
3122
+ } else if (selfKind.requirement ) {
3123
+ if (auto constraint = getAdopteeSelfSameTypeConstraint (classDecl,
3124
+ witness)) {
3125
+ // A "Self ==" constraint works incorrectly with subclasses. Complain.
3126
+ auto proto = Conformance->getProtocol ();
3127
+ auto &diags = proto->getASTContext ().Diags ;
3128
+ diags.diagnose (witness->getLoc (),
3129
+ diag::witness_self_same_type,
3130
+ witness->getDescriptiveKind (),
3131
+ witness->getFullName (),
3132
+ Conformance->getType (),
3133
+ requirement->getDescriptiveKind (),
3134
+ requirement->getFullName (),
3135
+ proto->getDeclaredType ());
3136
+
3137
+ if (auto requirementRepr = *constraint) {
3138
+ diags.diagnose (requirementRepr->getEqualLoc (),
3139
+ diag::witness_self_weaken_same_type,
3140
+ requirementRepr->getFirstType (),
3141
+ requirementRepr->getSecondType ())
3142
+ .fixItReplace (requirementRepr->getEqualLoc (), " :" );
3143
+ }
3144
+ }
3145
+ }
3146
+
3147
+ // A non-final class can model a protocol requirement with a
3148
+ // contravariant Self, because here the witness will always have
3149
+ // a more general type than the requirement.
3150
+ }
3151
+
3038
3152
ResolveWitnessResult
3039
3153
ConformanceChecker::resolveWitnessViaLookup (ValueDecl *requirement) {
3040
3154
assert (!isa<AssociatedTypeDecl>(requirement) && " Use resolveTypeWitnessVia*" );
@@ -3245,112 +3359,10 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
3245
3359
}
3246
3360
}
3247
3361
3248
- ClassDecl *classDecl = Adoptee->getClassOrBoundGenericClass ();
3249
-
3250
- if (classDecl && !classDecl->isFinal ()) {
3251
- // If we have an initializer requirement and the conforming type
3252
- // is a non-final class, the witness must be 'required'.
3253
- // We exempt Objective-C initializers from this requirement
3254
- // because there is no equivalent to 'required' in Objective-C.
3255
- if (auto ctor = dyn_cast<ConstructorDecl>(best.Witness )) {
3256
- if (!ctor->isRequired () &&
3257
- !ctor->getDeclContext ()->getAsProtocolOrProtocolExtensionContext () &&
3258
- !ctor->hasClangNode ()) {
3259
- // FIXME: We're not recovering (in the AST), so the Fix-It
3260
- // should move.
3261
- diagnoseOrDefer (requirement, false ,
3262
- [ctor, requirement](NormalProtocolConformance *conformance) {
3263
- bool inExtension = isa<ExtensionDecl>(ctor->getDeclContext ());
3264
- auto &diags = ctor->getASTContext ().Diags ;
3265
- auto diag = diags.diagnose (ctor->getLoc (),
3266
- diag::witness_initializer_not_required,
3267
- requirement->getFullName (),
3268
- inExtension,
3269
- conformance->getType ());
3270
- if (!ctor->isImplicit () && !inExtension)
3271
- diag.fixItInsert (ctor->getStartLoc (), " required " );
3272
- });
3273
- }
3274
- }
3275
-
3276
- // Check whether this requirement uses Self in a way that might
3277
- // prevent conformance from succeeding.
3278
- auto selfKind = Proto->findProtocolSelfReferences (requirement,
3279
- /* allowCovariantParameters=*/ false ,
3280
- /* skipAssocTypes=*/ true );
3281
-
3282
- if (selfKind.other ) {
3283
- // References to Self in a position where subclasses cannot do
3284
- // the right thing. Complain if the adoptee is a non-final
3285
- // class.
3286
- diagnoseOrDefer (requirement, false ,
3287
- [witness, requirement](NormalProtocolConformance *conformance) {
3288
- auto proto = conformance->getProtocol ();
3289
- auto &diags = proto->getASTContext ().Diags ;
3290
- diags.diagnose (witness->getLoc (), diag::witness_self_non_subtype,
3291
- proto->getDeclaredType (), requirement->getFullName (),
3292
- conformance->getType ());
3293
- });
3294
- } else if (selfKind.result ) {
3295
- // The reference to Self occurs in the result type. A non-final class
3296
- // can satisfy this requirement with a method that returns Self.
3297
-
3298
- // If the function has a dynamic Self, it's okay.
3299
- if (auto func = dyn_cast<FuncDecl>(best.Witness )) {
3300
- if (!func->hasDynamicSelf ()) {
3301
- diagnoseOrDefer (requirement, false ,
3302
- [witness, requirement](NormalProtocolConformance *conformance) {
3303
- auto proto = conformance->getProtocol ();
3304
- auto &diags = proto->getASTContext ().Diags ;
3305
- diags.diagnose (witness->getLoc (),
3306
- diag::witness_requires_dynamic_self,
3307
- requirement->getFullName (),
3308
- conformance->getType (),
3309
- proto->getDeclaredType ());
3310
- });
3311
- }
3312
-
3313
- // Constructors conceptually also have a dynamic Self
3314
- // return type, so they're okay.
3315
- } else if (!isa<ConstructorDecl>(best.Witness )) {
3316
- diagnoseOrDefer (requirement, false ,
3317
- [witness, requirement](NormalProtocolConformance *conformance) {
3318
- auto proto = conformance->getProtocol ();
3319
- auto &diags = proto->getASTContext ().Diags ;
3320
- diags.diagnose (witness->getLoc (), diag::witness_self_non_subtype,
3321
- proto->getDeclaredType (),
3322
- requirement->getFullName (),
3323
- conformance->getType ());
3324
- });
3325
- }
3326
- } else if (selfKind.requirement ) {
3327
- if (auto constraint = getAdopteeSelfSameTypeConstraint (classDecl,
3328
- witness)) {
3329
- // A "Self ==" constraint works incorrectly with subclasses. Complain.
3330
- auto proto = Conformance->getProtocol ();
3331
- auto &diags = proto->getASTContext ().Diags ;
3332
- diags.diagnose (witness->getLoc (),
3333
- diag::witness_self_same_type,
3334
- witness->getDescriptiveKind (),
3335
- witness->getFullName (),
3336
- Conformance->getType (),
3337
- requirement->getDescriptiveKind (),
3338
- requirement->getFullName (),
3339
- proto->getDeclaredType ());
3340
-
3341
- if (auto requirementRepr = *constraint) {
3342
- diags.diagnose (requirementRepr->getEqualLoc (),
3343
- diag::witness_self_weaken_same_type,
3344
- requirementRepr->getFirstType (),
3345
- requirementRepr->getSecondType ())
3346
- .fixItReplace (requirementRepr->getEqualLoc (), " :" );
3347
- }
3348
- }
3362
+ if (auto *classDecl = Adoptee->getClassOrBoundGenericClass ()) {
3363
+ if (!classDecl->isFinal ()) {
3364
+ checkNonFinalClassWitness (requirement, witness);
3349
3365
}
3350
-
3351
- // A non-final class can model a protocol requirement with a
3352
- // contravariant Self, because here the witness will always have
3353
- // a more general type than the requirement.
3354
3366
}
3355
3367
3356
3368
// Record the match.
0 commit comments