@@ -940,7 +940,9 @@ static bool isNeverDefaultInitializable(Pattern *p) {
940
940
bool result = false ;
941
941
942
942
p->forEachVariable ([&](VarDecl *var) {
943
- assert (!var->getAttrs ().hasAttribute <NSManagedAttr>());
943
+ if (var->getAttrs ().hasAttribute <NSManagedAttr>())
944
+ return ;
945
+
944
946
if (var->isDebuggerVar () ||
945
947
var->isLet ())
946
948
result = true ;
@@ -2078,6 +2080,11 @@ static Optional<ObjCReason> shouldMarkAsObjC(TypeChecker &TC,
2078
2080
// An override of an @objc declaration is implicitly @objc.
2079
2081
else if (VD->getOverriddenDecl () && VD->getOverriddenDecl ()->isObjC ())
2080
2082
return ObjCReason::OverridesObjC;
2083
+ // A witness to an @objc protocol requirement is implicitly @objc.
2084
+ else if (!TC.findWitnessedObjCRequirements (
2085
+ VD,
2086
+ /* onlyFirstRequirement=*/ true ).empty ())
2087
+ return ObjCReason::WitnessToObjC;
2081
2088
else if (VD->isInvalid ())
2082
2089
return None;
2083
2090
// Implicitly generated declarations are not @objc, except for constructors.
@@ -2185,6 +2192,135 @@ static void checkBridgedFunctions(TypeChecker &TC) {
2185
2192
}
2186
2193
}
2187
2194
2195
+ // / Infer the Objective-C name for a given declaration.
2196
+ static void inferObjCName (TypeChecker &tc, ValueDecl *decl) {
2197
+ // If this declaration overrides an @objc declaration, use its name.
2198
+ if (auto overridden = decl->getOverriddenDecl ()) {
2199
+ if (overridden->isObjC ()) {
2200
+ // Handle methods first.
2201
+ if (auto overriddenFunc = dyn_cast<AbstractFunctionDecl>(overridden)) {
2202
+ // Determine the selector of the overridden method.
2203
+ ObjCSelector overriddenSelector = overriddenFunc->getObjCSelector (&tc);
2204
+
2205
+ // Dig out the @objc attribute on the method, if it exists.
2206
+ auto attr = decl->getAttrs ().getAttribute <ObjCAttr>();
2207
+ if (!attr) {
2208
+ // There was no @objc attribute; add one with the
2209
+ // appropriate name.
2210
+ decl->getAttrs ().add (ObjCAttr::create (tc.Context ,
2211
+ overriddenSelector,
2212
+ true ));
2213
+ return ;
2214
+ }
2215
+
2216
+ // Determine whether there is a name conflict.
2217
+ bool shouldFixName = !attr->hasName ();
2218
+ if (attr->hasName () && *attr->getName () != overriddenSelector) {
2219
+ // If the user explicitly wrote the incorrect name, complain.
2220
+ if (!attr->isNameImplicit ()) {
2221
+ {
2222
+ auto diag = tc.diagnose (
2223
+ attr->AtLoc ,
2224
+ diag::objc_override_method_selector_mismatch,
2225
+ *attr->getName (), overriddenSelector);
2226
+ fixDeclarationObjCName (diag, decl, overriddenSelector);
2227
+ }
2228
+
2229
+ tc.diagnose (overriddenFunc, diag::overridden_here);
2230
+ }
2231
+
2232
+ shouldFixName = true ;
2233
+ }
2234
+
2235
+ // If we have to set the name, do so.
2236
+ if (shouldFixName) {
2237
+ // Override the name on the attribute.
2238
+ const_cast <ObjCAttr *>(attr)->setName (overriddenSelector,
2239
+ /* implicit=*/ true );
2240
+ }
2241
+ return ;
2242
+ }
2243
+
2244
+ // Handle properties.
2245
+ if (auto overriddenProp = dyn_cast<VarDecl>(overridden)) {
2246
+ Identifier overriddenName = overriddenProp->getObjCPropertyName ();
2247
+ ObjCSelector overriddenNameAsSel (tc.Context , 0 , overriddenName);
2248
+
2249
+ // Dig out the @objc attribute, if specified.
2250
+ auto attr = decl->getAttrs ().getAttribute <ObjCAttr>();
2251
+ if (!attr) {
2252
+ // There was no @objc attribute; add one with the
2253
+ // appropriate name.
2254
+ decl->getAttrs ().add (
2255
+ ObjCAttr::createNullary (tc.Context ,
2256
+ overriddenName,
2257
+ /* isNameImplicit=*/ true ));
2258
+ return ;
2259
+ }
2260
+
2261
+ // Determine whether there is a name conflict.
2262
+ bool shouldFixName = !attr->hasName ();
2263
+ if (attr->hasName () && *attr->getName () != overriddenNameAsSel) {
2264
+ // If the user explicitly wrote the wrong name, complain.
2265
+ if (!attr->isNameImplicit ()) {
2266
+ tc.diagnose (attr->AtLoc ,
2267
+ diag::objc_override_property_name_mismatch,
2268
+ attr->getName ()->getSelectorPieces ()[0 ],
2269
+ overriddenName)
2270
+ .fixItReplaceChars (attr->getNameLocs ().front (),
2271
+ attr->getRParenLoc (),
2272
+ overriddenName.str ());
2273
+ tc.diagnose (overridden, diag::overridden_here);
2274
+ }
2275
+
2276
+ shouldFixName = true ;
2277
+ }
2278
+
2279
+ // Fix the name, if needed.
2280
+ if (shouldFixName) {
2281
+ const_cast <ObjCAttr *>(attr)->setName (overriddenNameAsSel,
2282
+ /* implicit=*/ true );
2283
+ }
2284
+ return ;
2285
+ }
2286
+ }
2287
+ }
2288
+
2289
+ // Dig out the @objc attribute. If it already has a name, do
2290
+ // nothing; the protocol conformance checker will handle any
2291
+ // mismatches.
2292
+ auto attr = decl->getAttrs ().getAttribute <ObjCAttr>();
2293
+ if (attr && attr->hasName ()) return ;
2294
+
2295
+ // When no overridde determined the Objective-C name, look for
2296
+ // requirements for which this declaration is a witness.
2297
+ Optional<ObjCSelector> requirementObjCName;
2298
+ for (auto req : tc.findWitnessedObjCRequirements (decl,
2299
+ /* onlyFirst=*/ false )) {
2300
+ // If this is the first requirement, take its name.
2301
+ if (!requirementObjCName) {
2302
+ requirementObjCName = req->getObjCRuntimeName ();
2303
+ continue ;
2304
+ }
2305
+
2306
+ // If this requirement has a different name from one we've seen,
2307
+ // bail out and let protocol-conformance diagnostics handle this.
2308
+ if (*requirementObjCName != *req->getObjCRuntimeName ())
2309
+ return ;
2310
+ }
2311
+
2312
+ // If we have a name, install it via an @objc attribute.
2313
+ if (requirementObjCName) {
2314
+ if (attr)
2315
+ const_cast <ObjCAttr *>(attr)->setName (*requirementObjCName,
2316
+ /* implicit=*/ true );
2317
+ else
2318
+ decl->getAttrs ().add (
2319
+ ObjCAttr::create (tc.Context , *requirementObjCName,
2320
+ /* isNameImplicit=*/ true ));
2321
+ }
2322
+ }
2323
+
2188
2324
// / Mark the given declaration as being Objective-C compatible (or
2189
2325
// / not) as appropriate.
2190
2326
// /
@@ -2224,13 +2360,12 @@ void swift::markAsObjC(TypeChecker &TC, ValueDecl *D,
2224
2360
if (auto classDecl
2225
2361
= D->getDeclContext ()->getAsClassOrClassExtensionContext ()) {
2226
2362
if (auto method = dyn_cast<AbstractFunctionDecl>(D)) {
2227
- // If we are overriding another method, make sure the
2228
- // selectors line up.
2363
+ // Determine the foreign error convention.
2229
2364
if (auto baseMethod = method->getOverriddenDecl ()) {
2230
2365
// If the overridden method has a foreign error convention,
2231
- // adopt it. Set the foreign error convention for a
2232
- // throwing method. Note that the foreign error convention
2233
- // affects the selector, so we perform this first .
2366
+ // adopt it. Set the foreign error convention for a throwing
2367
+ // method. Note that the foreign error convention affects the
2368
+ // selector, so we perform this before inferring a selector .
2234
2369
if (method->isBodyThrowing ()) {
2235
2370
if (auto baseErrorConvention
2236
2371
= baseMethod->getForeignErrorConvention ()) {
@@ -2240,38 +2375,16 @@ void swift::markAsObjC(TypeChecker &TC, ValueDecl *D,
2240
2375
assert (errorConvention && " Missing error convention" );
2241
2376
method->setForeignErrorConvention (*errorConvention);
2242
2377
}
2243
-
2244
- ObjCSelector baseSelector = baseMethod->getObjCSelector (&TC);
2245
- if (baseSelector != method->getObjCSelector (&TC)) {
2246
- // The selectors differ. If the method's selector was
2247
- // explicitly specified, this is an error. Otherwise, we
2248
- // inherit the selector.
2249
- if (auto attr = method->getAttrs ().getAttribute <ObjCAttr>()) {
2250
- if (attr->hasName () && !attr->isNameImplicit ()) {
2251
- {
2252
- auto diag = TC.diagnose (attr->AtLoc ,
2253
- diag::objc_override_method_selector_mismatch,
2254
- *attr->getName (), baseSelector);
2255
- fixDeclarationObjCName (diag, method, baseSelector);
2256
- }
2257
- TC.diagnose (baseMethod, diag::overridden_here);
2258
- }
2259
-
2260
- // Override the name on the attribute.
2261
- const_cast <ObjCAttr *>(attr)->setName (baseSelector,
2262
- /* implicit=*/ true );
2263
- } else {
2264
- method->getAttrs ().add (ObjCAttr::create (TC.Context ,
2265
- baseSelector,
2266
- true ));
2267
- }
2268
- }
2269
2378
} else if (method->isBodyThrowing ()) {
2270
2379
// Attach the foreign error convention.
2271
2380
assert (errorConvention && " Missing error convention" );
2272
2381
method->setForeignErrorConvention (*errorConvention);
2273
2382
}
2274
2383
2384
+ // Infer the Objective-C name for this method.
2385
+ inferObjCName (TC, method);
2386
+
2387
+ // ... then record it.
2275
2388
classDecl->recordObjCMethod (method);
2276
2389
2277
2390
// Swift does not permit class methods with Objective-C selectors 'load',
@@ -2295,37 +2408,9 @@ void swift::markAsObjC(TypeChecker &TC, ValueDecl *D,
2295
2408
diagInfo.first , diagInfo.second , sel);
2296
2409
}
2297
2410
}
2298
- } else if (auto var = dyn_cast<VarDecl>(D)) {
2299
- // If we are overriding a property, make sure that the
2300
- // Objective-C names of the properties match.
2301
- if (auto baseVar = var->getOverriddenDecl ()) {
2302
- if (var->getObjCPropertyName () != baseVar->getObjCPropertyName ()) {
2303
- Identifier baseName = baseVar->getObjCPropertyName ();
2304
- ObjCSelector baseSelector (TC.Context , 0 , baseName);
2305
-
2306
- // If not, see whether we can implicitly adjust.
2307
- if (auto attr = var->getAttrs ().getAttribute <ObjCAttr>()) {
2308
- if (attr->hasName () && !attr->isNameImplicit ()) {
2309
- TC.diagnose (attr->AtLoc ,
2310
- diag::objc_override_property_name_mismatch,
2311
- attr->getName ()->getSelectorPieces ()[0 ],
2312
- baseName)
2313
- .fixItReplaceChars (attr->getNameLocs ().front (),
2314
- attr->getRParenLoc (),
2315
- baseName.str ());
2316
- TC.diagnose (baseVar, diag::overridden_here);
2317
- }
2318
-
2319
- // Override the name on the attribute.
2320
- const_cast <ObjCAttr *>(attr)->setName (baseSelector,
2321
- /* implicit=*/ true );
2322
- } else {
2323
- var->getAttrs ().add (ObjCAttr::create (TC.Context ,
2324
- baseSelector,
2325
- true ));
2326
- }
2327
- }
2328
- }
2411
+ } else if (isa<VarDecl>(D)) {
2412
+ // Infer the Objective-C name for this property.
2413
+ inferObjCName (TC, D);
2329
2414
}
2330
2415
} else if (auto method = dyn_cast<AbstractFunctionDecl>(D)) {
2331
2416
if (method->isBodyThrowing ()) {
0 commit comments