Skip to content

Commit 9adaddc

Browse files
committed
[NFC] Additional readability improvements
Courtesy of Varun.
1 parent 014bb1c commit 9adaddc

File tree

2 files changed

+128
-52
lines changed

2 files changed

+128
-52
lines changed

lib/AST/Module.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,11 +1470,14 @@ class OverlayFile {
14701470
/// The list of module names; empty if loading failed.
14711471
llvm::TinyPtrVector<Identifier> overlayModuleNames;
14721472

1473-
enum class State { pending, loaded, failed };
1474-
State state = State::pending;
1473+
enum class State { Pending, Loaded, Failed };
1474+
State state = State::Pending;
14751475

14761476
/// Actually loads the overlay module name list. This should mutate
14771477
/// \c overlayModuleNames, but not \c filePath.
1478+
///
1479+
/// \returns \c true on success, \c false on failure. Diagnoses any failures
1480+
/// before returning.
14781481
bool loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
14791482
Identifier bystandingModule);
14801483

@@ -1486,7 +1489,10 @@ class OverlayFile {
14861489
return ctx.Allocate(bytes, alignment);
14871490
}
14881491

1489-
OverlayFile(StringRef filePath) : filePath(filePath) { }
1492+
OverlayFile(StringRef filePath)
1493+
: filePath(filePath) {
1494+
assert(!filePath.empty());
1495+
}
14901496

14911497
/// Returns the list of additional modules that should be imported if both
14921498
/// the primary and secondary modules have been imported. This may load a
@@ -1498,9 +1504,9 @@ class OverlayFile {
14981504
ArrayRef<Identifier> getOverlayModuleNames(const ModuleDecl *M,
14991505
SourceLoc diagLoc,
15001506
Identifier bystandingModule) {
1501-
if (state == State::pending) {
1507+
if (state == State::Pending) {
15021508
state = loadOverlayModuleNames(M, diagLoc, bystandingModule)
1503-
? State::loaded : State::failed;
1509+
? State::Loaded : State::Failed;
15041510
}
15051511
return overlayModuleNames;
15061512
}
@@ -1602,8 +1608,6 @@ OverlayFileContents::load(std::unique_ptr<llvm::MemoryBuffer> input,
16021608
bool
16031609
OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
16041610
Identifier bystanderName) {
1605-
assert(!filePath.empty());
1606-
16071611
auto &ctx = M->getASTContext();
16081612
llvm::vfs::FileSystem &fs = *ctx.SourceMgr.getFileSystem();
16091613

lib/Sema/NameBinding.cpp

Lines changed: 117 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,36 @@ namespace {
5555
/// source, or it may represent a cross-import overlay that has been found and
5656
/// needs to be loaded.
5757
struct UnboundImport {
58+
/// The source location to use when diagnosing errors for this import.
59+
SourceLoc importLoc;
60+
61+
/// The options for this import, such as "exported" or
62+
/// "implementation-only". Use this field, not \c attrs, to determine the
63+
/// behavior expected for this import.
64+
ImportOptions options;
65+
66+
/// If \c options includes \c PrivateImport, the filename we should import
67+
/// private declarations from.
68+
StringRef privateImportFileName;
69+
70+
/// The kind of declaration expected for a scoped import, or \c Module if
71+
/// the import is not scoped.
72+
Located<ImportKind> importKind;
73+
74+
/// The module names being imported. There will usually be just one for the
75+
/// top-level module, but a submodule import will have more.
76+
ModuleDecl::AccessPathTy modulePath;
77+
78+
/// If this is a scoped import, the names of the declaration being imported;
79+
/// otherwise empty. (Currently the compiler doesn't support nested scoped
80+
/// imports, so there should always be zero or one elements, but
81+
/// \c AccessPathTy is the common currency type for this.)
82+
ModuleDecl::AccessPathTy declPath;
83+
84+
//
85+
// Set only on UnboundImports that represent physical ImportDecls:
86+
//
87+
5888
/// If this UnboundImport directly represents an ImportDecl, the ImportDecl
5989
/// it represents.
6090
///
@@ -63,14 +93,19 @@ namespace {
6393
/// the other member variables.
6494
NullablePtr<ImportDecl> ID;
6595

66-
SourceLoc importLoc;
67-
ImportOptions options;
68-
StringRef privateImportFileName;
69-
Located<ImportKind> importKind;
70-
ModuleDecl::AccessPathTy modulePath;
71-
ModuleDecl::AccessPathTy declPath;
72-
96+
/// If this UnboundImport directly represents an ImportDecl, the attributes
97+
/// of that ImportDecl.
98+
///
99+
/// This property should only be used to improve diagnostics. Don't pull
100+
/// information about the import's attributes from this property; use
101+
/// \c options instead.
73102
NullablePtr<DeclAttributes> attrs;
103+
104+
//
105+
// Set only on UnboundImports that represent cross-import overlays:
106+
//
107+
108+
/// The module this cross-import overlay is overlaying.
74109
NullablePtr<ModuleDecl> underlyingModule;
75110

76111
/// Create an UnboundImport for a user-written import declaration.
@@ -82,16 +117,27 @@ namespace {
82117
const ImportedModuleDesc &declaringImport,
83118
const ImportedModuleDesc &bystandingImport);
84119

85-
/// Make sure the import is not a self-import.
120+
/// Diagnoses if the import would simply load the module \p SF already
121+
/// belongs to, with no actual effect.
122+
///
123+
/// Some apparent self-imports do actually load a different module; this
124+
/// method allows them.
86125
bool checkNotTautological(const SourceFile &SF);
87126

88127
/// Make sure the module actually loaded, and diagnose if it didn't.
89128
bool checkModuleLoaded(ModuleDecl *M, SourceFile &SF);
90129

91-
/// Find the top-level module for this module. If \p M is not a submodule,
92-
/// returns \p M. If it is a submodule, returns either the parent module of
93-
/// \p M or \c nullptr if the current module is the parent (which can happen
94-
/// in a mixed-language framework).
130+
/// Find the top-level module for this module; that is, if \p M is the
131+
/// module \c Foo.Bar.Baz, this finds \c Foo.
132+
///
133+
/// Specifically, this method returns:
134+
///
135+
/// \li \p M if \p M is a top-level module.
136+
/// \li \c nullptr if \p M is a submodule of \c SF's parent module. (This
137+
/// corner case can occur in mixed-source frameworks, where Swift code
138+
/// can import a Clang submodule of itself.)
139+
/// \li The top-level parent (i.e. ancestor with no parent) module above
140+
/// \p M otherwise.
95141
NullablePtr<ModuleDecl> getTopLevelModule(ModuleDecl *M, SourceFile &SF);
96142

97143
/// Diagnose any errors concerning the \c @_exported, \c @_implementationOnly,
@@ -121,21 +167,44 @@ namespace {
121167
};
122168

123169
/// Represents an import whose options have been checked and module has been
124-
/// loaded, but its scope (if any) has not been validated.
170+
/// loaded, but its scope (if it's a scoped import) has not been validated
171+
/// and it has not been added to \c SF.
125172
struct BoundImport {
173+
/// The \c UnboundImport we bound to produce this import. Used to avoid
174+
/// duplicating its fields.
126175
UnboundImport unbound;
176+
177+
/// The \c ImportedModuleDesc that should be added to the source file for
178+
/// this import.
127179
ImportedModuleDesc desc;
180+
181+
/// The module we bound \c unbound to.
128182
ModuleDecl *module;
129-
bool needsScopeValidation = false;
183+
184+
/// If \c true, another, more specific \c BoundImport will validate the same
185+
/// scope as this import, so validating this one is not necessary.
186+
bool scopeValidatedElsewhere = true;
130187

131188
BoundImport(UnboundImport unbound, ImportedModuleDesc desc,
132-
ModuleDecl *module, bool needsScopeValidation);
189+
ModuleDecl *module, bool scopeValidatedElsewhere);
133190

134191
/// Validate the scope of the import, if needed.
192+
///
193+
/// A "scoped import" is an import which only covers one particular
194+
/// declaration, such as:
195+
///
196+
/// import class Foundation.NSString
197+
///
198+
/// We validate the scope by making sure that the named declaration exists
199+
/// and is of the kind indicated by the keyword. This can't be done until we
200+
/// have bound all cross-import overlays, since a cross-import overlay could
201+
/// provide the declaration.
135202
void validateScope(SourceFile &SF);
136203
};
137204

138-
class NameBinder : public DeclVisitor<NameBinder> {
205+
class NameBinder final : public DeclVisitor<NameBinder> {
206+
friend DeclVisitor<NameBinder>;
207+
139208
SourceFile &SF;
140209
ASTContext &ctx;
141210

@@ -146,15 +215,15 @@ namespace {
146215
/// Imports which still need their scoped imports validated.
147216
SmallVector<BoundImport, 16> unvalidatedImports;
148217

149-
// crossImportableModules is usually relatively small (~hundreds max) and
150-
// keeping it in order is convenient, so we use a SmallSetVector for it.
151-
// visibleModules is much larger and we don't care about its order, so we
152-
// use a DenseSet instead.
153-
154218
/// All imported modules, including by re-exports, and including submodules.
155219
llvm::DenseSet<ImportedModuleDesc> visibleModules;
156220

157-
/// visibleModules but without the submoduless.
221+
/// \c visibleModules but without the submodules.
222+
///
223+
/// We use a \c SmallSetVector here because this doubles as the worklist for
224+
/// cross-importing, so we want to keep it in order; this is feasible
225+
/// because this set is usually fairly small, while \c visibleModules is
226+
/// often enormous.
158227
SmallSetVector<ImportedModuleDesc, 64> crossImportableModules;
159228

160229
/// The index of the next module in \c visibleModules that should be
@@ -166,6 +235,11 @@ namespace {
166235
: SF(SF), ctx(SF.getASTContext())
167236
{ }
168237

238+
/// Postprocess the imports this NameBinder has bound and collect them into
239+
/// \p imports.
240+
void finishImports(SmallVectorImpl<ImportedModuleDesc> &imports);
241+
242+
private:
169243
// Special behavior for these decls:
170244
void visitImportDecl(ImportDecl *ID);
171245
void visitPrecedenceGroupDecl(PrecedenceGroupDecl *group);
@@ -176,11 +250,6 @@ namespace {
176250
// Ignore other decls.
177251
void visitDecl(Decl *D) {}
178252

179-
/// Postprocess the imports this NameBinder has bound and collect them into
180-
/// a vector.
181-
void finishImports(SmallVectorImpl<ImportedModuleDesc> &imports);
182-
183-
protected:
184253
template<typename ...ArgTypes>
185254
InFlightDiagnostic diagnose(ArgTypes &&...Args) {
186255
return ctx.Diags.diagnose(std::forward<ArgTypes>(Args)...);
@@ -230,10 +299,14 @@ namespace {
230299
/// performNameBinding - Once parsing is complete, this walks the AST to
231300
/// resolve names and do other top-level validation.
232301
///
233-
/// At this point parsing has been performed, but we still have
234-
/// UnresolvedDeclRefExpr nodes for unresolved value names, and we may have
235-
/// unresolved type names as well. This handles import directives and forward
236-
/// references.
302+
/// Most names are actually bound by the type checker, but before we can
303+
/// type-check a source file, we need to make declarations imported from other
304+
/// modules available and build tables of the operators and precedecence groups
305+
/// declared in that file. Name binding processes top-level \c ImportDecl,
306+
/// \c OperatorDecl, and \c PrecedenceGroupDecl nodes to perform these tasks,
307+
/// along with related validation.
308+
///
309+
/// Name binding operates on a parsed but otherwise unvalidated AST.
237310
void swift::performNameBinding(SourceFile &SF) {
238311
FrontendStatsTracer tracer(SF.getASTContext().Stats, "Name binding");
239312

@@ -343,12 +416,12 @@ void NameBinder::bindImport(UnboundImport &&I) {
343416
if (topLevelModule && topLevelModule != M) {
344417
// If we have distinct submodule and top-level module, add both, disabling
345418
// the top-level module's scoped import validation.
346-
addImport(I, M, false);
347-
addImport(I, topLevelModule.get(), true);
419+
addImport(I, M, true);
420+
addImport(I, topLevelModule.get(), false);
348421
}
349422
else {
350423
// Add only the import itself.
351-
addImport(I, M, true);
424+
addImport(I, M, false);
352425
}
353426

354427
crossImport(M, I);
@@ -358,11 +431,11 @@ void NameBinder::bindImport(UnboundImport &&I) {
358431
}
359432

360433
void NameBinder::addImport(const UnboundImport &I, ModuleDecl *M,
361-
bool needsScopeValidation) {
434+
bool scopeValidatedElsewhere) {
362435
auto importDesc = I.makeDesc(M);
363436

364437
addVisibleModules(importDesc);
365-
unvalidatedImports.emplace_back(I, importDesc, M, needsScopeValidation);
438+
unvalidatedImports.emplace_back(I, importDesc, M, scopeValidatedElsewhere);
366439
}
367440

368441
//===----------------------------------------------------------------------===//
@@ -426,10 +499,10 @@ UnboundImport::getTopLevelModule(ModuleDecl *M, SourceFile &SF) {
426499

427500
/// Create an UnboundImport for a user-written import declaration.
428501
UnboundImport::UnboundImport(ImportDecl *ID)
429-
: ID(ID), importLoc(ID->getLoc()), options(), privateImportFileName(),
502+
: importLoc(ID->getLoc()), options(), privateImportFileName(),
430503
importKind(ID->getImportKind(), ID->getKindLoc()),
431504
modulePath(ID->getModulePath()), declPath(ID->getDeclPath()),
432-
attrs(&ID->getAttrs()), underlyingModule()
505+
ID(ID), attrs(&ID->getAttrs()), underlyingModule()
433506
{
434507
if (ID->isExported())
435508
options |= ImportFlags::Exported;
@@ -600,9 +673,9 @@ void UnboundImport::diagnoseInvalidAttr(DeclAttrKind attrKind,
600673
//===----------------------------------------------------------------------===//
601674

602675
BoundImport::BoundImport(UnboundImport unbound, ImportedModuleDesc desc,
603-
ModuleDecl *module, bool needsScopeValidation)
676+
ModuleDecl *module, bool scopeValidatedElsewhere)
604677
: unbound(unbound), desc(desc), module(module),
605-
needsScopeValidation(needsScopeValidation) {
678+
scopeValidatedElsewhere(scopeValidatedElsewhere) {
606679
assert(module && "Can't have an import bound to nothing");
607680
}
608681

@@ -680,7 +753,7 @@ static const char *getImportKindString(ImportKind kind) {
680753
}
681754

682755
void BoundImport::validateScope(SourceFile &SF) {
683-
if (unbound.importKind.Item == ImportKind::Module || !needsScopeValidation)
756+
if (unbound.importKind.Item == ImportKind::Module || scopeValidatedElsewhere)
684757
return;
685758

686759
ASTContext &ctx = SF.getASTContext();
@@ -767,15 +840,14 @@ UnboundImport::UnboundImport(ASTContext &ctx,
767840
const UnboundImport &base, Identifier overlayName,
768841
const ImportedModuleDesc &declaringImport,
769842
const ImportedModuleDesc &bystandingImport)
770-
: ID(nullptr), importLoc(base.importLoc), options(),
771-
privateImportFileName(), importKind({ ImportKind::Module, SourceLoc() }),
772-
modulePath(),
843+
: importLoc(base.importLoc), options(), privateImportFileName(),
844+
importKind({ ImportKind::Module, SourceLoc() }), modulePath(),
773845
// If the declaring import was scoped, inherit that scope in the
774846
// overlay's import. Note that we do *not* set importKind; this keeps
775847
// BoundImport::validateScope() from unnecessarily revalidating the
776848
// scope.
777849
declPath(declaringImport.module.first),
778-
attrs(nullptr), underlyingModule(declaringImport.module.second)
850+
ID(nullptr), attrs(nullptr), underlyingModule(declaringImport.module.second)
779851
{
780852
modulePath = ctx.AllocateCopy(
781853
ModuleDecl::AccessPathTy( { overlayName, base.modulePath[0].Loc }));

0 commit comments

Comments
 (0)