Skip to content

Commit 1228619

Browse files
committed
[NFC] Improvements suggested in code review
Thank you, @hamishknight and @varungandhi-apple.
1 parent 747c507 commit 1228619

File tree

6 files changed

+93
-46
lines changed

6 files changed

+93
-46
lines changed

docs/Lexicon.rst

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,32 @@ source code, tests, and commit messages. See also the `LLVM lexicon`_.
264264
compiler can do something with it.
265265

266266
overlay
267-
A library that is imported whenever a C library or framework by the same
268-
name is imported. The purpose of an overlay is to augment and extend a
269-
library on the system when the library on the system cannot be modified.
270-
Apple has a number of overlays for its own SDKs in stdlib/public/SDK/.
267+
A wrapper library that is implicitly imported "on top of" another library.
268+
It contains an @_exported import of the underlying library, but it augments
269+
it with additional APIs which, for one reason or another, are not included
270+
in the underlying library directly.
271+
272+
There are two kinds of overlays:
273+
274+
A "clang overlay" (the older kind, so it's often just called an "overlay")
275+
is a Swift library that adds Swift-specific functionality to a C-family
276+
library or framework. Clang overlays are used with system libraries that
277+
cannot be modified to add Swift features. A clang overlay has the same
278+
module name as the underlying library and can do a few special things that
279+
normal modules can't, like adding required initializers to classes. If a
280+
module has a clang overlay, the Clang Importer will always load it unless it
281+
is actually compiling the overlay itself. Apple has a number of clang
282+
overlays for its own SDKs in stdlib/public/Darwin/.
283+
284+
A "separately-imported overlay" is a separate module with its own name.
285+
Unlike a clang overlay, it can be imported in some SourceFiles and not
286+
others. When the compiler processes import declarations, it determines which
287+
separately-imported overlays need to be imported and then adds them to the
288+
list of imports for that file; name lookup also knows to look through the
289+
overlay when it looks for declarations in the underlying module.
290+
Separately-imported overlays are used to implement the "cross-import
291+
overlays" feature, which is used to augment a module with additional
292+
functionality when it is imported alongside another module.
271293

272294
PCH
273295
Precompiled header, a type of file ending in .pch. A precompiled header is

include/swift/AST/Module.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,6 @@ class ModuleDecl : public DeclContext, public TypeDecl {
205205

206206
SmallVector<FileUnit *, 2> Files;
207207

208-
friend OverlayFile;
209208
llvm::SmallDenseMap<Identifier, SmallVector<OverlayFile *, 1>>
210209
declaredCrossImports;
211210

@@ -268,7 +267,7 @@ class ModuleDecl : public DeclContext, public TypeDecl {
268267
/// reverse the positions of the two modules involved in the cross-import.
269268
void findDeclaredCrossImportOverlays(
270269
Identifier bystanderName, SmallVectorImpl<Identifier> &overlayNames,
271-
SourceLoc diagLoc);
270+
SourceLoc diagLoc) const;
272271

273272
/// Get the list of all modules this module declares a cross-import with.
274273
void getDeclaredCrossImportBystanders(

lib/AST/Module.cpp

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,19 +1464,18 @@ const clang::Module *ModuleDecl::findUnderlyingClangModule() const {
14641464
namespace swift {
14651465
/// Represents a file containing information about cross-module overlays.
14661466
class OverlayFile {
1467-
/// If not empty, contains the name of the cross-import file that must be
1468-
/// loaded; \c overlayModuleNames is not valid and must be empty.
1469-
///
1470-
/// If empty, \c overlayModuleNames is valid and will contain the list of
1471-
/// module names unless loading the file failed.
1467+
/// The file that data should be loaded from.
14721468
StringRef filePath;
14731469

14741470
/// The list of module names; empty if loading failed.
14751471
llvm::TinyPtrVector<Identifier> overlayModuleNames;
14761472

1473+
enum class State { pending, loaded, failed };
1474+
State state = State::pending;
1475+
14771476
/// Actually loads the overlay module name list. This should mutate
14781477
/// \c overlayModuleNames, but not \c filePath.
1479-
void loadOverlayModuleNames(ModuleDecl *M, SourceLoc diagLoc,
1478+
bool loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
14801479
Identifier bystandingModule);
14811480

14821481
public:
@@ -1487,8 +1486,7 @@ class OverlayFile {
14871486
return ctx.Allocate(bytes, alignment);
14881487
}
14891488

1490-
OverlayFile(StringRef filePath)
1491-
: filePath(filePath), overlayModuleNames() { }
1489+
OverlayFile(StringRef filePath) : filePath(filePath) { }
14921490

14931491
/// Returns the list of additional modules that should be imported if both
14941492
/// the primary and secondary modules have been imported. This may load a
@@ -1497,13 +1495,12 @@ class OverlayFile {
14971495
///
14981496
/// The result can be empty, either because of an error or because the file
14991497
/// didn't contain any overlay module names.
1500-
ArrayRef<Identifier> getOverlayModuleNames(ModuleDecl *M, SourceLoc diagLoc,
1498+
ArrayRef<Identifier> getOverlayModuleNames(const ModuleDecl *M,
1499+
SourceLoc diagLoc,
15011500
Identifier bystandingModule) {
1502-
if (!filePath.empty()) {
1503-
assert(overlayModuleNames.empty()
1504-
&& "cross-import list can't be full before loading");
1505-
loadOverlayModuleNames(M, diagLoc, bystandingModule);
1506-
filePath = "";
1501+
if (state == State::pending) {
1502+
state = loadOverlayModuleNames(M, diagLoc, bystandingModule)
1503+
? State::loaded : State::failed;
15071504
}
15081505
return overlayModuleNames;
15091506
}
@@ -1521,12 +1518,12 @@ void ModuleDecl::addCrossImportOverlayFile(StringRef file) {
15211518
void ModuleDecl::
15221519
findDeclaredCrossImportOverlays(Identifier bystanderName,
15231520
SmallVectorImpl<Identifier> &overlayNames,
1524-
SourceLoc diagLoc) {
1521+
SourceLoc diagLoc) const {
15251522
if (getName() == bystanderName)
15261523
// We don't currently support self-cross-imports.
15271524
return;
15281525

1529-
for (auto &crossImportFile : declaredCrossImports[bystanderName])
1526+
for (auto &crossImportFile : declaredCrossImports.lookup(bystanderName))
15301527
llvm::copy(crossImportFile->getOverlayModuleNames(this, diagLoc,
15311528
bystanderName),
15321529
std::back_inserter(overlayNames));
@@ -1602,20 +1599,20 @@ OverlayFileContents::load(std::unique_ptr<llvm::MemoryBuffer> input,
16021599
return contents;
16031600
}
16041601

1605-
void OverlayFile::loadOverlayModuleNames(ModuleDecl *M, SourceLoc diagLoc,
1606-
Identifier bystanderName) {
1602+
bool
1603+
OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
1604+
Identifier bystanderName) {
16071605
assert(!filePath.empty());
16081606

16091607
auto &ctx = M->getASTContext();
16101608
llvm::vfs::FileSystem &fs = *ctx.SourceMgr.getFileSystem();
16111609

16121610
auto bufOrError = fs.getBufferForFile(filePath);
16131611
if (!bufOrError) {
1614-
M->getASTContext().Diags
1615-
.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file,
1616-
M->getName(), bystanderName, bufOrError.getError().message(),
1617-
filePath);
1618-
return;
1612+
ctx.Diags.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file,
1613+
M->getName(), bystanderName,
1614+
bufOrError.getError().message(), filePath);
1615+
return false;
16191616
}
16201617

16211618
SmallVector<std::string, 4> errorMessages;
@@ -1626,10 +1623,9 @@ void OverlayFile::loadOverlayModuleNames(ModuleDecl *M, SourceLoc diagLoc,
16261623
errorMessages.push_back(contentsOrErr.getError().message());
16271624

16281625
for (auto message : errorMessages)
1629-
M->getASTContext().Diags
1630-
.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file,
1631-
M->getName(), bystanderName, message, filePath);
1632-
return;
1626+
ctx.Diags.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file,
1627+
M->getName(), bystanderName, message, filePath);
1628+
return false;
16331629
}
16341630

16351631
auto contents = std::move(*contentsOrErr);
@@ -1638,6 +1634,8 @@ void OverlayFile::loadOverlayModuleNames(ModuleDecl *M, SourceLoc diagLoc,
16381634
auto moduleIdent = ctx.getIdentifier(module.name);
16391635
overlayModuleNames.push_back(moduleIdent);
16401636
}
1637+
1638+
return true;
16411639
}
16421640

16431641
//===----------------------------------------------------------------------===//

lib/AST/ModuleLoader.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,34 +97,51 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
9797

9898
auto &langOpts = module->getASTContext().LangOpts;
9999

100+
// This method constructs several paths to directories near the module and
101+
// scans them for .swiftoverlay files. These paths can be in various
102+
// directories and have a few different filenames at the end, but I'll
103+
// illustrate the path transformations by showing examples for a module
104+
// defined by a swiftinterface at:
105+
//
106+
// /usr/lib/swift/FooKit.swiftmodule/x86_64-apple-macos.swiftinterface
107+
108+
// dirPath = /usr/lib/swift/FooKit.swiftmodule
100109
SmallString<64> dirPath{file->getModuleDefiningPath()};
101-
102110
if (dirPath.empty())
103111
return;
112+
113+
// dirPath = /usr/lib/swift/
104114
path::remove_filename(dirPath);
105115

106-
// <parent-dir>/<module-name>.swiftcrossimport
116+
// dirPath = /usr/lib/swift/FooKit.swiftcrossimport
107117
path::append(dirPath, file->getExportedModuleName());
108118
path::replace_extension(dirPath, getExtension(TY_SwiftCrossImportDir));
119+
120+
// Search for swiftoverlays that apply to all platforms.
109121
if (!findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker))
110122
// If we diagnosed an error, or we didn't find the directory at all, don't
111123
// bother trying the target-specific directories.
112124
return;
113125

114-
// <parent-dir>/<module-name>.swiftcrossimport/<target-module-triple>
126+
// dirPath = /usr/lib/swift/FooKit.swiftcrossimport/x86_64-apple-macos
115127
auto moduleTriple = getTargetSpecificModuleTriple(langOpts.Target);
116128
path::append(dirPath, moduleTriple.str());
129+
130+
// Search for swiftoverlays specific to the target triple's platform.
117131
findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker);
118132

133+
// The rest of this handles target variant triples, which are only used for
134+
// certain MacCatalyst builds.
119135
if (!langOpts.TargetVariant)
120136
return;
121137

138+
// dirPath = /usr/lib/swift/FooKit.swiftcrossimport/x86_64-apple-ios-macabi
122139
path::remove_filename(dirPath);
123-
124-
// <parent-dir>/<module-name>.swiftcrossimport/<targetvariant-module-triple>
125140
auto moduleVariantTriple =
126141
getTargetSpecificModuleTriple(*langOpts.TargetVariant);
127142
path::append(dirPath, moduleVariantTriple.str());
143+
144+
// Search for swiftoverlays specific to the target variant's platform.
128145
findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker);
129146
}
130147

lib/Sema/NameBinding.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -594,8 +594,9 @@ void UnboundImport::diagnoseInvalidAttr(DeclAttrKind attrKind,
594594
BoundImport::BoundImport(UnboundImport unbound, ImportedModuleDesc desc,
595595
ModuleDecl *module, bool needsScopeValidation)
596596
: unbound(unbound), desc(desc), module(module),
597-
needsScopeValidation(needsScopeValidation)
598-
{ }
597+
needsScopeValidation(needsScopeValidation) {
598+
assert(module && "Can't have an import bound to nothing");
599+
}
599600

600601
void NameBinder::finishImports(SmallVectorImpl<ImportedModuleDesc> &imports) {
601602
for (auto &unvalidated : unvalidatedImports) {
@@ -674,11 +675,6 @@ void BoundImport::validateScope(SourceFile &SF) {
674675
if (unbound.importKind.Item == ImportKind::Module || !needsScopeValidation)
675676
return;
676677

677-
// Per getTopLevelModule(), topLevelModule should only be nullptr if we are
678-
// importing a submodule, and we should never do a scoped import of a
679-
// submodule.
680-
// assert(topLevelModule && "scoped import of a submodule import?");
681-
682678
ASTContext &ctx = SF.getASTContext();
683679

684680
// If we're importing a specific decl, validate the import kind.
@@ -797,6 +793,21 @@ UnboundImport::UnboundImport(ASTContext &ctx,
797793
}
798794

799795
void NameBinder::crossImport(ModuleDecl *M, UnboundImport &I) {
796+
// FIXME: There is a fundamental problem with this find-as-we-go approach:
797+
// The '@_exported import'-ed modules in this module's other files should be
798+
// taken into account, but they haven't been bound yet, and binding them would
799+
// require cross-importing. Chicken, meet egg.
800+
//
801+
// The way to fix this is probably to restructure name binding so we first
802+
// bind all exported imports in all files, then bind all other imports in each
803+
// file. This may become simpler if we bind all ImportDecls before we start
804+
// computing cross-imports, but I haven't figured that part out yet.
805+
//
806+
// Fixing this is tracked within Apple by rdar://problem/59527118. I haven't
807+
// filed an SR because I plan to address it myself, but if this comment is
808+
// still here in April 2020 without an SR number, please file a Swift bug and
809+
// harass @brentdax to fill in the details.
810+
800811
if (!SF.shouldCrossImport())
801812
return;
802813

test/CrossImport/horrible.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import UnitaryGoose
1616
// expected-error@-1 {{cannot list cross-import overlays for 'UnitaryGoose': Not a directory}}
1717

1818
// FIXME: It might be better to diagnose these errors on HorribleGoose's import
19-
// decl, since they actually belong to HorribleGoose.
19+
// decl, since they actually belong to HorribleGoose. (SR-12223)
2020

2121
import FlockOfGoose
2222
// expected-error@-1 {{cannot load cross-import overlay for 'HorribleGoose' and 'FlockOfGoose': Is a directory}}

0 commit comments

Comments
 (0)