diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def index 6bbe1a459ceb5..d4ebede4903ec 100644 --- a/include/swift/AST/ASTTypeIDZone.def +++ b/include/swift/AST/ASTTypeIDZone.def @@ -22,7 +22,7 @@ SWIFT_TYPEID(BodyInitKindAndExpr) SWIFT_TYPEID(CtorInitializerKind) SWIFT_TYPEID(FunctionBuilderBodyPreCheck) SWIFT_TYPEID(GenericSignature) -SWIFT_TYPEID(ImplicitImport) +SWIFT_TYPEID(ImplicitImportList) SWIFT_TYPEID(ImplicitMemberAction) SWIFT_TYPEID(ParamSpecifier) SWIFT_TYPEID(PropertyWrapperBackingPropertyInfo) diff --git a/include/swift/AST/ASTTypeIDs.h b/include/swift/AST/ASTTypeIDs.h index 8bbb7366f965d..94323e9353913 100644 --- a/include/swift/AST/ASTTypeIDs.h +++ b/include/swift/AST/ASTTypeIDs.h @@ -42,7 +42,7 @@ class GenericTypeParamType; class InfixOperatorDecl; class IterableDeclContext; class ModuleDecl; -struct ImplicitImport; +struct ImplicitImportList; class NamedPattern; class NominalTypeDecl; class OperatorDecl; diff --git a/include/swift/AST/FileUnit.h b/include/swift/AST/FileUnit.h index ec8ea98f22b88..16d6e46d749dd 100644 --- a/include/swift/AST/FileUnit.h +++ b/include/swift/AST/FileUnit.h @@ -235,12 +235,12 @@ class FileUnit : public DeclContext { /// \p filter controls whether public, private, or any imports are included /// in this list. virtual void - getImportedModules(SmallVectorImpl &imports, + getImportedModules(SmallVectorImpl &imports, ModuleDecl::ImportFilter filter) const {} /// \see ModuleDecl::getImportedModulesForLookup virtual void getImportedModulesForLookup( - SmallVectorImpl &imports) const { + SmallVectorImpl &imports) const { return getImportedModules(imports, ModuleDecl::ImportFilterKind::Exported); } diff --git a/include/swift/AST/Import.h b/include/swift/AST/Import.h index 55f5bd642f0f5..b6a1f7a2d352a 100644 --- a/include/swift/AST/Import.h +++ b/include/swift/AST/Import.h @@ -21,14 +21,21 @@ #include "swift/AST/Identifier.h" #include "swift/Basic/Located.h" +#include "swift/Basic/OptionSet.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" #include namespace swift { class ASTContext; +class ModuleDecl; + +// MARK: - Fundamental import enums /// Describes what kind of name is being imported. /// @@ -45,6 +52,43 @@ enum class ImportKind : uint8_t { Func }; +inline bool isScopedImportKind(ImportKind importKind) { + return importKind != ImportKind::Module; +} + +/// Possible attributes for imports in source files. +enum class ImportFlags { + /// The imported module is exposed to anyone who imports the parent module. + Exported = 0x1, + + /// This source file has access to testable declarations in the imported + /// module. + Testable = 0x2, + + /// This source file has access to private declarations in the imported + /// module. + PrivateImport = 0x4, + + /// The imported module is an implementation detail of this file and should + /// not be required to be present if the main module is ever imported + /// elsewhere. + /// + /// Mutually exclusive with Exported. + ImplementationOnly = 0x8, + + /// The module is imported to have access to named SPIs which is an + /// implementation detail of this file. + SPIAccessControl = 0x10, + + /// Used for DenseMap. + Reserved = 0x80 +}; + +/// \see ImportFlags +using ImportOptions = OptionSet; + +// MARK: - Import Paths + namespace detail { using ImportPathElement = Located; using ImportPathRaw = llvm::ArrayRef; @@ -108,6 +152,17 @@ namespace detail { if (empty()) return SourceRange(); return SourceRange(raw.front().Loc, raw.back().Loc); } + + void print(llvm::raw_ostream &os) const { + llvm::interleave(*this, + [&](Element elem) { os << elem.Item.str(); }, + [&]() { os << "."; }); + } + + void getString(SmallVectorImpl &modulePathStr) const { + llvm::raw_svector_ostream os(modulePathStr); + print(os); + } }; // These shims avoid circularity between ASTContext.h and Import.h. @@ -118,9 +173,17 @@ namespace detail { template class ImportPathBuilder { - llvm::SmallVector scratch; + using Scratch = llvm::SmallVector; + Scratch scratch; public: + using value_type = Scratch::value_type; + using reference = Scratch::reference; + using iterator = Scratch::iterator; + using const_iterator = Scratch::const_iterator; + using difference_type = Scratch::difference_type; + using size_type = Scratch::size_type; + Subclass get() const { return Subclass(scratch); } @@ -352,16 +415,326 @@ class ImportPath : public detail::ImportPathBase { /// including submodules, assuming the \c ImportDecl has the indicated /// \c importKind. Module getModulePath(ImportKind importKind) const { - return getModulePath(importKind != ImportKind::Module); + return getModulePath(isScopedImportKind(importKind)); } /// Extracts the portion of the \c ImportPath which represents a scope for the /// import, assuming the \c ImportDecl has the indicated \c importKind. Access getAccessPath(ImportKind importKind) const { - return getAccessPath(importKind != ImportKind::Module); + return getAccessPath(isScopedImportKind(importKind)); + } +}; + +// MARK: - Abstractions of imports + +/// Convenience struct to keep track of an import path and whether or not it +/// is scoped. +class UnloadedImportedModule { + // This is basically an ArrayRef with a bit stolen from the pointer. + // FIXME: Extract an ArrayRefIntPair type from this. + llvm::PointerIntPair dataAndIsScoped; + ImportPath::Raw::size_type length; + + ImportPath::Raw::iterator data() const { + return dataAndIsScoped.getPointer(); + } + + bool isScoped() const { + return dataAndIsScoped.getInt(); + } + + ImportPath::Raw getRaw() const { + return ImportPath::Raw(data(), length); + } + + UnloadedImportedModule(ImportPath::Raw raw, bool isScoped) + : dataAndIsScoped(raw.data(), isScoped), length(raw.size()) { } + +public: + UnloadedImportedModule(ImportPath importPath, bool isScoped) + : UnloadedImportedModule(importPath.getRaw(), isScoped) { } + + UnloadedImportedModule(ImportPath importPath, ImportKind importKind) + : UnloadedImportedModule(importPath, isScopedImportKind(importKind)) { } + + ImportPath getImportPath() const { + return ImportPath(getRaw()); + } + + ImportPath::Module getModulePath() const { + return getImportPath().getModulePath(isScoped()); + } + + ImportPath::Access getAccessPath() const { + return getImportPath().getAccessPath(isScoped()); + } + + friend bool operator==(const UnloadedImportedModule &lhs, + const UnloadedImportedModule &rhs) { + return (lhs.getRaw() == rhs.getRaw()) && + (lhs.isScoped() == rhs.isScoped()); + } +}; + +/// Convenience struct to keep track of a module along with its access path. +struct alignas(uint64_t) ImportedModule { + /// The access path from an import: `import Foo.Bar` -> `Foo.Bar`. + ImportPath::Access accessPath; + /// The actual module corresponding to the import. + /// + /// Invariant: The pointer is non-null. + ModuleDecl *importedModule; + + ImportedModule(ImportPath::Access accessPath, + ModuleDecl *importedModule) + : accessPath(accessPath), importedModule(importedModule) { + assert(this->importedModule); + } + + explicit ImportedModule(ModuleDecl *importedModule) + : ImportedModule(ImportPath::Access(), importedModule) { } + + bool operator==(const ImportedModule &other) const { + return (this->importedModule == other.importedModule) && + (this->accessPath == other.accessPath); + } + + /// Uniques the items in \p imports, ignoring the source locations of the + /// access paths. + /// + /// The order of items in \p imports is \e not preserved. + static void removeDuplicates(SmallVectorImpl &imports); + + // Purely here to allow ImportedModule and UnloadedImportedModule to + // substitute into the same templates. + ImportPath::Access getAccessPath() const { return accessPath; } + + /// Arbitrarily orders ImportedModule records, for inclusion in sets and such. + class Order { + public: + bool operator()(const ImportedModule &lhs, + const ImportedModule &rhs) const { + if (lhs.importedModule != rhs.importedModule) + return std::less()(lhs.importedModule, + rhs.importedModule); + if (lhs.accessPath.getRaw().data() != rhs.accessPath.getRaw().data()) + return std::less()(lhs.accessPath.begin(), + rhs.accessPath.begin()); + return lhs.accessPath.size() < rhs.accessPath.size(); + } + }; +}; + +/// Augments a type representing an import to also include information about the +/// import's attributes. This is usually used with either \c ImportedModule or +/// \c UnloadedImportedModule. +template +struct AttributedImport { + /// Information about the module and access path being imported. + ModuleInfo module; + + /// Flags indicating which attributes of this import are present. + ImportOptions options; + + /// If this is a @_private import, the value of its 'sourceFile:' argument; + /// otherwise, empty string. + StringRef sourceFileArg; + + /// Names of explicitly imported SPI groups. + ArrayRef spiGroups; + + AttributedImport(ModuleInfo module, ImportOptions options = ImportOptions(), + StringRef filename = {}, ArrayRef spiGroups = {}) + : module(module), options(options), sourceFileArg(filename), + spiGroups(spiGroups) { + assert(!(options.contains(ImportFlags::Exported) && + options.contains(ImportFlags::ImplementationOnly)) || + options.contains(ImportFlags::Reserved)); + } + + template + AttributedImport(ModuleInfo module, AttributedImport other) + : AttributedImport(module, other.options, other.sourceFileArg, + other.spiGroups) { } + + friend bool operator==(const AttributedImport &lhs, + const AttributedImport &rhs) { + return lhs.module == rhs.module && + lhs.options.toRaw() == rhs.options.toRaw() && + lhs.sourceFileArg == rhs.sourceFileArg && + lhs.spiGroups == rhs.spiGroups; + } + + AttributedImport getLoaded(ModuleDecl *loadedModule) const { + return { ImportedModule(module.getAccessPath(), loadedModule), *this }; + } +}; + +void simple_display(llvm::raw_ostream &out, + const ImportedModule &import); + +void simple_display(llvm::raw_ostream &out, + const UnloadedImportedModule &import); + +// This is a quasi-implementation detail of the template version below. +void simple_display(llvm::raw_ostream &out, + const AttributedImport> &import); + +template +void simple_display(llvm::raw_ostream &out, + const AttributedImport &import) { + // Print the module. + simple_display(out, import.module); + + // Print the other details of the import, using the std::tuple<> + // specialization. + AttributedImport> importWithoutModule({}, import); + simple_display(out, importWithoutModule); +} + +// MARK: - Implicit imports + +/// The kind of stdlib that should be imported. +enum class ImplicitStdlibKind { + /// No standard library should be implicitly imported. + None, + + /// The Builtin module should be implicitly imported. + Builtin, + + /// The regular Swift standard library should be implicitly imported. + Stdlib +}; + +/// Represents unprocessed options for implicit imports. +struct ImplicitImportInfo { + /// The implicit stdlib to import. + ImplicitStdlibKind StdlibKind; + + /// Whether we should attempt to import an underlying Clang half of this + /// module. + bool ShouldImportUnderlyingModule; + + /// The bridging header path for this module, empty if there is none. + StringRef BridgingHeaderPath; + + /// The names of additional modules to be loaded and implicitly imported. + SmallVector, 4> + AdditionalUnloadedImports; + + /// An additional list of already-loaded modules which should be implicitly + /// imported. + SmallVector, 4> + AdditionalImports; + + ImplicitImportInfo() + : StdlibKind(ImplicitStdlibKind::None), + ShouldImportUnderlyingModule(false) {} +}; + +/// Contains names of and pointers to modules that must be implicitly imported. +struct ImplicitImportList { + ArrayRef> imports; + ArrayRef> unloadedImports; + + friend bool operator==(const ImplicitImportList &lhs, + const ImplicitImportList &rhs) { + return lhs.imports == rhs.imports + && lhs.unloadedImports == rhs.unloadedImports; + } +}; + +/// A list of modules to implicitly import. +void simple_display(llvm::raw_ostream &out, + const ImplicitImportList &importList); + +} + +// MARK: - DenseMapInfo + +namespace llvm { + +template<> +struct DenseMapInfo { + using ImportOptions = swift::ImportOptions; + + using UnsignedDMI = DenseMapInfo; + + static inline ImportOptions getEmptyKey() { + return ImportOptions(UnsignedDMI::getEmptyKey()); + } + static inline ImportOptions getTombstoneKey() { + return ImportOptions(UnsignedDMI::getTombstoneKey()); + } + static inline unsigned getHashValue(ImportOptions options) { + return UnsignedDMI::getHashValue(options.toRaw()); + } + static bool isEqual(ImportOptions a, ImportOptions b) { + return UnsignedDMI::isEqual(a.toRaw(), b.toRaw()); } }; +template <> +class DenseMapInfo { + using ImportedModule = swift::ImportedModule; + using ModuleDecl = swift::ModuleDecl; +public: + static ImportedModule getEmptyKey() { + return {{}, llvm::DenseMapInfo::getEmptyKey()}; + } + static ImportedModule getTombstoneKey() { + return {{}, llvm::DenseMapInfo::getTombstoneKey()}; + } + + static unsigned getHashValue(const ImportedModule &val) { + auto pair = std::make_pair(val.accessPath.size(), val.importedModule); + return llvm::DenseMapInfo::getHashValue(pair); + } + + static bool isEqual(const ImportedModule &lhs, + const ImportedModule &rhs) { + return lhs.importedModule == rhs.importedModule && + lhs.accessPath.isSameAs(rhs.accessPath); + } +}; + +template +struct DenseMapInfo> { + using AttributedImport = swift::AttributedImport; + + using ModuleInfoDMI = DenseMapInfo; + using ImportOptionsDMI = DenseMapInfo; + using StringRefDMI = DenseMapInfo; + // We can't include spiGroups in the hash because ArrayRef is not + // DenseMapInfo-able, but we do check that the spiGroups match in isEqual(). + + static inline AttributedImport getEmptyKey() { + return AttributedImport(ModuleInfoDMI::getEmptyKey(), + ImportOptionsDMI::getEmptyKey(), + StringRefDMI::getEmptyKey(), + {}); + } + static inline AttributedImport getTombstoneKey() { + return AttributedImport(ModuleInfoDMI::getTombstoneKey(), + ImportOptionsDMI::getTombstoneKey(), + StringRefDMI::getTombstoneKey(), + {}); + } + static inline unsigned getHashValue(const AttributedImport &import) { + return detail::combineHashValue( + ModuleInfoDMI::getHashValue(import.module), + detail::combineHashValue( + ImportOptionsDMI::getHashValue(import.options), + StringRefDMI::getHashValue(import.sourceFileArg))); + } + static bool isEqual(const AttributedImport &a, + const AttributedImport &b) { + return ModuleInfoDMI::isEqual(a.module, b.module) && + ImportOptionsDMI::isEqual(a.options, b.options) && + StringRefDMI::isEqual(a.sourceFileArg, b.sourceFileArg) && + a.spiGroups == b.spiGroups; + } +}; } #endif diff --git a/include/swift/AST/ImportCache.h b/include/swift/AST/ImportCache.h index e52e322c604a0..5334b5ddddd36 100644 --- a/include/swift/AST/ImportCache.h +++ b/include/swift/AST/ImportCache.h @@ -49,7 +49,7 @@ namespace namelookup { /// it was explicitly imported (or re-exported). class ImportSet final : public llvm::FoldingSetNode, - private llvm::TrailingObjects { + private llvm::TrailingObjects { friend TrailingObjects; friend class ImportCache; @@ -58,8 +58,8 @@ class ImportSet final : unsigned NumTransitiveImports; ImportSet(bool hasHeaderImportModule, - ArrayRef topLevelImports, - ArrayRef transitiveImports); + ArrayRef topLevelImports, + ArrayRef transitiveImports); ImportSet(const ImportSet &) = delete; void operator=(const ImportSet &) = delete; @@ -70,9 +70,9 @@ class ImportSet final : } static void Profile( llvm::FoldingSetNodeID &ID, - ArrayRef topLevelImports); + ArrayRef topLevelImports); - size_t numTrailingObjects(OverloadToken) const { + size_t numTrailingObjects(OverloadToken) const { return NumTopLevelImports + NumTransitiveImports; } @@ -83,24 +83,24 @@ class ImportSet final : return HasHeaderImportModule; } - ArrayRef getTopLevelImports() const { - return {getTrailingObjects(), + ArrayRef getTopLevelImports() const { + return {getTrailingObjects(), NumTopLevelImports}; } - ArrayRef getTransitiveImports() const { - return {getTrailingObjects() + + ArrayRef getTransitiveImports() const { + return {getTrailingObjects() + NumTopLevelImports, NumTransitiveImports}; } - ArrayRef getAllImports() const { - return {getTrailingObjects(), + ArrayRef getAllImports() const { + return {getTrailingObjects(), NumTopLevelImports + NumTransitiveImports}; } }; -class alignas(ModuleDecl::ImportedModule) ImportCache { +class alignas(ImportedModule) ImportCache { ImportCache(const ImportCache &) = delete; void operator=(const ImportCache &) = delete; @@ -121,7 +121,7 @@ class alignas(ModuleDecl::ImportedModule) ImportCache { SmallVectorImpl &results); ImportSet &getImportSet(ASTContext &ctx, - ArrayRef topLevelImports); + ArrayRef topLevelImports); public: ImportCache() {} @@ -154,7 +154,7 @@ class alignas(ModuleDecl::ImportedModule) ImportCache { } }; -ArrayRef getAllImports(const DeclContext *dc); +ArrayRef getAllImports(const DeclContext *dc); } // namespace namelookup diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 7717bc02cfee3..d9c6dc675b40d 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -56,7 +56,6 @@ namespace swift { class FuncDecl; class InfixOperatorDecl; class LinkLibrary; - struct ImplicitImport; class ModuleLoader; class NominalTypeDecl; class EnumElementDecl; @@ -154,42 +153,6 @@ enum class ResilienceStrategy : unsigned { Resilient }; -/// The kind of stdlib that should be imported. -enum class ImplicitStdlibKind { - /// No standard library should be implicitly imported. - None, - - /// The Builtin module should be implicitly imported. - Builtin, - - /// The regular Swift standard library should be implicitly imported. - Stdlib -}; - -struct ImplicitImportInfo { - /// The implicit stdlib to import. - ImplicitStdlibKind StdlibKind; - - /// Whether we should attempt to import an underlying Clang half of this - /// module. - bool ShouldImportUnderlyingModule; - - /// The bridging header path for this module, empty if there is none. - StringRef BridgingHeaderPath; - - /// The names of additional modules to be implicitly imported. - SmallVector ModuleNames; - - /// An additional list of already-loaded modules which should be implicitly - /// imported. - SmallVector, 4> - AdditionalModules; - - ImplicitImportInfo() - : StdlibKind(ImplicitStdlibKind::None), - ShouldImportUnderlyingModule(false) {} -}; - class OverlayFile; /// The minimum unit of compilation. @@ -203,42 +166,6 @@ class ModuleDecl : public DeclContext, public TypeDecl { friend class DirectPrecedenceGroupLookupRequest; public: - /// Convenience struct to keep track of a module along with its access path. - struct alignas(uint64_t) ImportedModule { - /// The access path from an import: `import Foo.Bar` -> `Foo.Bar`. - ImportPath::Access accessPath; - /// The actual module corresponding to the import. - /// - /// Invariant: The pointer is non-null. - ModuleDecl *importedModule; - - ImportedModule(ImportPath::Access accessPath, - ModuleDecl *importedModule) - : accessPath(accessPath), importedModule(importedModule) { - assert(this->importedModule); - } - - bool operator==(const ModuleDecl::ImportedModule &other) const { - return (this->importedModule == other.importedModule) && - (this->accessPath == other.accessPath); - } - }; - - /// Arbitrarily orders ImportedModule records, for inclusion in sets and such. - class OrderImportedModules { - public: - bool operator()(const ImportedModule &lhs, - const ImportedModule &rhs) const { - if (lhs.importedModule != rhs.importedModule) - return std::less()(lhs.importedModule, - rhs.importedModule); - if (lhs.accessPath.getRaw().data() != rhs.accessPath.getRaw().data()) - return std::less()(lhs.accessPath.begin(), - rhs.accessPath.begin()); - return lhs.accessPath.size() < rhs.accessPath.size(); - } - }; - /// Produces the components of a given module's full name in reverse order. /// /// For a Swift module, this will only ever have one component, but an @@ -350,7 +277,7 @@ class ModuleDecl : public DeclContext, public TypeDecl { /// Retrieve a list of modules that each file of this module implicitly /// imports. - ArrayRef getImplicitImports() const; + ImplicitImportList getImplicitImports() const; ArrayRef getFiles() { assert(!Files.empty() || failedToLoad()); @@ -715,12 +642,6 @@ class ModuleDecl : public DeclContext, public TypeDecl { /// This assumes that \p module was imported. bool isImportedImplementationOnly(const ModuleDecl *module) const; - /// Uniques the items in \p imports, ignoring the source locations of the - /// access paths. - /// - /// The order of items in \p imports is \e not preserved. - static void removeDuplicateImports(SmallVectorImpl &imports); - /// Finds all top-level decls of this module. /// /// This does a simple local lookup, not recursively looking through imports. @@ -887,29 +808,4 @@ inline SourceLoc extractNearestSourceLoc(const ModuleDecl *mod) { } // end namespace swift -namespace llvm { - template <> - class DenseMapInfo { - using ModuleDecl = swift::ModuleDecl; - public: - static ModuleDecl::ImportedModule getEmptyKey() { - return {{}, llvm::DenseMapInfo::getEmptyKey()}; - } - static ModuleDecl::ImportedModule getTombstoneKey() { - return {{}, llvm::DenseMapInfo::getTombstoneKey()}; - } - - static unsigned getHashValue(const ModuleDecl::ImportedModule &val) { - auto pair = std::make_pair(val.accessPath.size(), val.importedModule); - return llvm::DenseMapInfo::getHashValue(pair); - } - - static bool isEqual(const ModuleDecl::ImportedModule &lhs, - const ModuleDecl::ImportedModule &rhs) { - return lhs.importedModule == rhs.importedModule && - lhs.accessPath.isSameAs(rhs.accessPath); - } - }; -} - #endif diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 5eab3844b32d8..8d4af0907bf96 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -19,6 +19,7 @@ #define SWIFT_AST_MODULE_DEPENDENCIES_H #include "swift/Basic/LLVM.h" +#include "swift/AST/Import.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSet.h" @@ -330,6 +331,12 @@ class ModuleDependencies { void addModuleDependency(StringRef module, llvm::StringSet<> *alreadyAddedModules = nullptr); + /// Add a dependency on the given module, if it was not already in the set. + void addModuleDependency(ImportPath::Module module, + llvm::StringSet<> *alreadyAddedModules = nullptr) { + addModuleDependency(module.front().Item.str(), alreadyAddedModules); + } + /// Add all of the module dependencies for the imports in the given source /// file to the set of module dependencies. void addModuleDependencies(const SourceFile &sf, diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index 2939ffd079cd7..5679e5d5f76de 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -14,6 +14,7 @@ #define SWIFT_AST_SOURCEFILE_H #include "swift/AST/FileUnit.h" +#include "swift/AST/Import.h" #include "swift/AST/SynthesizedFileUnit.h" #include "swift/Basic/Debug.h" #include "llvm/ADT/SetVector.h" @@ -32,58 +33,6 @@ class SourceFile final : public FileUnit { friend class ParseSourceFileRequest; public: - /// Possible attributes for imports in source files. - enum class ImportFlags { - /// The imported module is exposed to anyone who imports the parent module. - Exported = 0x1, - - /// This source file has access to testable declarations in the imported - /// module. - Testable = 0x2, - - /// This source file has access to private declarations in the imported - /// module. - PrivateImport = 0x4, - - /// The imported module is an implementation detail of this file and should - /// not be required to be present if the main module is ever imported - /// elsewhere. - /// - /// Mutually exclusive with Exported. - ImplementationOnly = 0x8, - - // The module is imported to have access to named SPIs which is an - // implementation detail of this file. - SPIAccessControl = 0x10, - - /// Used for DenseMap. - Reserved = 0x80 - }; - - /// \see ImportFlags - using ImportOptions = OptionSet; - - struct ImportedModuleDesc { - ModuleDecl::ImportedModule module; - ImportOptions importOptions; - - // Filename for a @_private import. - StringRef filename; - - // Names of explicitly imported SPIs. - ArrayRef spiGroups; - - ImportedModuleDesc(ModuleDecl::ImportedModule module, ImportOptions options, - StringRef filename = {}, - ArrayRef spiGroups = {}) - : module(module), importOptions(options), filename(filename), - spiGroups(spiGroups) { - assert(!(importOptions.contains(ImportFlags::Exported) && - importOptions.contains(ImportFlags::ImplementationOnly)) || - importOptions.contains(ImportFlags::Reserved)); - } - }; - /// Flags that direct how the source file is parsed. enum class ParsingFlags : uint8_t { /// Whether to disable delayed parsing for nominal type, extension, and @@ -133,7 +82,7 @@ class SourceFile final : public FileUnit { /// This is the list of modules that are imported by this module. /// /// This is \c None until it is filled in by the import resolution phase. - Optional> Imports; + Optional>> Imports; /// A unique identifier representing this file; used to mark private decls /// within the file to keep them from conflicting with other files in the @@ -339,11 +288,13 @@ class SourceFile final : public FileUnit { ~SourceFile(); /// Retrieve an immutable view of the source file's imports. - ArrayRef getImports() const { return *Imports; } + ArrayRef> getImports() const { + return *Imports; + } /// Set the imports for this source file. This gets called by import /// resolution. - void setImports(ArrayRef imports); + void setImports(ArrayRef> imports); enum ImportQueryKind { /// Return the results for testable or private imports. @@ -447,7 +398,7 @@ class SourceFile final : public FileUnit { getOpaqueReturnTypeDecls(SmallVectorImpl &results) const override; virtual void - getImportedModules(SmallVectorImpl &imports, + getImportedModules(SmallVectorImpl &imports, ModuleDecl::ImportFilter filter) const override; virtual void @@ -660,60 +611,4 @@ inline void simple_display(llvm::raw_ostream &out, const SourceFile *SF) { } } // end namespace swift -namespace llvm { - -template<> -struct DenseMapInfo { - using ImportOptions = swift::SourceFile::ImportOptions; - - using UnsignedDMI = DenseMapInfo; - - static inline ImportOptions getEmptyKey() { - return ImportOptions(UnsignedDMI::getEmptyKey()); - } - static inline ImportOptions getTombstoneKey() { - return ImportOptions(UnsignedDMI::getTombstoneKey()); - } - static inline unsigned getHashValue(ImportOptions options) { - return UnsignedDMI::getHashValue(options.toRaw()); - } - static bool isEqual(ImportOptions a, ImportOptions b) { - return UnsignedDMI::isEqual(a.toRaw(), b.toRaw()); - } -}; - -template<> -struct DenseMapInfo { - using ImportedModuleDesc = swift::SourceFile::ImportedModuleDesc; - - using ImportedModuleDMI = DenseMapInfo; - using ImportOptionsDMI = DenseMapInfo; - using StringRefDMI = DenseMapInfo; - - static inline ImportedModuleDesc getEmptyKey() { - return ImportedModuleDesc(ImportedModuleDMI::getEmptyKey(), - ImportOptionsDMI::getEmptyKey(), - StringRefDMI::getEmptyKey()); - } - static inline ImportedModuleDesc getTombstoneKey() { - return ImportedModuleDesc(ImportedModuleDMI::getTombstoneKey(), - ImportOptionsDMI::getTombstoneKey(), - StringRefDMI::getTombstoneKey()); - } - static inline unsigned getHashValue(const ImportedModuleDesc &import) { - return detail::combineHashValue( - ImportedModuleDMI::getHashValue(import.module), - detail::combineHashValue( - ImportOptionsDMI::getHashValue(import.importOptions), - StringRefDMI::getHashValue(import.filename))); - } - static bool isEqual(const ImportedModuleDesc &a, - const ImportedModuleDesc &b) { - return ImportedModuleDMI::isEqual(a.module, b.module) && - ImportOptionsDMI::isEqual(a.importOptions, b.importOptions) && - StringRefDMI::isEqual(a.filename, b.filename); - } -}; -} - #endif diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 9546b7dfab229..4926c75477fac 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -2494,30 +2494,11 @@ class SimpleDidSetRequest } }; -/// A module which has been implicitly imported. -struct ImplicitImport { - using ImportOptions = SourceFile::ImportOptions; - - ModuleDecl *Module; - ImportOptions Options; - - ImplicitImport(ModuleDecl *module, ImportOptions opts = {}) - : Module(module), Options(opts) {} - - friend bool operator==(const ImplicitImport &lhs, - const ImplicitImport &rhs) { - return lhs.Module == rhs.Module && - lhs.Options.toRaw() == rhs.Options.toRaw(); - } -}; - -void simple_display(llvm::raw_ostream &out, const ImplicitImport &import); - /// Computes the loaded modules that should be implicitly imported by each file /// of a given module. class ModuleImplicitImportsRequest : public SimpleRequest(ModuleDecl *), + ImplicitImportList(ModuleDecl *), RequestFlags::Cached> { public: using SimpleRequest::SimpleRequest; @@ -2525,8 +2506,7 @@ class ModuleImplicitImportsRequest private: friend SimpleRequest; - ArrayRef - evaluate(Evaluator &evaluator, ModuleDecl *module) const; + ImplicitImportList evaluate(Evaluator &evaluator, ModuleDecl *module) const; public: // Cached. diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 7b3f269555979..446b8c1e1a39f 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -148,7 +148,7 @@ SWIFT_REQUEST(TypeChecker, ValidatePrecedenceGroupRequest, SWIFT_REQUEST(TypeChecker, MangleLocalTypeDeclRequest, std::string(const TypeDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, ModuleImplicitImportsRequest, - ArrayRef(ModuleDecl *), Cached, NoLocationInfo) + ImplicitImportList(ModuleDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, NamingPatternRequest, NamedPattern *(VarDecl *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, OpaqueReadOwnershipRequest, diff --git a/include/swift/Basic/NullablePtr.h b/include/swift/Basic/NullablePtr.h index 316cfbb46251f..75a81eb9a1924 100644 --- a/include/swift/Basic/NullablePtr.h +++ b/include/swift/Basic/NullablePtr.h @@ -20,6 +20,7 @@ #include #include #include +#include "llvm/Support/PointerLikeTypeTraits.h" namespace swift { /// NullablePtr pointer wrapper - NullablePtr is used for APIs where a @@ -81,4 +82,19 @@ class NullablePtr { } // end namespace swift +namespace llvm { +template struct PointerLikeTypeTraits; +template struct PointerLikeTypeTraits> { +public: + static inline void *getAsVoidPointer(swift::NullablePtr ptr) { + return static_cast(ptr.getPtrOrNull()); + } + static inline swift::NullablePtr getFromVoidPointer(void *ptr) { + return swift::NullablePtr(static_cast(ptr)); + } + enum { NumLowBitsAvailable = PointerLikeTypeTraits::NumLowBitsAvailable }; +}; + +} + #endif // SWIFT_BASIC_NULLABLEPTR_H diff --git a/include/swift/ClangImporter/ClangModule.h b/include/swift/ClangImporter/ClangModule.h index c79fb8c04ece4..6541f1fcacdce 100644 --- a/include/swift/ClangImporter/ClangModule.h +++ b/include/swift/ClangImporter/ClangModule.h @@ -36,7 +36,7 @@ class ClangModuleUnit final : public LoadedFile { ClangImporter::Implementation &owner; const clang::Module *clangModule; llvm::PointerIntPair overlayModule; - mutable Optional> importedModulesForLookup; + mutable Optional> importedModulesForLookup; /// The metadata of the underlying Clang module. clang::ASTSourceDescriptor ASTSourceDescriptor; @@ -92,11 +92,11 @@ class ClangModuleUnit final : public LoadedFile { virtual void getDisplayDecls(SmallVectorImpl &results) const override; virtual void - getImportedModules(SmallVectorImpl &imports, + getImportedModules(SmallVectorImpl &imports, ModuleDecl::ImportFilter filter) const override; virtual void getImportedModulesForLookup( - SmallVectorImpl &imports) const override; + SmallVectorImpl &imports) const override; virtual void collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override; diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index dc0dff3c449f2..66fdcc94afefd 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -34,7 +34,8 @@ class FrontendOptions { friend class ArgsToFrontendOptionsConverter; /// A list of arbitrary modules to import and make implicitly visible. - std::vector ImplicitImportModuleNames; + std::vector> + ImplicitImportModuleNames; public: FrontendInputsAndOutputs InputsAndOutputs; @@ -351,7 +352,8 @@ class FrontendOptions { /// Retrieves the list of arbitrary modules to import and make implicitly /// visible. - ArrayRef getImplicitImportModuleNames() const { + ArrayRef> + getImplicitImportModuleNames() const { return ImplicitImportModuleNames; } diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index fe6e53afe9c98..8c2a727c4947b 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -512,6 +512,9 @@ def enable_throw_without_try : Flag<["-"], "enable-throw-without-try">, def import_module : Separate<["-"], "import-module">, HelpText<"Implicitly import the specified module">; +def testable_import_module : Separate<["-"], "testable-import-module">, + HelpText<"Implicitly import the specified module with @testable">; + def print_stats : Flag<["-"], "print-stats">, HelpText<"Print various statistics">; diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index e0aa714fd3914..59e813857f324 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -414,7 +414,7 @@ class SerializedASTFile final : public LoadedFile { virtual void getDisplayDecls(SmallVectorImpl &results) const override; virtual void - getImportedModules(SmallVectorImpl &imports, + getImportedModules(SmallVectorImpl &imports, ModuleDecl::ImportFilter filter) const override; virtual void diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index aff01f211fce0..b466124e24034 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -620,11 +620,7 @@ namespace { OS << " kind=" << getImportKindString(ID->getImportKind()); OS << " '"; - llvm::interleave(ID->getImportPath(), - [&](const ImportPath::Element &Elem) { - OS << Elem.Item; - }, - [&] { OS << '.'; }); + ID->getImportPath().print(OS); OS << "')"; } diff --git a/lib/AST/ImportCache.cpp b/lib/AST/ImportCache.cpp index a9a893934b824..af6e922ba0773 100644 --- a/lib/AST/ImportCache.cpp +++ b/lib/AST/ImportCache.cpp @@ -26,19 +26,19 @@ using namespace swift; using namespace namelookup; ImportSet::ImportSet(bool hasHeaderImportModule, - ArrayRef topLevelImports, - ArrayRef transitiveImports) + ArrayRef topLevelImports, + ArrayRef transitiveImports) : HasHeaderImportModule(hasHeaderImportModule), NumTopLevelImports(topLevelImports.size()), NumTransitiveImports(transitiveImports.size()) { - auto buffer = getTrailingObjects(); + auto buffer = getTrailingObjects(); std::uninitialized_copy(topLevelImports.begin(), topLevelImports.end(), buffer); std::uninitialized_copy(transitiveImports.begin(), transitiveImports.end(), buffer + topLevelImports.size()); #ifndef NDEBUG - llvm::SmallDenseSet unique; + llvm::SmallDenseSet unique; for (auto import : topLevelImports) { auto result = unique.insert(import).second; assert(result && "Duplicate imports in import set"); @@ -52,7 +52,7 @@ ImportSet::ImportSet(bool hasHeaderImportModule, void ImportSet::Profile( llvm::FoldingSetNodeID &ID, - ArrayRef topLevelImports) { + ArrayRef topLevelImports) { ID.AddInteger(topLevelImports.size()); for (auto import : topLevelImports) { ID.AddInteger(import.accessPath.size()); @@ -63,9 +63,9 @@ void ImportSet::Profile( } } -static void collectExports(ModuleDecl::ImportedModule next, - SmallVectorImpl &stack) { - SmallVector exports; +static void collectExports(ImportedModule next, + SmallVectorImpl &stack) { + SmallVector exports; next.importedModule->getImportedModulesForLookup(exports); for (auto exported : exports) { if (next.accessPath.empty()) @@ -81,16 +81,16 @@ static void collectExports(ModuleDecl::ImportedModule next, ImportSet & ImportCache::getImportSet(ASTContext &ctx, - ArrayRef imports) { + ArrayRef imports) { bool hasHeaderImportModule = false; ModuleDecl *headerImportModule = nullptr; if (auto *loader = ctx.getClangModuleLoader()) headerImportModule = loader->getImportedHeaderModule(); - SmallVector topLevelImports; + SmallVector topLevelImports; - SmallVector transitiveImports; - llvm::SmallDenseSet visited; + SmallVector transitiveImports; + llvm::SmallDenseSet visited; for (auto next : imports) { if (!visited.insert(next).second) @@ -115,7 +115,7 @@ ImportCache::getImportSet(ASTContext &ctx, if (ctx.Stats) ++ctx.Stats->getFrontendCounters().ImportSetFoldMiss; - SmallVector stack; + SmallVector stack; for (auto next : topLevelImports) { collectExports(next, stack); } @@ -139,7 +139,7 @@ ImportCache::getImportSet(ASTContext &ctx, if (ImportSet *result = ImportSets.FindNodeOrInsertPos(ID, InsertPos)) return *result; - size_t bytes = ImportSet::totalSizeToAlloc(topLevelImports.size() + transitiveImports.size()); + size_t bytes = ImportSet::totalSizeToAlloc(topLevelImports.size() + transitiveImports.size()); void *mem = ctx.Allocate(bytes, alignof(ImportSet), AllocationArena::Permanent); auto *result = new (mem) ImportSet(hasHeaderImportModule, @@ -169,10 +169,9 @@ ImportSet &ImportCache::getImportSet(const DeclContext *dc) { if (ctx.Stats) ++ctx.Stats->getFrontendCounters().ImportSetCacheMiss; - SmallVector imports; + SmallVector imports; - imports.emplace_back( - ModuleDecl::ImportedModule{ImportPath::Access(), mod}); + imports.emplace_back(ImportPath::Access(), mod); if (file) { // Should include both SPI & non-SPI. @@ -254,11 +253,10 @@ ImportCache::getAllAccessPathsNotShadowedBy(const ModuleDecl *mod, if (ctx.Stats) ++ctx.Stats->getFrontendCounters().ModuleShadowCacheMiss; - SmallVector stack; - llvm::SmallDenseSet visited; + SmallVector stack; + llvm::SmallDenseSet visited; - stack.emplace_back( - ModuleDecl::ImportedModule{ImportPath::Access(), currentMod}); + stack.emplace_back(ImportPath::Access(), currentMod); if (auto *file = dyn_cast(dc)) { // Should include both SPI & non-SPI @@ -297,7 +295,7 @@ ImportCache::getAllAccessPathsNotShadowedBy(const ModuleDecl *mod, return result; }; -ArrayRef +ArrayRef swift::namelookup::getAllImports(const DeclContext *dc) { return dc->getASTContext().getImportCache().getImportSet(dc) .getAllImports(); diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 135efbd415b97..6095d2d8c0008 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -487,14 +487,13 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx, Bits.ModuleDecl.HasIncrementalInfo = 0; } -ArrayRef ModuleDecl::getImplicitImports() const { +ImplicitImportList ModuleDecl::getImplicitImports() const { auto &evaluator = getASTContext().evaluator; auto *mutableThis = const_cast(this); return evaluateOrDefault(evaluator, ModuleImplicitImportsRequest{mutableThis}, {}); } - void ModuleDecl::addFile(FileUnit &newFile) { // If this is a LoadedFile, make sure it loaded without error. assert(!(isa(newFile) && @@ -1175,7 +1174,7 @@ void ModuleDecl::getImportedModules(SmallVectorImpl &modules, } void -SourceFile::getImportedModules(SmallVectorImpl &modules, +SourceFile::getImportedModules(SmallVectorImpl &modules, ModuleDecl::ImportFilter filter) const { // FIXME: Ideally we should assert that the file has had its imports resolved // before calling this function. However unfortunately that can cause issues @@ -1191,14 +1190,14 @@ SourceFile::getImportedModules(SmallVectorImpl &modu for (auto desc : *Imports) { ModuleDecl::ImportFilter requiredFilter; - if (desc.importOptions.contains(ImportFlags::Exported)) + if (desc.options.contains(ImportFlags::Exported)) requiredFilter |= ModuleDecl::ImportFilterKind::Exported; - else if (desc.importOptions.contains(ImportFlags::ImplementationOnly)) + else if (desc.options.contains(ImportFlags::ImplementationOnly)) requiredFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; else requiredFilter |= ModuleDecl::ImportFilterKind::Default; - if (desc.importOptions.contains(ImportFlags::SPIAccessControl)) + if (desc.options.contains(ImportFlags::SPIAccessControl)) requiredFilter |= ModuleDecl::ImportFilterKind::SPIAccessControl; if (!separatelyImportedOverlays.lookup(desc.module.importedModule).empty()) @@ -1281,7 +1280,7 @@ ModuleDecl::ReverseFullNameIterator::printForward(raw_ostream &out, } void -ModuleDecl::removeDuplicateImports(SmallVectorImpl &imports) { +ImportedModule::removeDuplicates(SmallVectorImpl &imports) { std::sort(imports.begin(), imports.end(), [](const ImportedModule &lhs, const ImportedModule &rhs) -> bool { // Arbitrarily sort by name to get a deterministic order. @@ -1451,7 +1450,7 @@ void ModuleDecl::collectLinkLibraries(LinkLibraryCallback callback) const { void SourceFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const { llvm::SmallDenseSet visited; - SmallVector stack; + SmallVector stack; ModuleDecl::ImportFilter filter = { ModuleDecl::ImportFilterKind::Exported, @@ -1465,9 +1464,7 @@ SourceFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const topLevel->getImportedModules(stack, topLevelFilter); // Make sure the top-level module is first; we want pre-order-ish traversal. - auto topLevelModule = - ModuleDecl::ImportedModule{ImportPath::Access(), topLevel}; - stack.emplace_back(topLevelModule); + stack.emplace_back(ImportPath::Access(), topLevel); while (!stack.empty()) { auto next = stack.pop_back_val().importedModule; @@ -1685,8 +1682,8 @@ ModuleDecl::getDeclaringModuleAndBystander() { // Search the transitive set of imported @_exported modules to see if any have // this module as their overlay. SmallPtrSet seen; - SmallVector imported; - SmallVector furtherImported; + SmallVector imported; + SmallVector furtherImported; ModuleDecl *overlayModule = this; getImportedModules(imported, ModuleDecl::ImportFilterKind::Exported); @@ -1884,17 +1881,17 @@ void SourceFile::print(ASTPrinter &Printer, const PrintOptions &PO) { } } -void SourceFile::setImports(ArrayRef imports) { +void +SourceFile::setImports(ArrayRef> imports) { assert(!Imports && "Already computed imports"); Imports = getASTContext().AllocateCopy(imports); } bool HasImplementationOnlyImportsRequest::evaluate(Evaluator &evaluator, SourceFile *SF) const { - using ModuleDesc = SourceFile::ImportedModuleDesc; - return llvm::any_of(SF->getImports(), [](ModuleDesc desc) { - return desc.importOptions.contains( - SourceFile::ImportFlags::ImplementationOnly); + return llvm::any_of(SF->getImports(), + [](AttributedImport desc) { + return desc.options.contains(ImportFlags::ImplementationOnly); }); } @@ -1915,20 +1912,19 @@ bool SourceFile::hasTestableOrPrivateImport( // internal/public access only needs an import marked as @_private. The // filename does not need to match (and we don't serialize it for such // decls). - return std::any_of( - Imports->begin(), Imports->end(), - [module, queryKind](ImportedModuleDesc desc) -> bool { + return llvm::any_of(*Imports, + [module, queryKind](AttributedImport desc) -> bool { if (queryKind == ImportQueryKind::TestableAndPrivate) return desc.module.importedModule == module && - (desc.importOptions.contains(ImportFlags::PrivateImport) || - desc.importOptions.contains(ImportFlags::Testable)); + (desc.options.contains(ImportFlags::PrivateImport) || + desc.options.contains(ImportFlags::Testable)); else if (queryKind == ImportQueryKind::TestableOnly) return desc.module.importedModule == module && - desc.importOptions.contains(ImportFlags::Testable); + desc.options.contains(ImportFlags::Testable); else { assert(queryKind == ImportQueryKind::PrivateOnly); return desc.module.importedModule == module && - desc.importOptions.contains(ImportFlags::PrivateImport); + desc.options.contains(ImportFlags::PrivateImport); } }); case AccessLevel::Open: @@ -1958,13 +1954,12 @@ bool SourceFile::hasTestableOrPrivateImport( if (filename.empty()) return false; - return std::any_of(Imports->begin(), Imports->end(), - [module, filename](ImportedModuleDesc desc) -> bool { - return desc.module.importedModule == module && - desc.importOptions.contains( - ImportFlags::PrivateImport) && - desc.filename == filename; - }); + return llvm::any_of(*Imports, + [module, filename](AttributedImport desc) { + return desc.module.importedModule == module && + desc.options.contains(ImportFlags::PrivateImport) && + desc.sourceFileArg == filename; + }); } bool SourceFile::isImportedImplementationOnly(const ModuleDecl *module) const { @@ -1978,7 +1973,7 @@ bool SourceFile::isImportedImplementationOnly(const ModuleDecl *module) const { // Look at the imports of this source file. for (auto &desc : *Imports) { // Ignore implementation-only imports. - if (desc.importOptions.contains(ImportFlags::ImplementationOnly)) + if (desc.options.contains(ImportFlags::ImplementationOnly)) continue; // If the module is imported this way, it's not imported @@ -2001,7 +1996,7 @@ bool ModuleDecl::isImportedImplementationOnly(const ModuleDecl *module) const { ModuleDecl::ImportFilterKind::Default, ModuleDecl::ImportFilterKind::SPIAccessControl, ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay}; - SmallVector results; + SmallVector results; getImportedModules(results, filter); for (auto &desc : results) { @@ -2016,7 +2011,7 @@ void SourceFile::lookupImportedSPIGroups( const ModuleDecl *importedModule, llvm::SmallSetVector &spiGroups) const { for (auto &import : *Imports) { - if (import.importOptions.contains(ImportFlags::SPIAccessControl) && + if (import.options.contains(ImportFlags::SPIAccessControl) && importedModule == import.module.importedModule) { auto importedSpis = import.spiGroups; spiGroups.insert(importedSpis.begin(), importedSpis.end()); diff --git a/lib/AST/ModuleDependencies.cpp b/lib/AST/ModuleDependencies.cpp index 45821a23424a8..c6b2bfaac066a 100644 --- a/lib/AST/ModuleDependencies.cpp +++ b/lib/AST/ModuleDependencies.cpp @@ -62,8 +62,7 @@ void ModuleDependencies::addModuleDependencies( if (!importDecl) continue; - addModuleDependency(importDecl->getModulePath().front().Item.str(), - &alreadyAddedModules); + addModuleDependency(importDecl->getModulePath(), &alreadyAddedModules); } auto fileName = sf.getFilename(); diff --git a/lib/AST/ModuleNameLookup.cpp b/lib/AST/ModuleNameLookup.cpp index af29ee62144e3..16c9d96a87c8e 100644 --- a/lib/AST/ModuleNameLookup.cpp +++ b/lib/AST/ModuleNameLookup.cpp @@ -182,7 +182,7 @@ void ModuleNameLookup::lookupInModule( if (!canReturnEarly) { auto &imports = ctx.getImportCache().getImportSet(moduleOrFile); - auto visitImport = [&](ModuleDecl::ImportedModule import, + auto visitImport = [&](ImportedModule import, const DeclContext *moduleScopeContext) { if (import.accessPath.empty()) import.accessPath = accessPath; @@ -202,9 +202,7 @@ void ModuleNameLookup::lookupInModule( if (auto *loader = ctx.getClangModuleLoader()) { headerImportModule = loader->getImportedHeaderModule(); if (headerImportModule) { - ModuleDecl::ImportedModule import{ImportPath::Access(), - headerImportModule}; - visitImport(import, nullptr); + visitImport(ImportedModule(headerImportModule), nullptr); } } } diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index c448198233fec..b8ee1ff3f1c8c 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -290,8 +290,7 @@ static void recordShadowedDeclsAfterTypeMatch( auto file = dc->getParentSourceFile(); if (!file) return false; for (const auto &import : file->getImports()) { - if (import.importOptions.contains( - SourceFile::ImportFlags::PrivateImport) + if (import.options.contains(ImportFlags::PrivateImport) && import.module.importedModule == module && import.module.accessPath.matches(name)) return true; diff --git a/lib/AST/OperatorNameLookup.cpp b/lib/AST/OperatorNameLookup.cpp index b074fbf30f630..63e64547b4ef9 100644 --- a/lib/AST/OperatorNameLookup.cpp +++ b/lib/AST/OperatorNameLookup.cpp @@ -83,8 +83,7 @@ static TinyPtrVector lookupOperatorImpl( if (!visitedModules.insert(mod).second) continue; - bool isExported = - import.importOptions.contains(SourceFile::ImportFlags::Exported); + bool isExported = import.options.contains(ImportFlags::Exported); if (!includePrivate && !isExported) continue; diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index da08ab9057d25..fee1a29ea9d51 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -1392,9 +1392,62 @@ TypeCheckFunctionBodyRequest::readDependencySource( //----------------------------------------------------------------------------// void swift::simple_display(llvm::raw_ostream &out, - const ImplicitImport &import) { - out << "implicit import of "; - simple_display(out, import.Module); + const ImportedModule &module) { + out << "import of "; + if (!module.accessPath.empty()) { + module.accessPath.print(out); + out << " in "; + } + simple_display(out, module.importedModule); +} + +void swift::simple_display(llvm::raw_ostream &out, + const UnloadedImportedModule &module) { + out << "import of "; + if (!module.getAccessPath().empty()) { + module.getAccessPath().print(out); + out << " in "; + } + out << "unloaded "; + module.getModulePath().print(out); +} + +void swift::simple_display(llvm::raw_ostream &out, + const AttributedImport> &import) { + out << " ["; + + if (import.options.contains(ImportFlags::Exported)) + out << " exported"; + if (import.options.contains(ImportFlags::Testable)) + out << " testable"; + if (import.options.contains(ImportFlags::ImplementationOnly)) + out << " implementation-only"; + if (import.options.contains(ImportFlags::PrivateImport)) + out << " private(" << import.sourceFileArg << ")"; + + if (import.options.contains(ImportFlags::SPIAccessControl)) { + out << " spi("; + llvm::interleaveComma(import.spiGroups, out, [&out](Identifier name) { + simple_display(out, name); + }); + out << ")"; + } + + out << " ]"; +} + +void swift::simple_display(llvm::raw_ostream &out, + const ImplicitImportList &importList) { + llvm::interleaveComma(importList.imports, out, + [&](const auto &import) { + simple_display(out, import); + }); + if (!importList.imports.empty() && !importList.unloadedImports.empty()) + out << ", "; + llvm::interleaveComma(importList.unloadedImports, out, + [&](const auto &import) { + simple_display(out, import); + }); } //----------------------------------------------------------------------------// diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 0720569da9558..37ad1a8ce665e 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -3434,7 +3434,7 @@ ModuleDecl *ClangModuleUnit::getOverlayModule() const { } void ClangModuleUnit::getImportedModules( - SmallVectorImpl &imports, + SmallVectorImpl &imports, ModuleDecl::ImportFilter filter) const { // Bail out if we /only/ want ImplementationOnly imports; Clang modules never // have any of these. @@ -3505,7 +3505,7 @@ void ClangModuleUnit::getImportedModules( } void ClangModuleUnit::getImportedModulesForLookup( - SmallVectorImpl &imports) const { + SmallVectorImpl &imports) const { // Reuse our cached list of imports if we have one. if (importedModulesForLookup.hasValue()) { @@ -3530,7 +3530,7 @@ void ClangModuleUnit::getImportedModulesForLookup( } if (imported.empty()) { - importedModulesForLookup = ArrayRef(); + importedModulesForLookup = ArrayRef(); return; } diff --git a/lib/ClangImporter/DWARFImporter.cpp b/lib/ClangImporter/DWARFImporter.cpp index 79bb6eeea19e4..8b635d1ce5ed6 100644 --- a/lib/ClangImporter/DWARFImporter.cpp +++ b/lib/ClangImporter/DWARFImporter.cpp @@ -67,11 +67,11 @@ class DWARFModuleUnit final : public LoadedFile { getDisplayDecls(SmallVectorImpl &results) const override {} virtual void - getImportedModules(SmallVectorImpl &imports, + getImportedModules(SmallVectorImpl &imports, ModuleDecl::ImportFilter filter) const override {} virtual void getImportedModulesForLookup( - SmallVectorImpl &imports) const override {}; + SmallVectorImpl &imports) const override {}; virtual void collectLinkLibraries( ModuleDecl::LinkLibraryCallback callback) const override {}; diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 8634d26296f1c..43c131981211a 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -215,7 +215,8 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.DisableBuildingInterface = Args.hasArg(OPT_disable_building_interface); computeImportObjCHeaderOptions(); - computeImplicitImportModuleNames(); + computeImplicitImportModuleNames(OPT_import_module, /*isTestable=*/false); + computeImplicitImportModuleNames(OPT_testable_import_module, /*isTestable=*/true); computeLLVMArgs(); return false; @@ -586,16 +587,17 @@ void ArgsToFrontendOptionsConverter::computeImportObjCHeaderOptions() { Opts.SerializeBridgingHeader |= !Opts.InputsAndOutputs.hasPrimaryInputs(); } } -void ArgsToFrontendOptionsConverter::computeImplicitImportModuleNames() { +void ArgsToFrontendOptionsConverter:: +computeImplicitImportModuleNames(OptSpecifier id, bool isTestable) { using namespace options; - for (const Arg *A : Args.filtered(OPT_import_module)) { + for (const Arg *A : Args.filtered(id)) { auto *moduleStr = A->getValue(); if (!Lexer::isIdentifier(moduleStr)) { Diags.diagnose(SourceLoc(), diag::error_bad_module_name, moduleStr, /*suggestModuleNameFlag*/ false); continue; } - Opts.ImplicitImportModuleNames.push_back(moduleStr); + Opts.ImplicitImportModuleNames.emplace_back(moduleStr, isTestable); } } void ArgsToFrontendOptionsConverter::computeLLVMArgs() { diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.h b/lib/Frontend/ArgsToFrontendOptionsConverter.h index 6e20e3688a8fa..66d85512ff068 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.h +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.h @@ -40,7 +40,8 @@ class ArgsToFrontendOptionsConverter { bool computeMainAndSupplementaryOutputFilenames(); void computeDumpScopeMapLocations(); void computeHelpOptions(); - void computeImplicitImportModuleNames(); + void computeImplicitImportModuleNames(llvm::opt::OptSpecifier id, + bool isTestable); void computeImportObjCHeaderOptions(); void computeLLVMArgs(); void computePlaygroundOptions(); diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 8ca60ba422374..9601547de0193 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -740,11 +740,23 @@ ImplicitImportInfo CompilerInstance::getImplicitImportInfo() const { ImplicitImportInfo imports; imports.StdlibKind = Invocation.getImplicitStdlibKind(); - for (auto &moduleStr : frontendOpts.getImplicitImportModuleNames()) - imports.ModuleNames.push_back(Context->getIdentifier(moduleStr)); + auto pushImport = [&](StringRef moduleStr, + ImportOptions options = ImportOptions()) { + ImportPath::Builder importPath(Context->getIdentifier(moduleStr)); + UnloadedImportedModule import(importPath.copyTo(*Context), + /*isScoped=*/false); + imports.AdditionalUnloadedImports.emplace_back(import, options); + }; + + for (auto &moduleStrAndTestable : frontendOpts.getImplicitImportModuleNames()) { + pushImport(moduleStrAndTestable.first, + moduleStrAndTestable.second ? ImportFlags::Testable + : ImportOptions()); + } - if (Invocation.shouldImportSwiftONoneSupport()) - imports.ModuleNames.push_back(Context->getIdentifier(SWIFT_ONONE_SUPPORT)); + if (Invocation.shouldImportSwiftONoneSupport()) { + pushImport(SWIFT_ONONE_SUPPORT); + } imports.ShouldImportUnderlyingModule = frontendOpts.ImportUnderlyingModule; imports.BridgingHeaderPath = frontendOpts.ImplicitObjCHeaderPath; diff --git a/lib/Frontend/ModuleInterfaceSupport.cpp b/lib/Frontend/ModuleInterfaceSupport.cpp index 52eb640375d99..4c442fd32feec 100644 --- a/lib/Frontend/ModuleInterfaceSupport.cpp +++ b/lib/Frontend/ModuleInterfaceSupport.cpp @@ -46,8 +46,8 @@ version::Version swift::InterfaceFormatVersion({1, 0}); /// /// These come from declarations like `import class FooKit.MainFooController`. static void diagnoseScopedImports(DiagnosticEngine &diags, - ArrayRef imports){ - for (const ModuleDecl::ImportedModule &importPair : imports) { + ArrayRef imports){ + for (const ImportedModule &importPair : imports) { if (importPair.accessPath.empty()) continue; diags.diagnose(importPair.accessPath.front().Loc, @@ -109,29 +109,27 @@ static void printImports(raw_ostream &out, // When printing the private swiftinterface file, print implementation-only // imports only if they are also SPI. First, list all implementation-only // imports and filter them later. - llvm::SmallSet ioiImportSet; + llvm::SmallSet ioiImportSet; if (Opts.PrintSPIs && Opts.ExperimentalSPIImports) { allImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; - SmallVector ioiImport; + SmallVector ioiImport; M->getImportedModules(ioiImport, {ModuleDecl::ImportFilterKind::ImplementationOnly, ModuleDecl::ImportFilterKind::SPIAccessControl}); ioiImportSet.insert(ioiImport.begin(), ioiImport.end()); } - SmallVector allImports; + SmallVector allImports; M->getImportedModules(allImports, allImportFilter); - ModuleDecl::removeDuplicateImports(allImports); + ImportedModule::removeDuplicates(allImports); diagnoseScopedImports(M->getASTContext().Diags, allImports); // Collect the public imports as a subset so that we can mark them with // '@_exported'. - SmallVector publicImports; + SmallVector publicImports; M->getImportedModules(publicImports, ModuleDecl::ImportFilterKind::Exported); - llvm::SmallSet publicImportSet; + llvm::SmallSet publicImportSet; publicImportSet.insert(publicImports.begin(), publicImports.end()); diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 39231330e0c30..65ed97bc973aa 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -318,10 +318,10 @@ static void getImmediateImports( ModuleDecl::ImportFilterKind::SPIAccessControl, ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay }) { - SmallVector importList; + SmallVector importList; module->getImportedModules(importList, importFilter); - for (ModuleDecl::ImportedModule &import : importList) + for (ImportedModule &import : importList) imports.insert(import.importedModule); } diff --git a/lib/FrontendTool/ImportedModules.cpp b/lib/FrontendTool/ImportedModules.cpp index 4ced1a7c5c8aa..857efcda8f98b 100644 --- a/lib/FrontendTool/ImportedModules.cpp +++ b/lib/FrontendTool/ImportedModules.cpp @@ -78,7 +78,7 @@ bool swift::emitImportedModules(ModuleDecl *mainModule, StringRef implicitHeaderPath = opts.ImplicitObjCHeaderPath; if (!implicitHeaderPath.empty()) { if (!clangImporter->importBridgingHeader(implicitHeaderPath, mainModule)) { - SmallVector imported; + SmallVector imported; clangImporter->getImportedHeaderModule()->getImportedModules( imported, {ModuleDecl::ImportFilterKind::Exported, ModuleDecl::ImportFilterKind::Default, diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index a39468e13fb21..8ab5f040d1a4e 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -817,13 +817,13 @@ bool swift::scanDependencies(CompilerInstance &instance) { } // Add any implicit module names. - for (const auto &moduleName : importInfo.ModuleNames) { - mainDependencies.addModuleDependency(moduleName.str(), &alreadyAddedModules); + for (const auto &import : importInfo.AdditionalUnloadedImports) { + mainDependencies.addModuleDependency(import.module.getModulePath(), &alreadyAddedModules); } // Already-loaded, implicitly imported module names. - for (const auto &module : importInfo.AdditionalModules) { - mainDependencies.addModuleDependency(module.first->getNameStr(), &alreadyAddedModules); + for (const auto &import : importInfo.AdditionalImports) { + mainDependencies.addModuleDependency(import.module.importedModule->getNameStr(), &alreadyAddedModules); } // Add the bridging header. diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 4fc0b5b149841..8079cd00c93d9 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -2036,8 +2036,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } void collectImportedModules(llvm::StringSet<> &ImportedModules) { - SmallVector Imported; - SmallVector FurtherImported; + SmallVector Imported; + SmallVector FurtherImported; CurrDeclContext->getParentSourceFile()->getImportedModules( Imported, {ModuleDecl::ImportFilterKind::Exported, @@ -5923,7 +5923,7 @@ static void deliverCompletionResults(CodeCompletionContext &CompletionContext, for (auto &Request: Lookup.RequestedCachedResults) { llvm::DenseSet ImportsSeen; - auto handleImport = [&](ModuleDecl::ImportedModule Import) { + auto handleImport = [&](ImportedModule Import) { ModuleDecl *TheModule = Import.importedModule; ImportPath::Access Path = Import.accessPath; if (TheModule->getFiles().empty()) @@ -5991,7 +5991,7 @@ static void deliverCompletionResults(CodeCompletionContext &CompletionContext, Lookup.addModuleName(curModule); // Add results for all imported modules. - SmallVector Imports; + SmallVector Imports; SF.getImportedModules( Imports, {ModuleDecl::ImportFilterKind::Exported, ModuleDecl::ImportFilterKind::Default, diff --git a/lib/IDE/REPLCodeCompletion.cpp b/lib/IDE/REPLCodeCompletion.cpp index caf7aef65bf70..02cdd4d82078b 100644 --- a/lib/IDE/REPLCodeCompletion.cpp +++ b/lib/IDE/REPLCodeCompletion.cpp @@ -221,16 +221,14 @@ doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID, auto *lastModule = SF.getParentModule(); ImplicitImportInfo implicitImports; - implicitImports.AdditionalModules.emplace_back(lastModule, - /*exported*/ false); + implicitImports.AdditionalImports.emplace_back(ImportedModule(lastModule)); // Carry over the private imports from the last module. - SmallVector imports; + SmallVector imports; lastModule->getImportedModules(imports, ModuleDecl::ImportFilterKind::Default); for (auto &import : imports) { - implicitImports.AdditionalModules.emplace_back(import.importedModule, - /*exported*/ false); + implicitImports.AdditionalImports.emplace_back(import); } // Create a new module and file for the code completion buffer, similar to how diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index 5d91564f12c26..d462676af3db3 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -661,7 +661,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { } void createImportedModule(llvm::DIScope *Context, - ModuleDecl::ImportedModule M, llvm::DIFile *File, + ImportedModule M, llvm::DIFile *File, unsigned Line) { // For overlays of Clang modules also emit an import of the underlying Clang // module. The helps the debugger resolve types that are present only in the @@ -761,7 +761,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { return None; } - llvm::DIModule *getOrCreateModule(ModuleDecl::ImportedModule IM) { + llvm::DIModule *getOrCreateModule(ImportedModule IM) { ModuleDecl *M = IM.importedModule; if (Optional ModuleDesc = getClangModule(*M)) return getOrCreateModule(*ModuleDesc, ModuleDesc->getModuleOrNull()); @@ -1882,7 +1882,7 @@ void IRGenDebugInfoImpl::finalize() { // Get the list of imported modules (which may actually be different // from all ImportDecls). - SmallVector ModuleWideImports; + SmallVector ModuleWideImports; IGM.getSwiftModule()->getImportedModules( ModuleWideImports, {ModuleDecl::ImportFilterKind::Exported, ModuleDecl::ImportFilterKind::Default, @@ -2129,7 +2129,7 @@ void IRGenDebugInfoImpl::emitImport(ImportDecl *D) { return; assert(D->getModule() && "compiler-synthesized ImportDecl is incomplete"); - ModuleDecl::ImportedModule Imported = { D->getAccessPath(), D->getModule() }; + ImportedModule Imported = { D->getAccessPath(), D->getModule() }; auto L = getDebugLoc(*this, D); auto *File = getOrCreateFile(L.Filename); createImportedModule(File, Imported, File, L.Line); diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp index f26580b5d3324..e8e6fab61ddc9 100644 --- a/lib/Index/Index.cpp +++ b/lib/Index/Index.cpp @@ -124,7 +124,7 @@ class SourceFileOrModule { } void - getImportedModules(SmallVectorImpl &Modules) const { + getImportedModules(SmallVectorImpl &Modules) const { constexpr ModuleDecl::ImportFilter ImportFilter = { ModuleDecl::ImportFilterKind::Exported, ModuleDecl::ImportFilterKind::Default, @@ -715,7 +715,7 @@ bool IndexSwiftASTWalker::visitImports( if (!IsNew) return true; - SmallVector Imports; + SmallVector Imports; TopMod.getImportedModules(Imports); llvm::SmallPtrSet Reported; @@ -1602,7 +1602,7 @@ void IndexSwiftASTWalker::collectRecursiveModuleImports( ImportFilter |= ModuleDecl::ImportFilterKind::Exported; ImportFilter |= ModuleDecl::ImportFilterKind::Default; // FIXME: ImportFilterKind::ShadowedByCrossImportOverlay? - SmallVector Imports; + SmallVector Imports; TopMod.getImportedModules(Imports); for (auto Import : Imports) { diff --git a/lib/Index/IndexRecord.cpp b/lib/Index/IndexRecord.cpp index 9beed7ea04ca0..4d0706ff6fa6e 100644 --- a/lib/Index/IndexRecord.cpp +++ b/lib/Index/IndexRecord.cpp @@ -383,7 +383,7 @@ emitDataForSwiftSerializedModule(ModuleDecl *module, IndexUnitWriter &parentUnitWriter, SourceFile *initialFile); -static void addModuleDependencies(ArrayRef imports, +static void addModuleDependencies(ArrayRef imports, StringRef indexStorePath, bool indexSystemModules, bool skipStdlib, @@ -580,7 +580,7 @@ emitDataForSwiftSerializedModule(ModuleDecl *module, unitWriter.addRecordFile(recordFile, *FE, isSystemModule, mod); } - SmallVector imports; + SmallVector imports; module->getImportedModules(imports, {ModuleDecl::ImportFilterKind::Exported, ModuleDecl::ImportFilterKind::Default}); StringScratchSpace moduleNameScratch; @@ -619,7 +619,7 @@ recordSourceFileUnit(SourceFile *primarySourceFile, StringRef indexUnitToken, getModuleInfoFromOpaqueModule); // Module dependencies. - SmallVector imports; + SmallVector imports; primarySourceFile->getImportedModules( imports, {ModuleDecl::ImportFilterKind::Exported, ModuleDecl::ImportFilterKind::Default, diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 9b2a4362eaa3f..017fe84c4e5f6 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -43,11 +43,6 @@ using namespace swift; // MARK: ImportResolver and supporting types //===----------------------------------------------------------------------===// -using ImportedModule = ModuleDecl::ImportedModule; -using ImportedModuleDesc = SourceFile::ImportedModuleDesc; -using ImportOptions = SourceFile::ImportOptions; -using ImportFlags = SourceFile::ImportFlags; - namespace { /// Represents an import which the ImportResolver knows exists, but which has /// not yet had its options checked, module loaded, or cross-imports found. @@ -56,44 +51,26 @@ namespace { /// source, or it may represent a cross-import overlay that has been found and /// needs to be loaded. struct UnboundImport { + /// Information about the import. Use this field, not \c getImportDecl(), to + /// determine the behavior expected for this import. + AttributedImport import; + /// The source location to use when diagnosing errors for this import. SourceLoc importLoc; - /// The options for this import, such as "exported" or - /// "implementation-only". Use this field, not \c attrs, to determine the - /// behavior expected for this import. - ImportOptions options; - - /// If \c options includes \c PrivateImport, the filename we should import - /// private declarations from. - StringRef privateImportFileName; - - /// The module names being imported. There will usually be just one for the - /// top-level module, but a submodule import will have more. - ImportPath::Module modulePath; - - /// If this is a scoped import, the names of the declaration being imported; - /// otherwise empty. (Currently the compiler doesn't support nested scoped - /// imports, so there should always be zero or one elements, but - /// \c ImportPath::Access is the common currency type for this.) - ImportPath::Access accessPath; - - // Names of explicitly imported SPI groups via @_spi. - ArrayRef spiGroups; - /// If this UnboundImport directly represents an ImportDecl, contains the /// ImportDecl it represents. This should only be used for diagnostics and /// for updating the AST; if you want to read information about the import, - /// get it from the other fields in \c UnboundImport rather than from the - /// \c ImportDecl. + /// get it from the \c import field rather than from the \c ImportDecl. /// /// If this UnboundImport represents a cross-import, contains the declaring /// module's \c ModuleDecl. - PointerUnion importOrUnderlyingModuleDecl; + PointerUnion, ModuleDecl *> + importOrUnderlyingModuleDecl; NullablePtr getImportDecl() const { - return importOrUnderlyingModuleDecl.is() ? - importOrUnderlyingModuleDecl.get() : nullptr; + return importOrUnderlyingModuleDecl.is>() ? + importOrUnderlyingModuleDecl.get>() : nullptr; } NullablePtr getUnderlyingModule() const { @@ -104,11 +81,14 @@ struct UnboundImport { /// Create an UnboundImport for a user-written import declaration. explicit UnboundImport(ImportDecl *ID); + /// Create an UnboundImport for an unloaded implicit import. + explicit UnboundImport(AttributedImport implicit); + /// Create an UnboundImport for a cross-import overlay. explicit UnboundImport(ASTContext &ctx, const UnboundImport &base, Identifier overlayName, - const ImportedModuleDesc &declaringImport, - const ImportedModuleDesc &bystandingImport); + const AttributedImport &declaringImport, + const AttributedImport &bystandingImport); /// Diagnoses if the import would simply load the module \p SF already /// belongs to, with no actual effect. @@ -138,11 +118,11 @@ struct UnboundImport { /// non-implementation-only import of a fragile library from a resilient one. void validateOptions(NullablePtr topLevelModule, SourceFile &SF); - /// Create an \c ImportedModuleDesc from the information in this + /// Create an \c AttributedImport from the information in this /// UnboundImport. - ImportedModuleDesc makeDesc(ModuleDecl *module) const { - return ImportedModuleDesc({ accessPath, module }, options, - privateImportFileName, spiGroups); + AttributedImport + makeAttributedImport(ModuleDecl *module) const { + return import.getLoaded(module); } private: @@ -170,7 +150,7 @@ class ImportResolver final : public DeclVisitor { SmallVector unboundImports; /// The list of fully bound imports. - SmallVector boundImports; + SmallVector, 16> boundImports; /// All imported modules which should be considered when cross-importing. /// This is basically the transitive import graph, but with only top-level @@ -179,14 +159,14 @@ class ImportResolver final : public DeclVisitor { /// We use a \c SmallSetVector here because this doubles as the worklist for /// cross-importing, so we want to keep it in order; this is feasible /// because this set is usually fairly small. - SmallSetVector crossImportableModules; + SmallSetVector, 64> crossImportableModules; /// The subset of \c crossImportableModules which may declare cross-imports. /// /// This is a performance optimization. Since most modules do not register /// any cross-imports, we can usually compare against this list, which is /// much, much smaller than \c crossImportableModules. - SmallVector crossImportDeclaringModules; + SmallVector, 16> crossImportDeclaringModules; /// The index of the next module in \c visibleModules that should be /// cross-imported. @@ -197,18 +177,10 @@ class ImportResolver final : public DeclVisitor { addImplicitImports(); } - void addImplicitImports() { - // TODO: Support cross-module imports. - for (auto &import : SF.getParentModule()->getImplicitImports()) { - assert(!(SF.Kind == SourceFileKind::SIL && - import.Module->isStdlibModule())); - ImportedModule importedMod{ImportPath::Access(), import.Module}; - boundImports.emplace_back(importedMod, import.Options); - } - } + void addImplicitImports(); /// Retrieve the finalized imports. - ArrayRef getFinishedImports() const { + ArrayRef> getFinishedImports() const { return boundImports; } @@ -224,6 +196,9 @@ class ImportResolver final : public DeclVisitor { return ctx.Diags.diagnose(std::forward(Args)...); } + /// Calls \c bindImport() on unbound imports until \c boundImports is drained. + void bindPendingImports(); + /// Check a single unbound import, bind it, add it to \c boundImports, /// and add its cross-import overlays to \c unboundImports. void bindImport(UnboundImport &&I); @@ -233,7 +208,7 @@ class ImportResolver final : public DeclVisitor { /// Adds \p desc and everything it re-exports to \c visibleModules using /// the settings from \c desc. - void addCrossImportableModules(ImportedModuleDesc desc); + void addCrossImportableModules(AttributedImport desc); /// * If \p I is a cross-import overlay, registers \p M as overlaying /// \p I.underlyingModule in \c SF. @@ -244,18 +219,19 @@ class ImportResolver final : public DeclVisitor { /// Discovers any cross-imports between \p newImport and /// \p oldImports and adds them to \c unboundImports, using source /// locations from \p I. - void findCrossImportsInLists(UnboundImport &I, - ArrayRef declaring, - ArrayRef bystanding, - bool shouldDiagnoseRedundantCrossImports); + void findCrossImportsInLists( + UnboundImport &I, + ArrayRef> declaring, + ArrayRef> bystanding, + bool shouldDiagnoseRedundantCrossImports); /// Discovers any cross-imports between \p declaringImport and /// \p bystandingImport and adds them to \c unboundImports, using source /// locations from \p I. void findCrossImports(UnboundImport &I, - const ImportedModuleDesc &declaringImport, - const ImportedModuleDesc &bystandingImport, - bool shouldDiagnoseRedundantCrossImports); + const AttributedImport &declaringImport, + const AttributedImport &bystandingImport, + bool shouldDiagnoseRedundantCrossImports); /// Load a module referenced by an import statement. /// @@ -315,6 +291,10 @@ void ImportResolver::visitImportDecl(ImportDecl *ID) { assert(unboundImports.empty()); unboundImports.emplace_back(ID); + bindPendingImports(); +} + +void ImportResolver::bindPendingImports() { while(!unboundImports.empty()) bindImport(unboundImports.pop_back_val()); } @@ -329,7 +309,7 @@ void ImportResolver::bindImport(UnboundImport &&I) { return; } - ModuleDecl *M = getModule(I.modulePath); + ModuleDecl *M = getModule(I.import.module.getModulePath()); if (!I.checkModuleLoaded(M, SF)) { // Can't process further. checkModuleLoaded() will have diagnosed this. if (ID) @@ -358,7 +338,7 @@ void ImportResolver::bindImport(UnboundImport &&I) { } void ImportResolver::addImport(const UnboundImport &I, ModuleDecl *M) { - auto importDesc = I.makeDesc(M); + auto importDesc = I.makeAttributedImport(M); addCrossImportableModules(importDesc); boundImports.push_back(importDesc); } @@ -367,14 +347,16 @@ void ImportResolver::addImport(const UnboundImport &I, ModuleDecl *M) { // MARK: Import module loading //===----------------------------------------------------------------------===// -ModuleDecl * -ImportResolver::getModule(ImportPath::Module modulePath) { +static ModuleDecl * +getModuleImpl(ImportPath::Module modulePath, ModuleDecl *loadingModule, + bool canImportBuiltin) { + ASTContext &ctx = loadingModule->getASTContext(); + assert(!modulePath.empty()); auto moduleID = modulePath[0]; // The Builtin module cannot be explicitly imported unless we're a .sil file. - if (SF.Kind == SourceFileKind::SIL && - moduleID.Item == ctx.TheBuiltinModule->getName()) + if (canImportBuiltin && moduleID.Item == ctx.TheBuiltinModule->getName()) return ctx.TheBuiltinModule; // If the imported module name is the same as the current module, @@ -383,8 +365,7 @@ ImportResolver::getModule(ImportPath::Module modulePath) { // // FIXME: We'd like to only use this in SIL mode, but unfortunately we use it // for clang overlays as well. - if (moduleID.Item == SF.getParentModule()->getName() && - modulePath.size() == 1) { + if (moduleID.Item == loadingModule->getName() && modulePath.size() == 1) { if (auto importer = ctx.getClangModuleLoader()) return importer->loadModule(moduleID.Loc, modulePath); return nullptr; @@ -393,13 +374,19 @@ ImportResolver::getModule(ImportPath::Module modulePath) { return ctx.getModule(modulePath); } +ModuleDecl * +ImportResolver::getModule(ImportPath::Module modulePath) { + return getModuleImpl(modulePath, SF.getParentModule(), + /*canImportBuiltin=*/SF.Kind == SourceFileKind::SIL); +} + NullablePtr UnboundImport::getTopLevelModule(ModuleDecl *M, SourceFile &SF) { - if (modulePath.size() == 1) + if (import.module.getModulePath().size() == 1) return M; // If we imported a submodule, import the top-level module as well. - Identifier topLevelName = modulePath.front().Item; + Identifier topLevelName = import.module.getModulePath().front().Item; ModuleDecl *topLevelModule = SF.getASTContext().getLoadedModule(topLevelName); if (!topLevelModule) { @@ -422,49 +409,66 @@ UnboundImport::getTopLevelModule(ModuleDecl *M, SourceFile &SF) { // MARK: Implicit imports //===----------------------------------------------------------------------===// -ArrayRef +static void diagnoseNoSuchModule(ModuleDecl *importingModule, + SourceLoc importLoc, + ImportPath::Module modulePath, + bool nonfatalInREPL) { + ASTContext &ctx = importingModule->getASTContext(); + + if (modulePath.size() == 1 && + importingModule->getName() == modulePath.front().Item) { + ctx.Diags.diagnose(importLoc, diag::error_underlying_module_not_found, + importingModule->getName()); + } else { + SmallString<64> modulePathStr; + modulePath.getString(modulePathStr); + + auto diagKind = diag::sema_no_import; + if (nonfatalInREPL && ctx.LangOpts.DebuggerSupport) + diagKind = diag::sema_no_import_repl; + ctx.Diags.diagnose(importLoc, diagKind, modulePathStr); + } + + if (ctx.SearchPathOpts.SDKPath.empty() && + llvm::Triple(llvm::sys::getProcessTriple()).isMacOSX()) { + ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk); + ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk_xcrun); + } +} + +ImplicitImportList ModuleImplicitImportsRequest::evaluate(Evaluator &evaluator, ModuleDecl *module) const { - SmallVector imports; + SmallVector, 4> imports; + SmallVector, 4> unloadedImports; auto &ctx = module->getASTContext(); auto &importInfo = module->getImplicitImportInfo(); // Add an implicit stdlib if needed. + ModuleDecl *stdlib; switch (importInfo.StdlibKind) { case ImplicitStdlibKind::None: + stdlib = nullptr; break; case ImplicitStdlibKind::Builtin: - imports.emplace_back(ctx.TheBuiltinModule); + stdlib = ctx.TheBuiltinModule; break; - case ImplicitStdlibKind::Stdlib: { - auto *stdlib = ctx.getStdlibModule(/*loadIfAbsent*/ true); + case ImplicitStdlibKind::Stdlib: + stdlib = ctx.getStdlibModule(/*loadIfAbsent*/ true); assert(stdlib && "Missing stdlib?"); - imports.emplace_back(stdlib); break; } - } + + if (stdlib) + imports.emplace_back(ImportedModule(stdlib)); // Add any modules we were asked to implicitly import. - for (auto moduleName : importInfo.ModuleNames) { - auto *importModule = ctx.getModuleByIdentifier(moduleName); - if (!importModule) { - ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import, moduleName.str()); - if (ctx.SearchPathOpts.SDKPath.empty() && - llvm::Triple(llvm::sys::getProcessTriple()).isMacOSX()) { - ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk); - ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk_xcrun); - } - continue; - } - imports.emplace_back(importModule); - } + llvm::copy(importInfo.AdditionalUnloadedImports, + std::back_inserter(unloadedImports)); // Add any pre-loaded modules. - for (auto &module : importInfo.AdditionalModules) { - imports.emplace_back(module.first, module.second ? ImportFlags::Exported - : ImportOptions()); - } + llvm::copy(importInfo.AdditionalImports, std::back_inserter(imports)); auto *clangImporter = static_cast(ctx.getClangModuleLoader()); @@ -475,63 +479,82 @@ ModuleImplicitImportsRequest::evaluate(Evaluator &evaluator, !clangImporter->importBridgingHeader(bridgingHeaderPath, module)) { auto *headerModule = clangImporter->getImportedHeaderModule(); assert(headerModule && "Didn't load bridging header?"); - imports.emplace_back(headerModule, ImportFlags::Exported); + imports.emplace_back(ImportedModule(headerModule), ImportFlags::Exported); } // Implicitly import the underlying Clang half of this module if needed. if (importInfo.ShouldImportUnderlyingModule) { - auto *underlyingMod = clangImporter->loadModule( - SourceLoc(), ImportPath::Module::Builder(module->getName()).get()); - if (underlyingMod) { - imports.emplace_back(underlyingMod, ImportFlags::Exported); - } else { - ctx.Diags.diagnose(SourceLoc(), diag::error_underlying_module_not_found, - module->getName()); - } + // An @_exported self-import is loaded from ClangImporter instead of being + // rejected; see the special case in getModuleImpl() for details. + ImportPath::Builder importPath(module->getName()); + unloadedImports.emplace_back(UnloadedImportedModule(importPath.copyTo(ctx), + /*isScoped=*/false), + ImportFlags::Exported); + } + + return { ctx.AllocateCopy(imports), ctx.AllocateCopy(unloadedImports) }; +} + +void ImportResolver::addImplicitImports() { + auto implicitImports = SF.getParentModule()->getImplicitImports(); + + // TODO: Support cross-module imports. + for (auto &import : implicitImports.imports) { + assert(!(SF.Kind == SourceFileKind::SIL && + import.module.importedModule->isStdlibModule())); + boundImports.push_back(import); } - return ctx.AllocateCopy(imports); + for (auto &unloadedImport : implicitImports.unloadedImports) + unboundImports.emplace_back(unloadedImport); + + bindPendingImports(); } +UnboundImport::UnboundImport(AttributedImport implicit) + : import(implicit), importLoc(), + importOrUnderlyingModuleDecl(static_cast(nullptr)) {} + //===----------------------------------------------------------------------===// // MARK: Import validation (except for scoped imports) //===----------------------------------------------------------------------===// /// Create an UnboundImport for a user-written import declaration. UnboundImport::UnboundImport(ImportDecl *ID) - : importLoc(ID->getLoc()), options(), privateImportFileName(), - modulePath(ID->getModulePath()), accessPath(ID->getAccessPath()), - importOrUnderlyingModuleDecl(ID) + : import(UnloadedImportedModule(ID->getImportPath(), ID->getImportKind()), + {}), + importLoc(ID->getLoc()), importOrUnderlyingModuleDecl(ID) { if (ID->isExported()) - options |= ImportFlags::Exported; + import.options |= ImportFlags::Exported; if (ID->getAttrs().hasAttribute()) - options |= ImportFlags::Testable; + import.options |= ImportFlags::Testable; if (ID->getAttrs().hasAttribute()) - options |= ImportFlags::ImplementationOnly; + import.options |= ImportFlags::ImplementationOnly; if (auto *privateImportAttr = ID->getAttrs().getAttribute()) { - options |= ImportFlags::PrivateImport; - privateImportFileName = privateImportAttr->getSourceFile(); + import.options |= ImportFlags::PrivateImport; + import.sourceFileArg = privateImportAttr->getSourceFile(); } SmallVector spiGroups; for (auto attr : ID->getAttrs().getAttributes()) { - options |= SourceFile::ImportFlags::SPIAccessControl; + import.options |= ImportFlags::SPIAccessControl; auto attrSPIs = attr->getSPIGroups(); spiGroups.append(attrSPIs.begin(), attrSPIs.end()); } - this->spiGroups = ID->getASTContext().AllocateCopy(spiGroups); + import.spiGroups = ID->getASTContext().AllocateCopy(spiGroups); } bool UnboundImport::checkNotTautological(const SourceFile &SF) { // Exit early if this is not a self-import. + auto modulePath = import.module.getModulePath(); if (modulePath.front().Item != SF.getParentModule()->getName() || // Overlays use an @_exported self-import to load their clang module. - options.contains(ImportFlags::Exported) || + import.options.contains(ImportFlags::Exported) || // Imports of your own submodules are allowed in cross-language libraries. modulePath.size() != 1 || // SIL files self-import to get decls from the rest of the module. @@ -555,24 +578,8 @@ bool UnboundImport::checkModuleLoaded(ModuleDecl *M, SourceFile &SF) { if (M) return true; - ASTContext &ctx = SF.getASTContext(); - - SmallString<64> modulePathStr; - llvm::interleave(modulePath, [&](ImportPath::Element elem) { - modulePathStr += elem.Item.str(); - }, - [&] { modulePathStr += "."; }); - - auto diagKind = diag::sema_no_import; - if (ctx.LangOpts.DebuggerSupport) - diagKind = diag::sema_no_import_repl; - ctx.Diags.diagnose(importLoc, diagKind, modulePathStr); - - if (ctx.SearchPathOpts.SDKPath.empty() && - llvm::Triple(llvm::sys::getProcessTriple()).isMacOSX()) { - ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk); - ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk_xcrun); - } + diagnoseNoSuchModule(SF.getParentModule(), importLoc, + import.module.getModulePath(), /*nonfatalInREPL=*/true); return false; } @@ -602,7 +609,7 @@ void UnboundImport::validatePrivate(ModuleDecl *topLevelModule) { assert(topLevelModule); ASTContext &ctx = topLevelModule->getASTContext(); - if (!options.contains(ImportFlags::PrivateImport)) + if (!import.options.contains(ImportFlags::PrivateImport)) return; if (topLevelModule->arePrivateImportsEnabled()) @@ -610,16 +617,16 @@ void UnboundImport::validatePrivate(ModuleDecl *topLevelModule) { diagnoseInvalidAttr(DAK_PrivateImport, ctx.Diags, diag::module_not_compiled_for_private_import); - privateImportFileName = StringRef(); + import.sourceFileArg = StringRef(); } void UnboundImport::validateImplementationOnly(ASTContext &ctx) { - if (!options.contains(ImportFlags::ImplementationOnly) || - !options.contains(ImportFlags::Exported)) + if (!import.options.contains(ImportFlags::ImplementationOnly) || + !import.options.contains(ImportFlags::Exported)) return; // Remove one flag to maintain the invariant. - options -= ImportFlags::ImplementationOnly; + import.options -= ImportFlags::ImplementationOnly; diagnoseInvalidAttr(DAK_ImplementationOnly, ctx.Diags, diag::import_implementation_cannot_be_exported); @@ -629,7 +636,7 @@ void UnboundImport::validateTestable(ModuleDecl *topLevelModule) { assert(topLevelModule); ASTContext &ctx = topLevelModule->getASTContext(); - if (!options.contains(ImportFlags::Testable) || + if (!import.options.contains(ImportFlags::Testable) || topLevelModule->isTestingEnabled() || topLevelModule->isNonSwiftModule() || !ctx.LangOpts.EnableTestableAttrRequiresTestableModule) @@ -640,7 +647,7 @@ void UnboundImport::validateTestable(ModuleDecl *topLevelModule) { void UnboundImport::validateResilience(NullablePtr topLevelModule, SourceFile &SF) { - if (options.contains(ImportFlags::ImplementationOnly)) + if (import.options.contains(ImportFlags::ImplementationOnly)) return; // Per getTopLevelModule(), we'll only get nullptr here for non-Swift modules, @@ -653,7 +660,7 @@ void UnboundImport::validateResilience(NullablePtr topLevelModule, return; ASTContext &ctx = SF.getASTContext(); - ctx.Diags.diagnose(modulePath.front().Loc, + ctx.Diags.diagnose(import.module.getModulePath().front().Loc, diag::module_not_compiled_with_library_evolution, topLevelModule.get()->getName(), SF.getParentModule()->getName()); @@ -664,8 +671,8 @@ void UnboundImport::validateResilience(NullablePtr topLevelModule, void UnboundImport::diagnoseInvalidAttr(DeclAttrKind attrKind, DiagnosticEngine &diags, Diag diagID) { - auto diag = diags.diagnose(modulePath.front().Loc, diagID, - modulePath.front().Item); + auto diag = diags.diagnose(import.module.getModulePath().front().Loc, diagID, + import.module.getModulePath().front().Item); auto *ID = getImportDecl().getPtrOrNull(); if (!ID) return; @@ -917,29 +924,41 @@ ScopedImportLookupRequest::evaluate(Evaluator &evaluator, // MARK: Cross-import overlays //===----------------------------------------------------------------------===// -static bool canCrossImport(const ImportedModuleDesc &import) { - if (import.importOptions.contains(ImportFlags::Testable)) +static bool canCrossImport(const AttributedImport &import) { + if (import.options.contains(ImportFlags::Testable)) return false; - if (import.importOptions.contains(ImportFlags::PrivateImport)) + if (import.options.contains(ImportFlags::PrivateImport)) return false; return true; } +static UnloadedImportedModule makeUnimportedCrossImportOverlay( + ASTContext &ctx, + Identifier overlayName, + const UnboundImport &base, + const AttributedImport &declaringImport) { + ImportPath::Builder + builder(overlayName, base.import.module.getModulePath()[0].Loc); + + // If the declaring import was scoped, inherit that scope in the overlay's + // import. + llvm::copy(declaringImport.module.accessPath, std::back_inserter(builder)); + + // Cross-imports are not backed by an ImportDecl, so we need to provide + // our own storage for their module paths. + return UnloadedImportedModule(builder.copyTo(ctx), + /*isScoped=*/!declaringImport.module.accessPath.empty()); +} + /// Create an UnboundImport for a cross-import overlay. -UnboundImport::UnboundImport(ASTContext &ctx, const UnboundImport &base, - Identifier overlayName, - const ImportedModuleDesc &declaringImport, - const ImportedModuleDesc &bystandingImport) - : importLoc(base.importLoc), options(), privateImportFileName(), - // Cross-imports are not backed by an ImportDecl, so we need to provide - // our own storage for their module paths. - modulePath( - ImportPath::Module::Builder(overlayName, base.modulePath[0].Loc) - .copyTo(ctx)), - // If the declaring import was scoped, inherit that scope in the - // overlay's import. - accessPath(declaringImport.module.accessPath), +UnboundImport::UnboundImport( + ASTContext &ctx, const UnboundImport &base, Identifier overlayName, + const AttributedImport &declaringImport, + const AttributedImport &bystandingImport) + : import(makeUnimportedCrossImportOverlay(ctx, overlayName, base, + declaringImport), {}), + importLoc(base.importLoc), importOrUnderlyingModuleDecl(declaringImport.module.importedModule) { // A cross-import is never private or testable, and never comes from a private @@ -947,19 +966,19 @@ UnboundImport::UnboundImport(ASTContext &ctx, const UnboundImport &base, assert(canCrossImport(declaringImport)); assert(canCrossImport(bystandingImport)); - auto &declaringOptions = declaringImport.importOptions; - auto &bystandingOptions = bystandingImport.importOptions; + auto &declaringOptions = declaringImport.options; + auto &bystandingOptions = bystandingImport.options; // If both are exported, the cross-import is exported. if (declaringOptions.contains(ImportFlags::Exported) && bystandingOptions.contains(ImportFlags::Exported)) - options |= ImportFlags::Exported; + import.options |= ImportFlags::Exported; // If either are implementation-only, the cross-import is // implementation-only. if (declaringOptions.contains(ImportFlags::ImplementationOnly) || bystandingOptions.contains(ImportFlags::ImplementationOnly)) - options |= ImportFlags::ImplementationOnly; + import.options |= ImportFlags::ImplementationOnly; } void ImportResolver::crossImport(ModuleDecl *M, UnboundImport &I) { @@ -1037,8 +1056,8 @@ void ImportResolver::crossImport(ModuleDecl *M, UnboundImport &I) { } void ImportResolver::findCrossImportsInLists( - UnboundImport &I, ArrayRef declaring, - ArrayRef bystanding, + UnboundImport &I, ArrayRef> declaring, + ArrayRef> bystanding, bool shouldDiagnoseRedundantCrossImports) { for (auto &declaringImport : declaring) { if (!canCrossImport(declaringImport)) @@ -1055,8 +1074,9 @@ void ImportResolver::findCrossImportsInLists( } void ImportResolver::findCrossImports( - UnboundImport &I, const ImportedModuleDesc &declaringImport, - const ImportedModuleDesc &bystandingImport, + UnboundImport &I, + const AttributedImport &declaringImport, + const AttributedImport &bystandingImport, bool shouldDiagnoseRedundantCrossImports) { assert(&declaringImport != &bystandingImport); @@ -1109,7 +1129,7 @@ void ImportResolver::findCrossImports( name); LLVM_DEBUG({ - auto &crossImportOptions = unboundImports.back().options; + auto &crossImportOptions = unboundImports.back().import.options; llvm::dbgs() << " "; if (crossImportOptions.contains(ImportFlags::Exported)) llvm::dbgs() << "@_exported "; @@ -1125,7 +1145,8 @@ static bool isSubmodule(ModuleDecl* M) { return clangMod && clangMod->Parent; } -void ImportResolver::addCrossImportableModules(ImportedModuleDesc importDesc) { +void ImportResolver::addCrossImportableModules( + AttributedImport importDesc) { // FIXME: namelookup::getAllImports() doesn't quite do what we need (mainly // w.r.t. scoped imports), but it seems like we could extend it to do so, and // then eliminate most of this. diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index 600744840648e..4e211d525dbe1 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -149,8 +149,8 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( // Collect implicitly imported modules in case they are not explicitly // printed in the interface file, e.g. SwiftOnoneSupport. auto &imInfo = mainMod->getImplicitImportInfo(); - for (auto name: imInfo.ModuleNames) { - Result->addModuleDependency(name.str(), &alreadyAddedModules); + for (auto import: imInfo.AdditionalUnloadedImports) { + Result->addModuleDependency(import.module.getModulePath(), &alreadyAddedModules); } return std::error_code(); }); diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index 5bd056555121f..31e559be687bf 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -167,8 +167,8 @@ Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc) { return error(Status::FailedToLoadBridgingHeader); } ModuleDecl *importedHeaderModule = clangImporter->getImportedHeaderModule(); - dependency.Import = ModuleDecl::ImportedModule{ImportPath::Access(), - importedHeaderModule}; + dependency.Import = ImportedModule{ImportPath::Access(), + importedHeaderModule}; continue; } @@ -212,7 +212,7 @@ Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc) { continue; } - dependency.Import = ModuleDecl::ImportedModule{accessPath, module}; + dependency.Import = ImportedModule{accessPath, module}; // SPI StringRef spisStr = dependency.Core.RawSPIs; @@ -420,9 +420,8 @@ PrecedenceGroupDecl *ModuleFile::lookupPrecedenceGroup(Identifier name) { return cast(getDecl(data[0].second)); } -void ModuleFile::getImportedModules( - SmallVectorImpl &results, - ModuleDecl::ImportFilter filter) { +void ModuleFile::getImportedModules(SmallVectorImpl &results, + ModuleDecl::ImportFilter filter) { PrettyStackTraceModuleFile stackEntry(*this); for (auto &dep : Dependencies) { diff --git a/lib/Serialization/ModuleFile.h b/lib/Serialization/ModuleFile.h index 7749f82adee91..dfa5594eaf46f 100644 --- a/lib/Serialization/ModuleFile.h +++ b/lib/Serialization/ModuleFile.h @@ -90,7 +90,7 @@ class ModuleFile public: const ModuleFileSharedCore::Dependency &Core; - llvm::Optional Import = llvm::None; + llvm::Optional Import = llvm::None; SmallVector spiGroups; Dependency(const ModuleFileSharedCore::Dependency &coreDependency) @@ -527,7 +527,7 @@ class ModuleFile PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name); /// Adds any imported modules to the given vector. - void getImportedModules(SmallVectorImpl &results, + void getImportedModules(SmallVectorImpl &results, ModuleDecl::ImportFilter filter); void getImportDecls(SmallVectorImpl &Results); diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index ad6e002234df8..f5f2830ae446a 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -953,7 +953,7 @@ void Serializer::writeHeader(const SerializationOptions &options) { } } -static void flattenImportPath(const ModuleDecl::ImportedModule &import, +static void flattenImportPath(const ImportedModule &import, SmallVectorImpl &out) { llvm::raw_svector_ostream outStream(out); import.importedModule->getReverseFullModuleName().printForward( @@ -974,11 +974,10 @@ uint64_t getRawModTimeOrHash(const SerializationOptions::FileDependency &dep) { return dep.getModificationTime(); } -using ImportSet = llvm::SmallSet; +using ImportSet = llvm::SmallSet; static ImportSet getImportsAsSet(const ModuleDecl *M, ModuleDecl::ImportFilter filter) { - SmallVector imports; + SmallVector imports; M->getImportedModules(imports, filter); ImportSet importSet; importSet.insert(imports.begin(), imports.end()); @@ -987,7 +986,7 @@ static ImportSet getImportsAsSet(const ModuleDecl *M, void Serializer::writeInputBlock(const SerializationOptions &options) { BCBlockRAII restoreBlock(Out, INPUT_BLOCK_ID, 4); - input_block::ImportedModuleLayout ImportedModule(Out); + input_block::ImportedModuleLayout importedModule(Out); input_block::ImportedModuleLayoutSPI ImportedModuleSPI(Out); input_block::LinkLibraryLayout LinkLibrary(Out); input_block::ImportedHeaderLayout ImportedHeader(Out); @@ -1031,13 +1030,13 @@ void Serializer::writeInputBlock(const SerializationOptions &options) { if (!options.ModuleInterface.empty()) ModuleInterface.emit(ScratchRecord, options.ModuleInterface); - SmallVector allImports; + SmallVector allImports; M->getImportedModules(allImports, {ModuleDecl::ImportFilterKind::Exported, ModuleDecl::ImportFilterKind::Default, ModuleDecl::ImportFilterKind::ImplementationOnly, ModuleDecl::ImportFilterKind::SPIAccessControl}); - ModuleDecl::removeDuplicateImports(allImports); + ImportedModule::removeDuplicates(allImports); // Collect the public and private imports as a subset so that we can // distinguish them. @@ -1055,8 +1054,8 @@ void Serializer::writeInputBlock(const SerializationOptions &options) { auto clangImporter = static_cast(M->getASTContext().getClangModuleLoader()); ModuleDecl *bridgingHeaderModule = clangImporter->getImportedHeaderModule(); - ModuleDecl::ImportedModule bridgingHeaderImport{ImportPath::Access(), - bridgingHeaderModule}; + ImportedModule bridgingHeaderImport{ImportPath::Access(), + bridgingHeaderModule}; // Make sure the bridging header module is always at the top of the import // list, mimicking how it is processed before any module imports when @@ -1104,7 +1103,7 @@ void Serializer::writeInputBlock(const SerializationOptions &options) { llvm::SmallSetVector spis; M->lookupImportedSPIGroups(import.importedModule, spis); - ImportedModule.emit(ScratchRecord, + importedModule.emit(ScratchRecord, static_cast(stableImportControl), !import.accessPath.empty(), !spis.empty(), importPath); diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index c3ae09130cf70..30e5baaa778e2 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -1109,14 +1109,14 @@ void SerializedModuleLoaderBase::verifyAllModules() { //----------------------------------------------------------------------------- void SerializedASTFile::getImportedModules( - SmallVectorImpl &imports, + SmallVectorImpl &imports, ModuleDecl::ImportFilter filter) const { File.getImportedModules(imports, filter); } void SerializedASTFile::collectLinkLibrariesFromImports( ModuleDecl::LinkLibraryCallback callback) const { - llvm::SmallVector Imports; + llvm::SmallVector Imports; File.getImportedModules(Imports, {ModuleDecl::ImportFilterKind::Exported, ModuleDecl::ImportFilterKind::Default}); diff --git a/test/ClangImporter/MixedSource/mixed-target-using-module.swift b/test/ClangImporter/MixedSource/mixed-target-using-module.swift index 0c007f6dd7895..7cacecc69c4fd 100644 --- a/test/ClangImporter/MixedSource/mixed-target-using-module.swift +++ b/test/ClangImporter/MixedSource/mixed-target-using-module.swift @@ -1,6 +1,14 @@ // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -F %S/Inputs/mixed-target/ -module-name Mixed -import-underlying-module -typecheck %s -verify -enable-objc-interop -disable-objc-attr-requires-foundation-module // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -F %S/Inputs/mixed-target/ -module-name Mixed -import-underlying-module -enable-objc-interop -emit-ir %S/../../Inputs/empty.swift | %FileCheck -check-prefix=CHECK-AUTOLINK %s +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -F %S/Inputs/mixed-target/ -module-name Mixed -DOVERLAY_STYLE_RIGHT -enable-objc-interop -emit-ir %S/../../Inputs/empty.swift | %FileCheck -check-prefix=CHECK-AUTOLINK %s // RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -F %S/Inputs/mixed-target/ -module-name WrongName -import-underlying-module -typecheck %s -enable-objc-interop -disable-objc-attr-requires-foundation-module 2>&1 | %FileCheck -check-prefix=CHECK-WRONG-NAME %s +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -F %S/Inputs/mixed-target/ -module-name WrongName -DOVERLAY_STYLE_WRONG -typecheck %s -enable-objc-interop -disable-objc-attr-requires-foundation-module 2>&1 | %FileCheck -check-prefix=CHECK-WRONG-NAME %s + +#if OVERLAY_STYLE_RIGHT +@_exported import Mixed +#elseif OVERLAY_STYLE_WRONG +@_exported import WrongName +#endif // CHECK-AUTOLINK: !llvm.linker.options = !{ // CHECK-AUTOLINK-NOT: !"-framework" diff --git a/test/CrossImport/common-case.swift b/test/CrossImport/common-case.swift index f29a547e6004e..7ac70d60823cf 100644 --- a/test/CrossImport/common-case.swift +++ b/test/CrossImport/common-case.swift @@ -5,10 +5,13 @@ // RUN: cp -r %S/Inputs/lib-templates/* %t/ // RUN: %{python} %S/Inputs/rewrite-module-triples.py %t %module-target-triple -// RUN: %target-typecheck-verify-swift -enable-cross-import-overlays -I %t/include -I %t/lib/swift -F %t/Frameworks +// RUN: %target-typecheck-verify-swift -enable-cross-import-overlays -DIMPORT_BYSTANDING_LIBRARY -I %t/include -I %t/lib/swift -F %t/Frameworks +// RUN: %target-typecheck-verify-swift -enable-cross-import-overlays -import-module BystandingLibrary -I %t/include -I %t/lib/swift -F %t/Frameworks // Each framework has a cross-import overlay with this library: +#if IMPORT_BYSTANDING_LIBRARY import BystandingLibrary +#endif // 1. A Swift framework diff --git a/test/ImportResolution/import-command-line.swift b/test/ImportResolution/import-command-line.swift index 8a305450578b5..1f0012bdefd4e 100644 --- a/test/ImportResolution/import-command-line.swift +++ b/test/ImportResolution/import-command-line.swift @@ -7,5 +7,8 @@ // RUN: not %target-swift-frontend -typecheck %s -enable-source-import -I %S/Inputs -sdk "" -import-module NON_EXISTENT 2>&1 | %FileCheck -check-prefix=NON-EXISTENT %s // NON-EXISTENT: error: no such module 'NON_EXISTENT' +// RUN: not %target-swift-frontend -typecheck %s -enable-source-import -I %S/Inputs -sdk "" -testable-import-module abcde 2>&1 | %FileCheck -check-prefix=NON-TESTABLE %s +// NON-TESTABLE: error: module 'abcde' was not compiled for testing + var a: A? // expected-error {{cannot find type 'A' in scope}} var qA: abcde.A? // expected-error {{cannot find type 'abcde' in scope}} diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp index 13a1b571e34c3..0268272f6e1d5 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp @@ -347,14 +347,14 @@ ImportDepth::ImportDepth(ASTContext &context, // Imports from -import-name such as Playground auxiliary sources are treated // specially by applying import depth 0. llvm::StringSet<> auxImports; - for (StringRef moduleName : + for (const auto &pair : invocation.getFrontendOptions().getImplicitImportModuleNames()) - auxImports.insert(moduleName); + auxImports.insert(pair.first); // Private imports from this module. // FIXME: only the private imports from the current source file. // FIXME: ImportFilterKind::ShadowedByCrossImportOverlay? - SmallVector mainImports; + SmallVector mainImports; main->getImportedModules(mainImports, {ModuleDecl::ImportFilterKind::Default, ModuleDecl::ImportFilterKind::ImplementationOnly}); @@ -384,7 +384,7 @@ ImportDepth::ImportDepth(ASTContext &context, } // Add imports to the worklist. - SmallVector imports; + SmallVector imports; module->getImportedModules(imports); for (auto &import : imports) { uint8_t next = std::max(depth, uint8_t(depth + 1)); // unsigned wrap diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp index e90b71447c525..2620dfb3be2bb 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp @@ -754,7 +754,7 @@ static void collectModuleDependencies(ModuleDecl *TopMod, ImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; } // FIXME: ImportFilterKind::ShadowedByCrossImportOverlay? - SmallVector Imports; + SmallVector Imports; TopMod->getImportedModules(Imports, ImportFilter); for (auto Import : Imports) { diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index 2bc1c5206ab80..d0d874bbc2d17 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -3176,7 +3176,7 @@ static int doPrintModuleImports(const CompilerInvocation &InitInvok, continue; } - SmallVector scratch; + SmallVector scratch; for (auto next : namelookup::getAllImports(M)) { llvm::outs() << next.importedModule->getName(); if (next.importedModule->isNonSwiftModule())