Skip to content

Commit 30653a8

Browse files
committed
[Distributed] Don't crash in thunk generation when missing SR conformance
1 parent a14075a commit 30653a8

8 files changed

+88
-15
lines changed

include/swift/AST/DistributedDecl.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,11 @@ getDistributedSerializationRequirements(
117117
/// Given any set of generic requirements, locate those which are about the
118118
/// `SerializationRequirement`. Those need to be applied in the parameter and
119119
/// return type checking of distributed targets.
120-
llvm::SmallPtrSet<ProtocolDecl *, 2>
120+
void
121121
extractDistributedSerializationRequirements(
122-
ASTContext &C, ArrayRef<Requirement> allRequirements);
122+
ASTContext &C,
123+
ArrayRef<Requirement> allRequirements,
124+
llvm::SmallPtrSet<ProtocolDecl *, 2> &into);
123125

124126
}
125127

lib/AST/DistributedDecl.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,10 +1214,11 @@ AbstractFunctionDecl::isDistributedTargetInvocationResultHandlerOnReturn() const
12141214
return true;
12151215
}
12161216

1217-
llvm::SmallPtrSet<ProtocolDecl *, 2>
1217+
void
12181218
swift::extractDistributedSerializationRequirements(
1219-
ASTContext &C, ArrayRef<Requirement> allRequirements) {
1220-
llvm::SmallPtrSet<ProtocolDecl *, 2> serializationReqs;
1219+
ASTContext &C,
1220+
ArrayRef<Requirement> allRequirements,
1221+
llvm::SmallPtrSet<ProtocolDecl *, 2> &into) {
12211222
auto DA = C.getDistributedActorDecl();
12221223
auto daSerializationReqAssocType =
12231224
DA->getAssociatedType(C.Id_SerializationRequirement);
@@ -1238,8 +1239,6 @@ swift::extractDistributedSerializationRequirements(
12381239
}
12391240
}
12401241
}
1241-
1242-
return serializationReqs;
12431242
}
12441243

12451244
/******************************************************************************/

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,9 +842,15 @@ FuncDecl *GetDistributedThunkRequest::evaluate(Evaluator &evaluator,
842842
if (!distributedTarget->isDistributed())
843843
return nullptr;
844844
}
845-
846845
assert(distributedTarget);
847846

847+
// This evaluation type-check by now was already computed and cached;
848+
// We need to check in order to avoid emitting a THUNK for a distributed func
849+
// which had errors; as the thunk then may also cause un-addressable issues and confusion.
850+
if (swift::checkDistributedFunction(distributedTarget)) {
851+
return nullptr;
852+
}
853+
848854
auto &C = distributedTarget->getASTContext();
849855

850856
if (!getConcreteReplacementForProtocolActorSystemType(distributedTarget)) {

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2071,7 +2071,7 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
20712071
return (prop &&
20722072
prop->isFinal() &&
20732073
isa<ClassDecl>(prop->getDeclContext()) &&
2074-
cast<ClassDecl>(prop->getDeclContext())->isActor() &&
2074+
cast<ClassDecl>(prop->getDeclContext())->isAnyActor() &&
20752075
!prop->isStatic() &&
20762076
prop->getName() == ctx.Id_unownedExecutor &&
20772077
prop->getInterfaceType()->getAnyNominal() == ctx.getUnownedSerialExecutorDecl());

lib/Sema/TypeCheckDistributed.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,22 @@ bool CheckDistributedFunctionRequest::evaluate(
498498
// SerializationRequirement
499499
llvm::SmallPtrSet<ProtocolDecl *, 2> serializationRequirements;
500500
if (auto extension = dyn_cast<ExtensionDecl>(DC)) {
501-
serializationRequirements = extractDistributedSerializationRequirements(
502-
C, extension->getGenericRequirements());
501+
auto actorOrProtocol = extension->getExtendedNominal();
502+
if (auto actor = dyn_cast<ClassDecl>(actorOrProtocol)) {
503+
assert(actor->isAnyActor());
504+
serializationRequirements = getDistributedSerializationRequirementProtocols(
505+
getDistributedActorSystemType(actor)->getAnyNominal(),
506+
C.getProtocol(KnownProtocolKind::DistributedActorSystem));
507+
} else if (auto protocol = dyn_cast<ProtocolDecl>(actorOrProtocol)) {
508+
extractDistributedSerializationRequirements(
509+
C, protocol->getGenericRequirements(),
510+
/*into=*/serializationRequirements);
511+
extractDistributedSerializationRequirements(
512+
C, extension->getGenericRequirements(),
513+
/*into=*/serializationRequirements);
514+
} else {
515+
// ignore
516+
}
503517
} else if (auto actor = dyn_cast<ClassDecl>(DC)) {
504518
serializationRequirements = getDistributedSerializationRequirementProtocols(
505519
getDistributedActorSystemType(actor)->getAnyNominal(),
@@ -546,6 +560,7 @@ bool CheckDistributedFunctionRequest::evaluate(
546560
if (auto paramNominalTy = paramTy->getAnyNominal()) {
547561
addCodableFixIt(paramNominalTy, diag);
548562
} // else, no nominal type to suggest the fixit for, e.g. a closure
563+
549564
return true;
550565
}
551566
}
@@ -740,11 +755,11 @@ void TypeChecker::checkDistributedActor(SourceFile *SF, NominalTypeDecl *nominal
740755
(void)nominal->getDistributedActorIDProperty();
741756
}
742757

743-
void TypeChecker::checkDistributedFunc(FuncDecl *func) {
758+
bool TypeChecker::checkDistributedFunc(FuncDecl *func) {
744759
if (!func->isDistributed())
745-
return;
760+
return false;
746761

747-
swift::checkDistributedFunction(func);
762+
return swift::checkDistributedFunction(func);
748763
}
749764

750765
llvm::SmallPtrSet<ProtocolDecl *, 2>

lib/Sema/TypeCheckStmt.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2775,6 +2775,14 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &eval,
27752775
// So, build out the body now.
27762776
ASTScope::expandFunctionBody(AFD);
27772777

2778+
if (AFD->isDistributedThunk()) {
2779+
if (auto func = dyn_cast<FuncDecl>(AFD)) {
2780+
if (TypeChecker::checkDistributedFunc(func)) {
2781+
return errorBody();
2782+
}
2783+
}
2784+
}
2785+
27782786
// Type check the function body if needed.
27792787
bool hadError = false;
27802788
if (!alreadyTypeChecked) {

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1127,7 +1127,9 @@ diagnosePotentialUnavailability(SourceRange ReferenceRange,
11271127
void checkDistributedActor(SourceFile *SF, NominalTypeDecl *decl);
11281128

11291129
/// Type check a single 'distributed func' declaration.
1130-
void checkDistributedFunc(FuncDecl *func);
1130+
///
1131+
/// Returns `true` if there was an error.
1132+
bool checkDistributedFunc(FuncDecl *func);
11311133

11321134
bool checkAvailability(SourceRange ReferenceRange,
11331135
AvailabilityContext Availability,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift
3+
// RUN: %target-build-swift -module-name main -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/Inputs/FakeDistributedActorSystems.swift 2> %t/output.txt || echo 'failed expectedly'
4+
// RUN: %FileCheck %s < %t/output.txt
5+
6+
// REQUIRES: concurrency
7+
// REQUIRES: distributed
8+
9+
// rdar://76038845
10+
// UNSUPPORTED: use_os_stdlib
11+
// UNSUPPORTED: back_deployment_runtime
12+
13+
import Distributed
14+
15+
// Notes:
16+
// This test specifically is not just a -typecheck -verify test but attempts to generate the whole module.
17+
// This is because we may be emitting errors but otherwise still attempt to emit a thunk for an "error-ed"
18+
// distributed function, which would then crash in later phases of compilation when we try to get types
19+
// of the `func` the THUNK is based on.
20+
21+
typealias DefaultDistributedActorSystem = LocalTestingDistributedActorSystem
22+
23+
distributed actor Service {
24+
}
25+
26+
extension Service {
27+
distributed func boombox(_ id: Box) async throws {}
28+
// CHECK: parameter '' of type 'Box' in distributed instance method does not conform to serialization requirement 'Codable'
29+
30+
distributed func boxIt() async throws -> Box { fatalError() }
31+
// CHECK: result type 'Box' of distributed instance method 'boxIt' does not conform to serialization requirement 'Codable'
32+
}
33+
34+
public enum Box: Hashable { case boom }
35+
36+
@main struct Main {
37+
static func main() async {
38+
try? await Service(actorSystem: .init()).boombox(Box.boom)
39+
}
40+
}
41+

0 commit comments

Comments
 (0)