Skip to content

Commit a6b312f

Browse files
committed
[region-isolation] Change capturing a value into an async let that is not further sent into an actor isolated function to use a new style error.
Just going through and fixing sending errors. rdar://130915737 (cherry picked from commit 02e003f)
1 parent f126023 commit a6b312f

File tree

3 files changed

+134
-78
lines changed

3 files changed

+134
-78
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,10 @@ NOTE(regionbasedisolation_named_transfer_non_transferrable, none,
990990
NOTE(regionbasedisolation_named_transfer_non_transferrable_callee, none,
991991
"sending %1%0 to %2 %3 %4 risks causing data races between %2 and %5 uses",
992992
(Identifier, StringRef, ActorIsolation, DescriptiveDeclKind, DeclName, StringRef))
993+
NOTE(regionbasedisolation_named_nonisolated_asynclet_name, none,
994+
"sending %0 into async let risks causing data races between async let uses and local uses",
995+
(Identifier))
996+
993997
NOTE(regionbasedisolation_named_transfer_into_sending_param, none,
994998
"%0%1 is passed as a 'sending' parameter; Uses in callee may race with later %0uses",
995999
(StringRef, Identifier))

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 83 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,19 @@ class UseAfterTransferDiagnosticEmitter {
574574
emitRequireInstDiagnostics();
575575
}
576576

577+
void emitNamedAsyncLetNoIsolationCrossingError(SILLocation loc,
578+
Identifier name) {
579+
// Emit the short error.
580+
diagnoseError(loc, diag::regionbasedisolation_named_transfer_yields_race,
581+
name)
582+
.highlight(loc.getSourceRange())
583+
.limitBehaviorIf(getBehaviorLimit());
584+
585+
diagnoseNote(
586+
loc, diag::regionbasedisolation_named_nonisolated_asynclet_name, name);
587+
emitRequireInstDiagnostics();
588+
}
589+
577590
void emitTypedIsolationCrossing(SILLocation loc, Type inferredType,
578591
ApplyIsolationCrossing isolationCrossing) {
579592
diagnoseError(
@@ -843,7 +856,7 @@ struct UseAfterTransferDiagnosticInferrer::AutoClosureWalker : ASTWalker {
843856
: foundTypeInfo(foundTypeInfo), targetDecl(targetDecl),
844857
targetDeclIsolationInfo(targetDeclIsolationInfo) {}
845858

846-
Expr *lookThroughExpr(Expr *expr) {
859+
Expr *lookThroughArgExpr(Expr *expr) {
847860
while (true) {
848861
if (auto *memberRefExpr = dyn_cast<MemberRefExpr>(expr)) {
849862
expr = memberRefExpr->getBase();
@@ -871,67 +884,85 @@ struct UseAfterTransferDiagnosticInferrer::AutoClosureWalker : ASTWalker {
871884

872885
PreWalkResult<Expr *> walkToExprPre(Expr *expr) override {
873886
if (auto *declRef = dyn_cast<DeclRefExpr>(expr)) {
874-
// If this decl ref expr was not visited as part of a callExpr, add it as
875-
// something without isolation crossing.
887+
// If this decl ref expr was not visited as part of a callExpr and is our
888+
// target decl... emit a simple async let error.
876889
if (!visitedCallExprDeclRefExprs.count(declRef)) {
877890
if (declRef->getDecl() == targetDecl) {
878-
visitedCallExprDeclRefExprs.insert(declRef);
879891
foundTypeInfo.diagnosticEmitter
880-
.emitTypedRaceWithUnknownIsolationCrossing(
881-
foundTypeInfo.baseLoc, declRef->findOriginalType());
892+
.emitNamedAsyncLetNoIsolationCrossingError(
893+
foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier());
882894
return Action::Continue(expr);
883895
}
884896
}
885897
}
886898

899+
// If we have a call expr, see if any of its arguments will cause our sent
900+
// value to be transferred into another isolation domain.
887901
if (auto *callExpr = dyn_cast<CallExpr>(expr)) {
888-
if (auto isolationCrossing = callExpr->getIsolationCrossing()) {
889-
// Search callExpr's arguments to see if we have our targetDecl.
890-
auto *argList = callExpr->getArgs();
891-
for (auto pair : llvm::enumerate(argList->getArgExprs())) {
892-
auto *arg = lookThroughExpr(pair.value());
893-
if (auto *declRef = dyn_cast<DeclRefExpr>(arg)) {
894-
if (declRef->getDecl() == targetDecl) {
895-
// Found our target!
896-
visitedCallExprDeclRefExprs.insert(declRef);
897-
898-
// See if we can find a valueDecl/name for our callee so we can
899-
// emit a nicer error.
900-
ConcreteDeclRef concreteDecl =
901-
callExpr->getDirectCallee()->getReferencedDecl();
902-
903-
// If we do not find a direct one, see if we are calling a method
904-
// on a nominal type.
905-
if (!concreteDecl) {
906-
if (auto *dot = dyn_cast<DotSyntaxCallExpr>(
907-
callExpr->getDirectCallee())) {
908-
concreteDecl = dot->getSemanticFn()->getReferencedDecl();
909-
}
910-
}
911-
912-
if (concreteDecl) {
913-
auto *valueDecl = concreteDecl.getDecl();
914-
assert(valueDecl &&
915-
"Should be non-null if concreteDecl is valid");
916-
if (valueDecl->hasName()) {
917-
foundTypeInfo.diagnosticEmitter
918-
.emitNamedIsolationCrossingError(
919-
foundTypeInfo.baseLoc,
920-
targetDecl->getBaseIdentifier(),
921-
targetDeclIsolationInfo, *isolationCrossing,
922-
valueDecl->getName(),
923-
valueDecl->getDescriptiveKind());
924-
return Action::Continue(expr);
925-
}
926-
}
927-
928-
// Otherwise default back to the "callee" error.
929-
foundTypeInfo.diagnosticEmitter.emitNamedIsolationCrossingError(
930-
foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier(),
931-
targetDeclIsolationInfo, *isolationCrossing);
932-
return Action::Continue(expr);
933-
}
902+
// Search callExpr's arguments to see if we have our targetDecl.
903+
auto *argList = callExpr->getArgs();
904+
for (auto pair : llvm::enumerate(argList->getArgExprs())) {
905+
auto *arg = lookThroughArgExpr(pair.value());
906+
auto *declRef = dyn_cast<DeclRefExpr>(arg);
907+
if (!declRef)
908+
continue;
909+
910+
if (declRef->getDecl() != targetDecl)
911+
continue;
912+
913+
// Found our target!
914+
visitedCallExprDeclRefExprs.insert(declRef);
915+
916+
auto isolationCrossing = callExpr->getIsolationCrossing();
917+
918+
// If we do not have an isolation crossing, then we must be just sending
919+
// a value in a nonisolated fashion into an async let. So emit the
920+
// simple async let error.
921+
if (!isolationCrossing) {
922+
foundTypeInfo.diagnosticEmitter
923+
.emitNamedAsyncLetNoIsolationCrossingError(
924+
foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier());
925+
continue;
926+
}
927+
928+
// Otherwise, we are calling an actor isolated function in the async
929+
// let. Emit a better error.
930+
931+
// See if we can find a valueDecl/name for our callee so we can
932+
// emit a nicer error.
933+
ConcreteDeclRef concreteDecl =
934+
callExpr->getDirectCallee()->getReferencedDecl();
935+
936+
// If we do not find a direct one, see if we are calling a method
937+
// on a nominal type.
938+
if (!concreteDecl) {
939+
if (auto *dot =
940+
dyn_cast<DotSyntaxCallExpr>(callExpr->getDirectCallee())) {
941+
concreteDecl = dot->getSemanticFn()->getReferencedDecl();
942+
}
943+
}
944+
945+
if (!concreteDecl)
946+
continue;
947+
948+
auto *valueDecl = concreteDecl.getDecl();
949+
assert(valueDecl && "Should be non-null if concreteDecl is valid");
950+
951+
if (auto isolationCrossing = callExpr->getIsolationCrossing()) {
952+
// If we have an isolation crossing, use that information.
953+
if (valueDecl->hasName()) {
954+
foundTypeInfo.diagnosticEmitter.emitNamedIsolationCrossingError(
955+
foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier(),
956+
targetDeclIsolationInfo, *isolationCrossing,
957+
valueDecl->getName(), valueDecl->getDescriptiveKind());
958+
continue;
934959
}
960+
961+
// Otherwise default back to the "callee" error.
962+
foundTypeInfo.diagnosticEmitter.emitNamedIsolationCrossingError(
963+
foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier(),
964+
targetDeclIsolationInfo, *isolationCrossing);
965+
continue;
935966
}
936967
}
937968
}

0 commit comments

Comments
 (0)