Skip to content

Commit 02e003f

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
1 parent 78d74cf commit 02e003f

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
@@ -994,6 +994,10 @@ NOTE(regionbasedisolation_named_transfer_non_transferrable, none,
994994
NOTE(regionbasedisolation_named_transfer_non_transferrable_callee, none,
995995
"sending %1%0 to %2 %3 %4 risks causing data races between %2 and %5 uses",
996996
(Identifier, StringRef, ActorIsolation, DescriptiveDeclKind, DeclName, StringRef))
997+
NOTE(regionbasedisolation_named_nonisolated_asynclet_name, none,
998+
"sending %0 into async let risks causing data races between async let uses and local uses",
999+
(Identifier))
1000+
9971001
NOTE(regionbasedisolation_named_transfer_into_sending_param, none,
9981002
"%0%1 is passed as a 'sending' parameter; Uses in callee may race with later %0uses",
9991003
(StringRef, Identifier))

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

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

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

847-
Expr *lookThroughExpr(Expr *expr) {
860+
Expr *lookThroughArgExpr(Expr *expr) {
848861
while (true) {
849862
if (auto *memberRefExpr = dyn_cast<MemberRefExpr>(expr)) {
850863
expr = memberRefExpr->getBase();
@@ -872,67 +885,85 @@ struct UseAfterTransferDiagnosticInferrer::AutoClosureWalker : ASTWalker {
872885

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

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

0 commit comments

Comments
 (0)