Skip to content

Commit 6d5fa1e

Browse files
authored
[6.0][Distributed] Diagnose missing import also for funcs in extensions (#72928)
* [Distributed] Diagnose missing import also for funcs in extensions Resolves rdar://125813581 * [Distributed] Offer fixit for import Distributed when it is required
1 parent c83caf5 commit 6d5fa1e

20 files changed

+237
-59
lines changed

include/swift/AST/Decl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,13 @@ enum class DescriptiveDeclKind : uint8_t {
173173
Struct,
174174
Class,
175175
Actor,
176+
DistributedActor,
176177
Protocol,
177178
GenericEnum,
178179
GenericStruct,
179180
GenericClass,
180181
GenericActor,
182+
GenericDistributedActor,
181183
GenericType,
182184
Subscript,
183185
StaticSubscript,

include/swift/AST/DiagnosticEngine.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,9 @@ namespace swift {
727727

728728
static const char *fixItStringFor(const FixItID id);
729729

730+
/// Get the best location where an 'import' fixit might be offered.
731+
SourceLoc getBestAddImportFixItLoc(const Decl *Member) const;
732+
730733
/// Add a token-based replacement fix-it to the currently-active
731734
/// diagnostic.
732735
template <typename... ArgTypes>
@@ -783,6 +786,9 @@ namespace swift {
783786
return fixItReplaceChars(L, L, "%0", {Str});
784787
}
785788

789+
/// Add a fix-it suggesting to 'import' some module.
790+
InFlightDiagnostic &fixItAddImport(StringRef ModuleName);
791+
786792
/// Add an insertion fix-it to the currently-active diagnostic. The
787793
/// text is inserted immediately *after* the token specified.
788794
InFlightDiagnostic &fixItInsertAfter(SourceLoc L, StringRef Str) {
@@ -1391,6 +1397,11 @@ namespace swift {
13911397
SourceLoc getDefaultDiagnosticLoc() const {
13921398
return bufferIndirectlyCausingDiagnostic;
13931399
}
1400+
SourceLoc getBestAddImportFixItLoc(const Decl *Member,
1401+
SourceFile *sourceFile) const;
1402+
SourceLoc getBestAddImportFixItLoc(const Decl *Member) const {
1403+
return getBestAddImportFixItLoc(Member, nullptr);
1404+
}
13941405
};
13951406

13961407
/// Remember details about the state of a diagnostic engine and restore them

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5425,9 +5425,9 @@ ERROR(isolated_default_argument_context,none,
54255425
ERROR(conflicting_default_argument_isolation,none,
54265426
"default argument cannot be both %0 and %1",
54275427
(ActorIsolation, ActorIsolation))
5428-
ERROR(distributed_actor_needs_explicit_distributed_import,none,
5429-
"'Distributed' module not imported, required for 'distributed actor'",
5430-
())
5428+
ERROR(distributed_decl_needs_explicit_distributed_import,none,
5429+
"%kind0 declared without importing module 'Distributed'",
5430+
(const ValueDecl *))
54315431
NOTE(distributed_func_cannot_overload_on_async_only,none,
54325432
"%0 previously declared here, cannot overload distributed methods on effect only", (const ValueDecl *))
54335433
NOTE(distributed_func_other_ambiguous_overload_here,none,

include/swift/AST/TypeCheckRequests.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3025,7 +3025,7 @@ class HasCircularRawValueRequest
30253025

30263026
/// Checks if the Distributed module is available.
30273027
class DistributedModuleIsAvailableRequest
3028-
: public SimpleRequest<DistributedModuleIsAvailableRequest, bool(Decl *),
3028+
: public SimpleRequest<DistributedModuleIsAvailableRequest, bool(const ValueDecl *),
30293029
RequestFlags::Cached> {
30303030
public:
30313031
using SimpleRequest::SimpleRequest;
@@ -3034,7 +3034,7 @@ class DistributedModuleIsAvailableRequest
30343034
friend SimpleRequest;
30353035

30363036
// Evaluation.
3037-
bool evaluate(Evaluator &evaluator, Decl *decl) const;
3037+
bool evaluate(Evaluator &evaluator, const ValueDecl *decl) const;
30383038

30393039
public:
30403040
// Cached.

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest,
200200
SourceLoc, bool, bool),
201201
Uncached, NoLocationInfo)
202202
SWIFT_REQUEST(TypeChecker, DistributedModuleIsAvailableRequest,
203-
bool(ModuleDecl *), Cached, NoLocationInfo)
203+
bool(const ValueDecl *), Cached, NoLocationInfo)
204204
SWIFT_REQUEST(TypeChecker, InheritedTypeRequest,
205205
Type(llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *>,
206206
unsigned, TypeResolutionStage),

lib/AST/Decl.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,23 @@ DescriptiveDeclKind Decl::getDescriptiveKind() const {
187187
: DescriptiveDeclKind::Struct;
188188

189189
case DeclKind::Class: {
190-
bool isActor = cast<ClassDecl>(this)->isActor();
191-
return cast<ClassDecl>(this)->getGenericParams()
192-
? (isActor ? DescriptiveDeclKind::GenericActor
193-
: DescriptiveDeclKind::GenericClass)
194-
: (isActor ? DescriptiveDeclKind::Actor
195-
: DescriptiveDeclKind::Class);
190+
auto clazz = cast<ClassDecl>(this);
191+
bool isAnyActor = clazz->isAnyActor();
192+
bool isGeneric = clazz->getGenericParams();
193+
194+
auto kind = isGeneric ? DescriptiveDeclKind::GenericClass
195+
: DescriptiveDeclKind::Class;
196+
197+
if (isAnyActor) {
198+
if (clazz->isDistributedActor()) {
199+
kind = isGeneric ? DescriptiveDeclKind::GenericDistributedActor
200+
: DescriptiveDeclKind::DistributedActor;
201+
} else {
202+
kind = isGeneric ? DescriptiveDeclKind::GenericActor
203+
: DescriptiveDeclKind::Actor;
204+
}
205+
}
206+
return kind;
196207
}
197208

198209
case DeclKind::Var: {
@@ -332,11 +343,13 @@ StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) {
332343
ENTRY(Struct, "struct");
333344
ENTRY(Class, "class");
334345
ENTRY(Actor, "actor");
346+
ENTRY(DistributedActor, "distributed actor");
335347
ENTRY(Protocol, "protocol");
336348
ENTRY(GenericEnum, "generic enum");
337349
ENTRY(GenericStruct, "generic struct");
338350
ENTRY(GenericClass, "generic class");
339351
ENTRY(GenericActor, "generic actor");
352+
ENTRY(GenericDistributedActor, "generic distributed actor");
340353
ENTRY(GenericType, "generic type");
341354
ENTRY(Subscript, "subscript");
342355
ENTRY(StaticSubscript, "static subscript");

lib/AST/DiagnosticEngine.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,75 @@ InFlightDiagnostic::fixItReplaceChars(SourceLoc Start, SourceLoc End,
302302
return *this;
303303
}
304304

305+
SourceLoc
306+
DiagnosticEngine::getBestAddImportFixItLoc(const Decl *Member,
307+
SourceFile *sourceFile) const {
308+
auto &SM = SourceMgr;
309+
310+
SourceLoc bestLoc;
311+
312+
auto SF =
313+
sourceFile ? sourceFile : Member->getDeclContext()->getParentSourceFile();
314+
if (!SF) {
315+
return bestLoc;
316+
}
317+
318+
for (auto item : SF->getTopLevelItems()) {
319+
// If we found an import declaration, we want to insert after it.
320+
if (auto importDecl =
321+
dyn_cast_or_null<ImportDecl>(item.dyn_cast<Decl *>())) {
322+
SourceLoc loc = importDecl->getEndLoc();
323+
if (loc.isValid()) {
324+
bestLoc = Lexer::getLocForEndOfLine(SM, loc);
325+
}
326+
327+
// Keep looking for more import declarations.
328+
continue;
329+
}
330+
331+
// If we got a location based on import declarations, we're done.
332+
if (bestLoc.isValid())
333+
break;
334+
335+
// For any other item, we want to insert before it.
336+
SourceLoc loc = item.getStartLoc();
337+
if (loc.isValid()) {
338+
bestLoc = Lexer::getLocForStartOfLine(SM, loc);
339+
break;
340+
}
341+
}
342+
343+
return bestLoc;
344+
}
345+
346+
InFlightDiagnostic &InFlightDiagnostic::fixItAddImport(StringRef ModuleName) {
347+
assert(IsActive && "Cannot modify an inactive diagnostic");
348+
auto Member = Engine->ActiveDiagnostic->getDecl();
349+
SourceLoc bestLoc = Engine->getBestAddImportFixItLoc(Member);
350+
351+
if (bestLoc.isValid()) {
352+
llvm::SmallString<64> importText;
353+
354+
// @_spi imports.
355+
if (Member->isSPI()) {
356+
auto spiGroups = Member->getSPIGroups();
357+
if (!spiGroups.empty()) {
358+
importText += "@_spi(";
359+
importText += spiGroups[0].str();
360+
importText += ") ";
361+
}
362+
}
363+
364+
importText += "import ";
365+
importText += ModuleName;
366+
importText += "\n";
367+
368+
return fixItInsert(bestLoc, importText);
369+
}
370+
371+
return *this;
372+
}
373+
305374
InFlightDiagnostic &InFlightDiagnostic::fixItExchange(SourceRange R1,
306375
SourceRange R2) {
307376
assert(IsActive && "Cannot modify an inactive diagnostic");

lib/Basic/SourceLoc.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "swift/Basic/Range.h"
1413
#include "swift/Basic/SourceLoc.h"
14+
#include "swift/AST/SourceFile.h"
15+
#include "swift/Basic/Range.h"
1516
#include "swift/Basic/SourceManager.h"
1617
#include "llvm/Support/FileSystem.h"
1718
#include "llvm/Support/MemoryBuffer.h"
1819
#include "llvm/Support/PrettyStackTrace.h"
19-
#include "llvm/Support/raw_ostream.h"
2020
#include "llvm/Support/Signals.h"
21+
#include "llvm/Support/raw_ostream.h"
2122

2223
using namespace swift;
2324

lib/Sema/CSDiagnostics.cpp

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6196,33 +6196,8 @@ bool InaccessibleMemberFailure::diagnoseAsError() {
61966196
definingModule->getName());
61976197

61986198
auto enclosingSF = getDC()->getParentSourceFile();
6199-
SourceLoc bestLoc;
6200-
SourceManager &srcMgr = Member->getASTContext().SourceMgr;
6201-
for (auto item : enclosingSF->getTopLevelItems()) {
6202-
// If we found an import declaration, we want to insert after it.
6203-
if (auto importDecl =
6204-
dyn_cast_or_null<ImportDecl>(item.dyn_cast<Decl *>())) {
6205-
SourceLoc loc = importDecl->getEndLoc();
6206-
if (loc.isValid()) {
6207-
bestLoc = Lexer::getLocForEndOfLine(srcMgr, loc);
6208-
}
6209-
6210-
// Keep looking for more import declarations.
6211-
continue;
6212-
}
6213-
6214-
// If we got a location based on import declarations, we're done.
6215-
if (bestLoc.isValid())
6216-
break;
6217-
6218-
// For any other item, we want to insert before it.
6219-
SourceLoc loc = item.getStartLoc();
6220-
if (loc.isValid()) {
6221-
bestLoc = Lexer::getLocForStartOfLine(srcMgr, loc);
6222-
break;
6223-
}
6224-
}
6225-
6199+
SourceLoc bestLoc =
6200+
getBestAddImportFixItLocation(Member, getDC()->getParentSourceFile());
62266201
if (bestLoc.isValid()) {
62276202
llvm::SmallString<64> importText;
62286203

lib/Sema/CSDiagnostics.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ class FailureDiagnostic {
9090

9191
ConstraintLocator *getLocator() const { return Locator; }
9292

93+
SourceLoc getBestAddImportFixItLocation(const Decl *Member,
94+
SourceFile *sourceFile) const {
95+
auto &engine = Member->getASTContext().Diags;
96+
return engine.getBestAddImportFixItLoc(Member, sourceFile);
97+
}
98+
9399
Type getType(ASTNode node, bool wantRValue = true) const;
94100

95101
/// Get type associated with a given ASTNode without resolving it,

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ deriveBodyDistributed_thunk(AbstractFunctionDecl *thunk, void *context) {
231231

232232
// === Type:
233233
StructDecl *RCT = C.getRemoteCallTargetDecl();
234+
assert(RCT && "Missing RemoteCallTarget declaration");
234235
Type remoteCallTargetTy = RCT->getDeclaredInterfaceType();
235236

236237
// === __isRemoteActor(self)

lib/Sema/TypeCheckDistributed.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/NameLookupRequests.h"
2626
#include "swift/AST/TypeCheckRequests.h"
2727
#include "swift/AST/TypeVisitor.h"
28+
#include "swift/AST/ImportCache.h"
2829
#include "swift/AST/ExistentialLayout.h"
2930
#include "swift/Basic/Defer.h"
3031
#include "swift/AST/ASTPrinter.h"
@@ -33,7 +34,7 @@ using namespace swift;
3334

3435
// ==== ------------------------------------------------------------------------
3536

36-
bool swift::ensureDistributedModuleLoaded(Decl *decl) {
37+
bool swift::ensureDistributedModuleLoaded(const ValueDecl *decl) {
3738
auto &C = decl->getASTContext();
3839
auto moduleAvailable = evaluateOrDefault(
3940
C.evaluator, DistributedModuleIsAvailableRequest{decl}, false);
@@ -42,14 +43,25 @@ bool swift::ensureDistributedModuleLoaded(Decl *decl) {
4243

4344
bool
4445
DistributedModuleIsAvailableRequest::evaluate(Evaluator &evaluator,
45-
Decl *decl) const {
46+
const ValueDecl *decl) const {
4647
auto &C = decl->getASTContext();
4748

48-
if (C.getLoadedModule(C.Id_Distributed))
49+
auto DistributedModule = C.getLoadedModule(C.Id_Distributed);
50+
if (!DistributedModule) {
51+
decl->diagnose(diag::distributed_decl_needs_explicit_distributed_import,
52+
decl)
53+
.fixItAddImport("Distributed");
54+
return false;
55+
}
56+
57+
auto &importCache = C.getImportCache();
58+
if (importCache.isImportedBy(DistributedModule, decl->getDeclContext())) {
4959
return true;
60+
}
5061

5162
// seems we're missing the Distributed module, ask to import it explicitly
52-
decl->diagnose(diag::distributed_actor_needs_explicit_distributed_import);
63+
decl->diagnose(diag::distributed_decl_needs_explicit_distributed_import,
64+
decl);
5365
return false;
5466
}
5567

@@ -502,6 +514,10 @@ bool swift::checkDistributedFunction(AbstractFunctionDecl *func) {
502514
if (!func->isDistributed())
503515
return false;
504516

517+
// ==== Ensure the Distributed module is available,
518+
if (!swift::ensureDistributedModuleLoaded(func))
519+
return true;
520+
505521
auto &C = func->getASTContext();
506522
return evaluateOrDefault(C.evaluator,
507523
CheckDistributedFunctionRequest{func},
@@ -521,13 +537,11 @@ bool CheckDistributedFunctionRequest::evaluate(
521537
auto module = func->getParentModule();
522538

523539
/// If no distributed module is available, then no reason to even try checks.
524-
if (!C.getLoadedModule(C.Id_Distributed))
540+
if (!C.getLoadedModule(C.Id_Distributed)) {
541+
func->diagnose(diag::distributed_decl_needs_explicit_distributed_import,
542+
func);
525543
return true;
526-
527-
// // No checking for protocol requirements because they are not required
528-
// // to have `SerializationRequirement`.
529-
// if (isa<ProtocolDecl>(func->getDeclContext()))
530-
// return false;
544+
}
531545

532546
Type serializationReqType =
533547
getDistributedActorSerializationType(func->getDeclContext());

lib/Sema/TypeCheckDistributed.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class NominalTypeDecl;
3535
/******************************************************************************/
3636

3737
// Diagnose an error if the Distributed module is not loaded.
38-
bool ensureDistributedModuleLoaded(Decl *decl);
38+
bool ensureDistributedModuleLoaded(const ValueDecl *decl);
3939

4040
/// Check for illegal property declarations (e.g. re-declaring transport or id)
4141
void checkDistributedActorProperties(const NominalTypeDecl *decl);

test/Distributed/Inputs/FakeDistributedActorSystems.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414

1515
import Distributed
1616

17+
// ==== Example Distributed Actors ----------------------------------------------
18+
19+
@available(SwiftStdlib 5.7, *)
20+
public distributed actor FakeRoundtripActorSystemDistributedActor {
21+
public typealias ActorSystem = FakeRoundtripActorSystem
22+
}
23+
1724
// ==== Fake Address -----------------------------------------------------------
1825

1926
public struct ActorAddress: Hashable, Sendable, Codable {

0 commit comments

Comments
 (0)