Skip to content

Commit 8070e8a

Browse files
committed
[NFC] Use AttributedImport in import resolution
Removes what amount to redundant definitions from UnboundImport.
1 parent c489fff commit 8070e8a

File tree

2 files changed

+123
-68
lines changed

2 files changed

+123
-68
lines changed

include/swift/AST/Import.h

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/Basic/OptionSet.h"
2525
#include "llvm/ADT/ArrayRef.h"
2626
#include "llvm/ADT/DenseMapInfo.h"
27+
#include "llvm/ADT/PointerIntPair.h"
2728
#include "llvm/ADT/SmallVector.h"
2829
#include "llvm/ADT/STLExtras.h"
2930
#include "llvm/ADT/StringRef.h"
@@ -50,6 +51,10 @@ enum class ImportKind : uint8_t {
5051
Func
5152
};
5253

54+
inline bool isScopedImportKind(ImportKind importKind) {
55+
return importKind != ImportKind::Module;
56+
}
57+
5358
/// Possible attributes for imports in source files.
5459
enum class ImportFlags {
5560
/// The imported module is exposed to anyone who imports the parent module.
@@ -156,9 +161,17 @@ namespace detail {
156161

157162
template<typename Subclass>
158163
class ImportPathBuilder {
159-
llvm::SmallVector<ImportPathElement, 4> scratch;
164+
using Scratch = llvm::SmallVector<ImportPathElement, 4>;
165+
Scratch scratch;
160166

161167
public:
168+
using value_type = Scratch::value_type;
169+
using reference = Scratch::reference;
170+
using iterator = Scratch::iterator;
171+
using const_iterator = Scratch::const_iterator;
172+
using difference_type = Scratch::difference_type;
173+
using size_type = Scratch::size_type;
174+
162175
Subclass get() const {
163176
return Subclass(scratch);
164177
}
@@ -390,18 +403,67 @@ class ImportPath : public detail::ImportPathBase<ImportPath> {
390403
/// including submodules, assuming the \c ImportDecl has the indicated
391404
/// \c importKind.
392405
Module getModulePath(ImportKind importKind) const {
393-
return getModulePath(importKind != ImportKind::Module);
406+
return getModulePath(isScopedImportKind(importKind));
394407
}
395408

396409
/// Extracts the portion of the \c ImportPath which represents a scope for the
397410
/// import, assuming the \c ImportDecl has the indicated \c importKind.
398411
Access getAccessPath(ImportKind importKind) const {
399-
return getAccessPath(importKind != ImportKind::Module);
412+
return getAccessPath(isScopedImportKind(importKind));
400413
}
401414
};
402415

403416
// MARK: - Abstractions of imports
404417

418+
/// Convenience struct to keep track of an import path and whether or not it
419+
/// is scoped.
420+
class UnloadedImportedModule {
421+
// This is basically an ArrayRef with a bit stolen from the pointer.
422+
// FIXME: Extract an ArrayRefIntPair type from this.
423+
llvm::PointerIntPair<ImportPath::Raw::iterator, 1, bool> dataAndIsScoped;
424+
ImportPath::Raw::size_type length;
425+
426+
ImportPath::Raw::iterator data() const {
427+
return dataAndIsScoped.getPointer();
428+
}
429+
430+
bool isScoped() const {
431+
return dataAndIsScoped.getInt();
432+
}
433+
434+
ImportPath::Raw getRaw() const {
435+
return ImportPath::Raw(data(), length);
436+
}
437+
438+
UnloadedImportedModule(ImportPath::Raw raw, bool isScoped)
439+
: dataAndIsScoped(raw.data(), isScoped), length(raw.size()) { }
440+
441+
public:
442+
UnloadedImportedModule(ImportPath importPath, bool isScoped)
443+
: UnloadedImportedModule(importPath.getRaw(), isScoped) { }
444+
445+
UnloadedImportedModule(ImportPath importPath, ImportKind importKind)
446+
: UnloadedImportedModule(importPath, isScopedImportKind(importKind)) { }
447+
448+
ImportPath getImportPath() const {
449+
return ImportPath(getRaw());
450+
}
451+
452+
ImportPath::Module getModulePath() const {
453+
return getImportPath().getModulePath(isScoped());
454+
}
455+
456+
ImportPath::Access getAccessPath() const {
457+
return getImportPath().getAccessPath(isScoped());
458+
}
459+
460+
friend bool operator==(const UnloadedImportedModule &lhs,
461+
const UnloadedImportedModule &rhs) {
462+
return (lhs.getRaw() == rhs.getRaw()) &&
463+
(lhs.isScoped() == rhs.isScoped());
464+
}
465+
};
466+
405467
/// Convenience struct to keep track of a module along with its access path.
406468
struct alignas(uint64_t) ImportedModule {
407469
/// The access path from an import: `import Foo.Bar` -> `Foo.Bar`.
@@ -472,8 +534,6 @@ struct AttributedImport {
472534
}
473535
};
474536

475-
using ImportedModuleDesc = AttributedImport<ImportedModule>;
476-
477537
// MARK: - Implicit imports
478538

479539
/// A module which has been implicitly imported.

lib/Sema/ImportResolution.cpp

Lines changed: 58 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -51,36 +51,17 @@ namespace {
5151
/// source, or it may represent a cross-import overlay that has been found and
5252
/// needs to be loaded.
5353
struct UnboundImport {
54+
/// Information about the import. Use this field, not \c getImportDecl(), to
55+
/// determine the behavior expected for this import.
56+
AttributedImport<UnloadedImportedModule> import;
57+
5458
/// The source location to use when diagnosing errors for this import.
5559
SourceLoc importLoc;
5660

57-
/// The options for this import, such as "exported" or
58-
/// "implementation-only". Use this field, not \c attrs, to determine the
59-
/// behavior expected for this import.
60-
ImportOptions options;
61-
62-
/// If \c options includes \c PrivateImport, the filename we should import
63-
/// private declarations from.
64-
StringRef sourceFileArg;
65-
66-
/// The module names being imported. There will usually be just one for the
67-
/// top-level module, but a submodule import will have more.
68-
ImportPath::Module modulePath;
69-
70-
/// If this is a scoped import, the names of the declaration being imported;
71-
/// otherwise empty. (Currently the compiler doesn't support nested scoped
72-
/// imports, so there should always be zero or one elements, but
73-
/// \c ImportPath::Access is the common currency type for this.)
74-
ImportPath::Access accessPath;
75-
76-
// Names of explicitly imported SPI groups via @_spi.
77-
ArrayRef<Identifier> spiGroups;
78-
7961
/// If this UnboundImport directly represents an ImportDecl, contains the
8062
/// ImportDecl it represents. This should only be used for diagnostics and
8163
/// for updating the AST; if you want to read information about the import,
82-
/// get it from the other fields in \c UnboundImport rather than from the
83-
/// \c ImportDecl.
64+
/// get it from the \c import field rather than from the \c ImportDecl.
8465
///
8566
/// If this UnboundImport represents a cross-import, contains the declaring
8667
/// module's \c ModuleDecl.
@@ -137,8 +118,8 @@ struct UnboundImport {
137118
/// UnboundImport.
138119
AttributedImport<ImportedModule>
139120
makeAttributedImport(ModuleDecl *module) const {
140-
return { ImportedModule{ accessPath, module },
141-
options, sourceFileArg, spiGroups };
121+
return { ImportedModule{ import.module.getAccessPath(), module },
122+
import.options, import.sourceFileArg, import.spiGroups };
142123
}
143124

144125
private:
@@ -326,7 +307,7 @@ void ImportResolver::bindImport(UnboundImport &&I) {
326307
return;
327308
}
328309

329-
ModuleDecl *M = getModule(I.modulePath);
310+
ModuleDecl *M = getModule(I.import.module.getModulePath());
330311
if (!I.checkModuleLoaded(M, SF)) {
331312
// Can't process further. checkModuleLoaded() will have diagnosed this.
332313
if (ID)
@@ -392,11 +373,11 @@ ImportResolver::getModule(ImportPath::Module modulePath) {
392373

393374
NullablePtr<ModuleDecl>
394375
UnboundImport::getTopLevelModule(ModuleDecl *M, SourceFile &SF) {
395-
if (modulePath.size() == 1)
376+
if (import.module.getModulePath().size() == 1)
396377
return M;
397378

398379
// If we imported a submodule, import the top-level module as well.
399-
Identifier topLevelName = modulePath.front().Item;
380+
Identifier topLevelName = import.module.getModulePath().front().Item;
400381
ModuleDecl *topLevelModule = SF.getASTContext().getLoadedModule(topLevelName);
401382

402383
if (!topLevelModule) {
@@ -496,39 +477,40 @@ ModuleImplicitImportsRequest::evaluate(Evaluator &evaluator,
496477

497478
/// Create an UnboundImport for a user-written import declaration.
498479
UnboundImport::UnboundImport(ImportDecl *ID)
499-
: importLoc(ID->getLoc()), options(), sourceFileArg(),
500-
modulePath(ID->getModulePath()), accessPath(ID->getAccessPath()),
501-
importOrUnderlyingModuleDecl(ID)
480+
: import(UnloadedImportedModule(ID->getImportPath(), ID->getImportKind()),
481+
{}),
482+
importLoc(ID->getLoc()), importOrUnderlyingModuleDecl(ID)
502483
{
503484
if (ID->isExported())
504-
options |= ImportFlags::Exported;
485+
import.options |= ImportFlags::Exported;
505486

506487
if (ID->getAttrs().hasAttribute<TestableAttr>())
507-
options |= ImportFlags::Testable;
488+
import.options |= ImportFlags::Testable;
508489

509490
if (ID->getAttrs().hasAttribute<ImplementationOnlyAttr>())
510-
options |= ImportFlags::ImplementationOnly;
491+
import.options |= ImportFlags::ImplementationOnly;
511492

512493
if (auto *privateImportAttr =
513494
ID->getAttrs().getAttribute<PrivateImportAttr>()) {
514-
options |= ImportFlags::PrivateImport;
515-
sourceFileArg = privateImportAttr->getSourceFile();
495+
import.options |= ImportFlags::PrivateImport;
496+
import.sourceFileArg = privateImportAttr->getSourceFile();
516497
}
517498

518499
SmallVector<Identifier, 4> spiGroups;
519500
for (auto attr : ID->getAttrs().getAttributes<SPIAccessControlAttr>()) {
520-
options |= ImportFlags::SPIAccessControl;
501+
import.options |= ImportFlags::SPIAccessControl;
521502
auto attrSPIs = attr->getSPIGroups();
522503
spiGroups.append(attrSPIs.begin(), attrSPIs.end());
523504
}
524-
this->spiGroups = ID->getASTContext().AllocateCopy(spiGroups);
505+
import.spiGroups = ID->getASTContext().AllocateCopy(spiGroups);
525506
}
526507

527508
bool UnboundImport::checkNotTautological(const SourceFile &SF) {
528509
// Exit early if this is not a self-import.
510+
auto modulePath = import.module.getModulePath();
529511
if (modulePath.front().Item != SF.getParentModule()->getName() ||
530512
// Overlays use an @_exported self-import to load their clang module.
531-
options.contains(ImportFlags::Exported) ||
513+
import.options.contains(ImportFlags::Exported) ||
532514
// Imports of your own submodules are allowed in cross-language libraries.
533515
modulePath.size() != 1 ||
534516
// SIL files self-import to get decls from the rest of the module.
@@ -555,7 +537,8 @@ bool UnboundImport::checkModuleLoaded(ModuleDecl *M, SourceFile &SF) {
555537
ASTContext &ctx = SF.getASTContext();
556538

557539
SmallString<64> modulePathStr;
558-
llvm::interleave(modulePath, [&](ImportPath::Element elem) {
540+
llvm::interleave(import.module.getModulePath(),
541+
[&](ImportPath::Element elem) {
559542
modulePathStr += elem.Item.str();
560543
},
561544
[&] { modulePathStr += "."; });
@@ -599,24 +582,24 @@ void UnboundImport::validatePrivate(ModuleDecl *topLevelModule) {
599582
assert(topLevelModule);
600583
ASTContext &ctx = topLevelModule->getASTContext();
601584

602-
if (!options.contains(ImportFlags::PrivateImport))
585+
if (!import.options.contains(ImportFlags::PrivateImport))
603586
return;
604587

605588
if (topLevelModule->arePrivateImportsEnabled())
606589
return;
607590

608591
diagnoseInvalidAttr(DAK_PrivateImport, ctx.Diags,
609592
diag::module_not_compiled_for_private_import);
610-
sourceFileArg = StringRef();
593+
import.sourceFileArg = StringRef();
611594
}
612595

613596
void UnboundImport::validateImplementationOnly(ASTContext &ctx) {
614-
if (!options.contains(ImportFlags::ImplementationOnly) ||
615-
!options.contains(ImportFlags::Exported))
597+
if (!import.options.contains(ImportFlags::ImplementationOnly) ||
598+
!import.options.contains(ImportFlags::Exported))
616599
return;
617600

618601
// Remove one flag to maintain the invariant.
619-
options -= ImportFlags::ImplementationOnly;
602+
import.options -= ImportFlags::ImplementationOnly;
620603

621604
diagnoseInvalidAttr(DAK_ImplementationOnly, ctx.Diags,
622605
diag::import_implementation_cannot_be_exported);
@@ -626,7 +609,7 @@ void UnboundImport::validateTestable(ModuleDecl *topLevelModule) {
626609
assert(topLevelModule);
627610
ASTContext &ctx = topLevelModule->getASTContext();
628611

629-
if (!options.contains(ImportFlags::Testable) ||
612+
if (!import.options.contains(ImportFlags::Testable) ||
630613
topLevelModule->isTestingEnabled() ||
631614
topLevelModule->isNonSwiftModule() ||
632615
!ctx.LangOpts.EnableTestableAttrRequiresTestableModule)
@@ -637,7 +620,7 @@ void UnboundImport::validateTestable(ModuleDecl *topLevelModule) {
637620

638621
void UnboundImport::validateResilience(NullablePtr<ModuleDecl> topLevelModule,
639622
SourceFile &SF) {
640-
if (options.contains(ImportFlags::ImplementationOnly))
623+
if (import.options.contains(ImportFlags::ImplementationOnly))
641624
return;
642625

643626
// Per getTopLevelModule(), we'll only get nullptr here for non-Swift modules,
@@ -650,7 +633,7 @@ void UnboundImport::validateResilience(NullablePtr<ModuleDecl> topLevelModule,
650633
return;
651634

652635
ASTContext &ctx = SF.getASTContext();
653-
ctx.Diags.diagnose(modulePath.front().Loc,
636+
ctx.Diags.diagnose(import.module.getModulePath().front().Loc,
654637
diag::module_not_compiled_with_library_evolution,
655638
topLevelModule.get()->getName(),
656639
SF.getParentModule()->getName());
@@ -661,8 +644,8 @@ void UnboundImport::validateResilience(NullablePtr<ModuleDecl> topLevelModule,
661644
void UnboundImport::diagnoseInvalidAttr(DeclAttrKind attrKind,
662645
DiagnosticEngine &diags,
663646
Diag<Identifier> diagID) {
664-
auto diag = diags.diagnose(modulePath.front().Loc, diagID,
665-
modulePath.front().Item);
647+
auto diag = diags.diagnose(import.module.getModulePath().front().Loc, diagID,
648+
import.module.getModulePath().front().Item);
666649

667650
auto *ID = getImportDecl().getPtrOrNull();
668651
if (!ID) return;
@@ -923,20 +906,32 @@ static bool canCrossImport(const AttributedImport<ImportedModule> &import) {
923906
return true;
924907
}
925908

909+
static UnloadedImportedModule makeUnimportedCrossImportOverlay(
910+
ASTContext &ctx,
911+
Identifier overlayName,
912+
const UnboundImport &base,
913+
const AttributedImport<ImportedModule> &declaringImport) {
914+
ImportPath::Builder
915+
builder(overlayName, base.import.module.getModulePath()[0].Loc);
916+
917+
// If the declaring import was scoped, inherit that scope in the overlay's
918+
// import.
919+
llvm::copy(declaringImport.module.accessPath, std::back_inserter(builder));
920+
921+
// Cross-imports are not backed by an ImportDecl, so we need to provide
922+
// our own storage for their module paths.
923+
return UnloadedImportedModule(builder.copyTo(ctx),
924+
/*isScoped=*/!declaringImport.module.accessPath.empty());
925+
}
926+
926927
/// Create an UnboundImport for a cross-import overlay.
927928
UnboundImport::UnboundImport(
928929
ASTContext &ctx, const UnboundImport &base, Identifier overlayName,
929930
const AttributedImport<ImportedModule> &declaringImport,
930931
const AttributedImport<ImportedModule> &bystandingImport)
931-
: importLoc(base.importLoc), options(), sourceFileArg(),
932-
// Cross-imports are not backed by an ImportDecl, so we need to provide
933-
// our own storage for their module paths.
934-
modulePath(
935-
ImportPath::Module::Builder(overlayName, base.modulePath[0].Loc)
936-
.copyTo(ctx)),
937-
// If the declaring import was scoped, inherit that scope in the
938-
// overlay's import.
939-
accessPath(declaringImport.module.accessPath),
932+
: import(makeUnimportedCrossImportOverlay(ctx, overlayName, base,
933+
declaringImport), {}),
934+
importLoc(base.importLoc),
940935
importOrUnderlyingModuleDecl(declaringImport.module.importedModule)
941936
{
942937
// A cross-import is never private or testable, and never comes from a private
@@ -950,13 +945,13 @@ UnboundImport::UnboundImport(
950945
// If both are exported, the cross-import is exported.
951946
if (declaringOptions.contains(ImportFlags::Exported) &&
952947
bystandingOptions.contains(ImportFlags::Exported))
953-
options |= ImportFlags::Exported;
948+
import.options |= ImportFlags::Exported;
954949

955950
// If either are implementation-only, the cross-import is
956951
// implementation-only.
957952
if (declaringOptions.contains(ImportFlags::ImplementationOnly) ||
958953
bystandingOptions.contains(ImportFlags::ImplementationOnly))
959-
options |= ImportFlags::ImplementationOnly;
954+
import.options |= ImportFlags::ImplementationOnly;
960955
}
961956

962957
void ImportResolver::crossImport(ModuleDecl *M, UnboundImport &I) {
@@ -1107,7 +1102,7 @@ void ImportResolver::findCrossImports(
11071102
name);
11081103

11091104
LLVM_DEBUG({
1110-
auto &crossImportOptions = unboundImports.back().options;
1105+
auto &crossImportOptions = unboundImports.back().import.options;
11111106
llvm::dbgs() << " ";
11121107
if (crossImportOptions.contains(ImportFlags::Exported))
11131108
llvm::dbgs() << "@_exported ";

0 commit comments

Comments
 (0)