@@ -1225,6 +1225,79 @@ void swift::diagnoseMissingExplicitSendable(NominalTypeDecl *nominal) {
12251225 }
12261226}
12271227
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+
12281301// / Determine whether this is the main actor type.
12291302static bool isMainActor (Type type) {
12301303 if (auto nominal = type->getAnyNominal ())
0 commit comments