Skip to content

Commit d21ff5c

Browse files
authored
Merge pull request #34171 from DougGregor/concurrency-objc-compatibility
[Concurrency] Improve source compatibility with 'async' imports
2 parents e5b6333 + e60a68e commit d21ff5c

File tree

14 files changed

+427
-140
lines changed

14 files changed

+427
-140
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4172,10 +4172,10 @@ NOTE(actor_mutable_state,none,
41724172
WARNING(shared_mutable_state_access,none,
41734173
"reference to %0 %1 is not concurrency-safe because it involves "
41744174
"shared mutable state", (DescriptiveDeclKind, DeclName))
4175-
NOTE(actor_isolated_witness,none,
4175+
ERROR(actor_isolated_witness,none,
41764176
"actor-isolated %0 %1 cannot be used to satisfy a protocol requirement",
41774177
(DescriptiveDeclKind, DeclName))
4178-
NOTE(actor_isolated_witness_could_be_async_handler,none,
4178+
ERROR(actor_isolated_witness_could_be_async_handler,none,
41794179
"actor-isolated %0 %1 cannot be used to satisfy a protocol requirement; "
41804180
"did you mean to make it an asychronous handler?",
41814181
(DescriptiveDeclKind, DeclName))

lib/ClangImporter/ClangImporter.cpp

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3701,48 +3701,46 @@ void ClangImporter::Implementation::lookupValue(
37013701

37023702
// If we have a declaration and nothing matched so far, try the names used
37033703
// in other versions of Swift.
3704-
if (!anyMatching) {
3705-
if (auto clangDecl = entry.dyn_cast<clang::NamedDecl *>()) {
3706-
const clang::NamedDecl *recentClangDecl =
3707-
clangDecl->getMostRecentDecl();
3708-
3709-
CurrentVersion.forEachOtherImportNameVersion(
3710-
SwiftContext.LangOpts.EnableExperimentalConcurrency,
3711-
[&](ImportNameVersion nameVersion) {
3712-
if (anyMatching)
3713-
return;
3714-
3715-
// Check to see if the name and context match what we expect.
3716-
ImportedName newName = importFullName(recentClangDecl, nameVersion);
3717-
if (!newName.getDeclName().matchesRef(name))
3718-
return;
3719-
3720-
// If we asked for an async import and didn't find one, skip this.
3721-
// This filters out duplicates.
3722-
if (nameVersion.supportsConcurrency() &&
3723-
!newName.getAsyncInfo())
3724-
return;
3725-
3726-
const clang::DeclContext *clangDC =
3727-
newName.getEffectiveContext().getAsDeclContext();
3728-
if (!clangDC || !clangDC->isFileContext())
3729-
return;
3730-
3731-
// Then try to import the decl under the alternate name.
3732-
auto alternateNamedDecl =
3733-
cast_or_null<ValueDecl>(importDeclReal(recentClangDecl,
3734-
nameVersion));
3735-
if (!alternateNamedDecl || alternateNamedDecl == decl)
3736-
return;
3737-
assert(alternateNamedDecl->getName().matchesRef(name) &&
3738-
"importFullName behaved differently from importDecl");
3739-
if (alternateNamedDecl->getDeclContext()->isModuleScopeContext()) {
3740-
consumer.foundDecl(alternateNamedDecl,
3741-
DeclVisibilityKind::VisibleAtTopLevel);
3742-
anyMatching = true;
3743-
}
3744-
});
3745-
}
3704+
if (auto clangDecl = entry.dyn_cast<clang::NamedDecl *>()) {
3705+
const clang::NamedDecl *recentClangDecl =
3706+
clangDecl->getMostRecentDecl();
3707+
3708+
CurrentVersion.forEachOtherImportNameVersion(
3709+
SwiftContext.LangOpts.EnableExperimentalConcurrency,
3710+
[&](ImportNameVersion nameVersion) {
3711+
if (anyMatching)
3712+
return;
3713+
3714+
// Check to see if the name and context match what we expect.
3715+
ImportedName newName = importFullName(recentClangDecl, nameVersion);
3716+
if (!newName.getDeclName().matchesRef(name))
3717+
return;
3718+
3719+
// If we asked for an async import and didn't find one, skip this.
3720+
// This filters out duplicates.
3721+
if (nameVersion.supportsConcurrency() &&
3722+
!newName.getAsyncInfo())
3723+
return;
3724+
3725+
const clang::DeclContext *clangDC =
3726+
newName.getEffectiveContext().getAsDeclContext();
3727+
if (!clangDC || !clangDC->isFileContext())
3728+
return;
3729+
3730+
// Then try to import the decl under the alternate name.
3731+
auto alternateNamedDecl =
3732+
cast_or_null<ValueDecl>(importDeclReal(recentClangDecl,
3733+
nameVersion));
3734+
if (!alternateNamedDecl || alternateNamedDecl == decl)
3735+
return;
3736+
assert(alternateNamedDecl->getName().matchesRef(name) &&
3737+
"importFullName behaved differently from importDecl");
3738+
if (alternateNamedDecl->getDeclContext()->isModuleScopeContext()) {
3739+
consumer.foundDecl(alternateNamedDecl,
3740+
DeclVisibilityKind::VisibleAtTopLevel);
3741+
anyMatching = true;
3742+
}
3743+
});
37463744
}
37473745
}
37483746
}

lib/ClangImporter/ImportName.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2084,13 +2084,15 @@ ImportedName NameImporter::importName(const clang::NamedDecl *decl,
20842084
bool NameImporter::forEachDistinctImportName(
20852085
const clang::NamedDecl *decl, ImportNameVersion activeVersion,
20862086
llvm::function_ref<bool(ImportedName, ImportNameVersion)> action) {
2087-
using ImportNameKey = std::pair<DeclName, EffectiveClangContext>;
2087+
using ImportNameKey = std::tuple<DeclName, EffectiveClangContext, bool>;
20882088
SmallVector<ImportNameKey, 8> seenNames;
20892089

20902090
ImportedName newName = importName(decl, activeVersion);
20912091
if (!newName)
20922092
return true;
2093-
ImportNameKey key(newName.getDeclName(), newName.getEffectiveContext());
2093+
2094+
ImportNameKey key(newName.getDeclName(), newName.getEffectiveContext(),
2095+
newName.getAsyncInfo().hasValue());
20942096
if (action(newName, activeVersion))
20952097
seenNames.push_back(key);
20962098

@@ -2101,15 +2103,18 @@ bool NameImporter::forEachDistinctImportName(
21012103
ImportedName newName = importName(decl, nameVersion);
21022104
if (!newName)
21032105
return;
2104-
ImportNameKey key(newName.getDeclName(), newName.getEffectiveContext());
2106+
ImportNameKey key(newName.getDeclName(), newName.getEffectiveContext(),
2107+
newName.getAsyncInfo().hasValue());
21052108

21062109
bool seen = llvm::any_of(
21072110
seenNames, [&key](const ImportNameKey &existing) -> bool {
2108-
return key.first == existing.first &&
2109-
key.second.equalsWithoutResolving(existing.second);
2111+
return std::get<0>(key) == std::get<0>(existing) &&
2112+
std::get<2>(key) == std::get<2>(existing) &&
2113+
std::get<1>(key).equalsWithoutResolving(std::get<1>(existing));
21102114
});
21112115
if (seen)
21122116
return;
2117+
21132118
if (action(newName, nameVersion))
21142119
seenNames.push_back(key);
21152120
});

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,16 @@ bool IsAsyncHandlerRequest::evaluate(
110110

111111
// Are we in a context where inference is possible?
112112
auto dc = func->getDeclContext();
113-
if (!dc->isTypeContext() || !dc->getParentSourceFile() ||
114-
isa<ProtocolDecl>(dc) || !func->hasBody())
113+
if (!dc->getSelfClassDecl() || !dc->getParentSourceFile() || !func->hasBody())
115114
return false;
116115

117116
// Is it possible to infer @asyncHandler for this function at all?
118117
if (!func->canBeAsyncHandler())
119118
return false;
120119

120+
if (!dc->getSelfClassDecl()->isActor())
121+
return false;
122+
121123
// Add an implicit @asyncHandler attribute and return true. We're done.
122124
auto addImplicitAsyncHandlerAttr = [&] {
123125
func->getAttrs().add(new (func->getASTContext()) AsyncHandlerAttr(true));

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,12 +2372,22 @@ bool swift::diagnoseObjCUnsatisfiedOptReqConflicts(SourceFile &sf) {
23722372
if (conflicts.empty())
23732373
continue;
23742374

2375+
auto bestConflict = conflicts[0];
2376+
for (auto conflict : conflicts) {
2377+
if (conflict->getName().isCompoundName() &&
2378+
conflict->getName().getArgumentNames().size() ==
2379+
req->getName().getArgumentNames().size()) {
2380+
bestConflict = conflict;
2381+
break;
2382+
}
2383+
}
2384+
23752385
// Diagnose the conflict.
23762386
auto reqDiagInfo = getObjCMethodDiagInfo(unsatisfied.second);
2377-
auto conflictDiagInfo = getObjCMethodDiagInfo(conflicts[0]);
2387+
auto conflictDiagInfo = getObjCMethodDiagInfo(bestConflict);
23782388
auto protocolName
23792389
= cast<ProtocolDecl>(req->getDeclContext())->getName();
2380-
Ctx.Diags.diagnose(conflicts[0],
2390+
Ctx.Diags.diagnose(bestConflict,
23812391
diag::objc_optional_requirement_conflict,
23822392
conflictDiagInfo.first,
23832393
conflictDiagInfo.second,
@@ -2387,9 +2397,9 @@ bool swift::diagnoseObjCUnsatisfiedOptReqConflicts(SourceFile &sf) {
23872397
protocolName);
23882398

23892399
// Fix the name of the witness, if we can.
2390-
if (req->getName() != conflicts[0]->getName() &&
2391-
req->getKind() == conflicts[0]->getKind() &&
2392-
isa<AccessorDecl>(req) == isa<AccessorDecl>(conflicts[0])) {
2400+
if (req->getName() != bestConflict->getName() &&
2401+
req->getKind() == bestConflict->getKind() &&
2402+
isa<AccessorDecl>(req) == isa<AccessorDecl>(bestConflict)) {
23932403
// They're of the same kind: fix the name.
23942404
unsigned kind;
23952405
if (isa<ConstructorDecl>(req))
@@ -2402,29 +2412,29 @@ bool swift::diagnoseObjCUnsatisfiedOptReqConflicts(SourceFile &sf) {
24022412
llvm_unreachable("unhandled @objc declaration kind");
24032413
}
24042414

2405-
auto diag = Ctx.Diags.diagnose(conflicts[0],
2415+
auto diag = Ctx.Diags.diagnose(bestConflict,
24062416
diag::objc_optional_requirement_swift_rename,
24072417
kind, req->getName());
24082418

24092419
// Fix the Swift name.
2410-
fixDeclarationName(diag, conflicts[0], req->getName());
2420+
fixDeclarationName(diag, bestConflict, req->getName());
24112421

24122422
// Fix the '@objc' attribute, if needed.
2413-
if (!conflicts[0]->canInferObjCFromRequirement(req))
2414-
fixDeclarationObjCName(diag, conflicts[0],
2415-
conflicts[0]->getObjCRuntimeName(),
2423+
if (!bestConflict->canInferObjCFromRequirement(req))
2424+
fixDeclarationObjCName(diag, bestConflict,
2425+
bestConflict->getObjCRuntimeName(),
24162426
req->getObjCRuntimeName(),
24172427
/*ignoreImpliedName=*/true);
24182428
}
24192429

24202430
// @nonobjc will silence this warning.
24212431
bool hasExplicitObjCAttribute = false;
2422-
if (auto objcAttr = conflicts[0]->getAttrs().getAttribute<ObjCAttr>())
2432+
if (auto objcAttr = bestConflict->getAttrs().getAttribute<ObjCAttr>())
24232433
hasExplicitObjCAttribute = !objcAttr->isImplicit();
24242434
if (!hasExplicitObjCAttribute)
2425-
Ctx.Diags.diagnose(conflicts[0], diag::req_near_match_nonobjc, true)
2435+
Ctx.Diags.diagnose(bestConflict, diag::req_near_match_nonobjc, true)
24262436
.fixItInsert(
2427-
conflicts[0]->getAttributeInsertionLoc(/*forModifier=*/false),
2437+
bestConflict->getAttributeInsertionLoc(/*forModifier=*/false),
24282438
"@nonobjc ");
24292439

24302440
Ctx.Diags.diagnose(getDeclContextLoc(unsatisfied.first),

0 commit comments

Comments
 (0)