@@ -1225,6 +1225,79 @@ void swift::diagnoseMissingExplicitSendable(NominalTypeDecl *nominal) {
1225
1225
}
1226
1226
}
1227
1227
1228
+ void swift::tryDiagnoseExecutorConformance (ASTContext &C,
1229
+ const NominalTypeDecl *nominal,
1230
+ ProtocolDecl *proto) {
1231
+ assert (proto->isSpecificProtocol (KnownProtocolKind::Executor) ||
1232
+ proto->isSpecificProtocol (KnownProtocolKind::SerialExecutor));
1233
+
1234
+ auto &diags = C.Diags ;
1235
+ auto module = nominal->getParentModule ();
1236
+ Type nominalTy = nominal->getDeclaredInterfaceType ();
1237
+
1238
+ // enqueue(_: UnownedJob)
1239
+ auto enqueueDeclName = DeclName (C, DeclBaseName (C.Id_enqueue ), { Identifier () });
1240
+
1241
+ FuncDecl *unownedEnqueueRequirement = nullptr ;
1242
+ FuncDecl *moveOnlyEnqueueRequirement = nullptr ;
1243
+ for (auto req: proto->getProtocolRequirements ()) {
1244
+ auto *funcDecl = dyn_cast<FuncDecl>(req);
1245
+ if (!funcDecl)
1246
+ continue ;
1247
+
1248
+ if (funcDecl->getName () != enqueueDeclName)
1249
+ continue ;
1250
+
1251
+
1252
+ // look for the first parameter being a Job or UnownedJob
1253
+ if (funcDecl->getParameters ()->size () != 1 )
1254
+ continue ;
1255
+ if (auto param = funcDecl->getParameters ()->front ()) {
1256
+ if (param->getType ()->isEqual (C.getJobDecl ()->getDeclaredInterfaceType ())) {
1257
+ assert (moveOnlyEnqueueRequirement == nullptr );
1258
+ moveOnlyEnqueueRequirement = funcDecl;
1259
+ } else if (param->getType ()->isEqual (C.getUnownedJobDecl ()->getDeclaredInterfaceType ())) {
1260
+ assert (unownedEnqueueRequirement == nullptr );
1261
+ unownedEnqueueRequirement = funcDecl;
1262
+ }
1263
+ }
1264
+
1265
+ // if we found both, we're done here and break out of the loop
1266
+ if (unownedEnqueueRequirement && moveOnlyEnqueueRequirement)
1267
+ break ; // we're done looking for the requirements
1268
+ }
1269
+
1270
+
1271
+ auto conformance = module ->lookupConformance (nominalTy, proto);
1272
+ auto concreteConformance = conformance.getConcrete ();
1273
+ auto unownedEnqueueWitness = concreteConformance->getWitnessDeclRef (unownedEnqueueRequirement);
1274
+ auto moveOnlyEnqueueWitness = concreteConformance->getWitnessDeclRef (moveOnlyEnqueueRequirement);
1275
+
1276
+ if (auto enqueueUnownedDecl = unownedEnqueueWitness.getDecl ()) {
1277
+ // Old UnownedJob based impl is present, warn about it suggesting the new protocol requirement.
1278
+ if (enqueueUnownedDecl->getLoc ().isValid ()) {
1279
+ diags.diagnose (enqueueUnownedDecl->getLoc (), diag::executor_enqueue_unowned_implementation, nominalTy);
1280
+ }
1281
+ }
1282
+
1283
+ if (auto unownedEnqueueDecl = unownedEnqueueWitness.getDecl ()) {
1284
+ if (auto moveOnlyEnqueueDecl = moveOnlyEnqueueWitness.getDecl ()) {
1285
+ if (unownedEnqueueDecl && unownedEnqueueDecl->getLoc ().isInvalid () &&
1286
+ moveOnlyEnqueueDecl && moveOnlyEnqueueDecl->getLoc ().isInvalid ()) {
1287
+ // Neither old nor new implementation have been found, but we provide default impls for them
1288
+ // that are mutually recursive, so we must error and suggest implementing the right requirement.
1289
+ auto ownedRequirement = C.getExecutorDecl ()->getExecutorOwnedEnqueueFunction ();
1290
+ nominal->diagnose (diag::type_does_not_conform, nominalTy, proto->getDeclaredInterfaceType ());
1291
+ ownedRequirement->diagnose (diag::no_witnesses,
1292
+ getProtocolRequirementKind (ownedRequirement),
1293
+ ownedRequirement->getName (),
1294
+ proto->getDeclaredInterfaceType (),
1295
+ /* AddFixIt=*/ true );
1296
+ }
1297
+ }
1298
+ }
1299
+ }
1300
+
1228
1301
// / Determine whether this is the main actor type.
1229
1302
static bool isMainActor (Type type) {
1230
1303
if (auto nominal = type->getAnyNominal ())
0 commit comments