From 453667f65972599efcce833677c12335b0da2ed2 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 17 Mar 2020 10:27:09 -0700 Subject: [PATCH 1/4] [Frontend] Validate ImplicitImportModuleNames early Check whether the user has provided a valid identifier when parsing the options. Also make ImplicitImportModuleNames a private member of FrontendOptions to prevent mutation after being parsed. --- include/swift/Frontend/FrontendOptions.h | 12 +++++++++--- lib/Frontend/ArgsToFrontendOptionsConverter.cpp | 8 +++++++- lib/Frontend/Frontend.cpp | 2 +- .../lib/SwiftLang/CodeCompletionOrganizer.cpp | 2 +- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 81f72772239a0..fc83b750579d6 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -33,6 +33,9 @@ namespace swift { class FrontendOptions { friend class ArgsToFrontendOptionsConverter; + /// A list of arbitrary modules to import and make implicitly visible. + std::vector ImplicitImportModuleNames; + public: FrontendInputsAndOutputs InputsAndOutputs; @@ -44,9 +47,6 @@ class FrontendOptions { bool isOutputFileDirectory() const; - /// A list of arbitrary modules to import and make implicitly visible. - std::vector ImplicitImportModuleNames; - /// An Objective-C header to import and make implicitly visible. std::string ImplicitObjCHeaderPath; @@ -322,6 +322,12 @@ class FrontendOptions { const PrimarySpecificPaths & getPrimarySpecificPathsForPrimary(StringRef) const; + /// Retrieves the list of arbitrary modules to import and make implicitly + /// visible. + ArrayRef getImplicitImportModuleNames() const { + return ImplicitImportModuleNames; + } + private: static bool canActionEmitDependencies(ActionType); static bool canActionEmitReferenceDependencies(ActionType); diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index ee15319517670..e45159868a946 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -564,7 +564,13 @@ void ArgsToFrontendOptionsConverter::computeImportObjCHeaderOptions() { void ArgsToFrontendOptionsConverter::computeImplicitImportModuleNames() { using namespace options; for (const Arg *A : Args.filtered(OPT_import_module)) { - Opts.ImplicitImportModuleNames.push_back(A->getValue()); + 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); } } void ArgsToFrontendOptionsConverter::computeLLVMArgs() { diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index b162e549d05fe..76a1034c0d092 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -882,7 +882,7 @@ void CompilerInstance::getImplicitlyImportedModules( SmallVectorImpl &importModules) { FrontendStatsTracer tracer(getStatsReporter(), "get-implicitly-imported-modules"); for (auto &ImplicitImportModuleName : - Invocation.getFrontendOptions().ImplicitImportModuleNames) { + Invocation.getFrontendOptions().getImplicitImportModuleNames()) { if (Lexer::isIdentifier(ImplicitImportModuleName)) { auto moduleID = Context->getIdentifier(ImplicitImportModuleName); ModuleDecl *importModule = diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp index 5cd60485842d7..44cb9287a7116 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp @@ -337,7 +337,7 @@ ImportDepth::ImportDepth(ASTContext &context, // specially by applying import depth 0. llvm::StringSet<> auxImports; for (StringRef moduleName : - invocation.getFrontendOptions().ImplicitImportModuleNames) + invocation.getFrontendOptions().getImplicitImportModuleNames()) auxImports.insert(moduleName); // Private imports from this module. From 7f8a0e8a6cf2e9ea62695f7a50259ef017d553c2 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 17 Mar 2020 10:27:09 -0700 Subject: [PATCH 2/4] Requestify implicit imports Add ModuleImplicitImportsRequest, which computes the modules that should be implicitly imported by each file of a given module. Use this request in import resolution to add all the necessary implicit imports. The request computes the implicit imports by consulting the ImplicitImportInfo, which ModuleDecl can now be created with. This allows us to remove uses of `SourceFile::addImports` in favor of adding modules needed to be implicitly imported to the ImplicitImportInfo. --- include/swift/AST/ASTTypeIDZone.def | 1 + include/swift/AST/ASTTypeIDs.h | 1 + include/swift/AST/DiagnosticsCommon.def | 4 + include/swift/AST/DiagnosticsFrontend.def | 2 - include/swift/AST/Module.h | 61 +++++- include/swift/AST/SourceFile.h | 11 +- include/swift/AST/TypeCheckRequests.h | 40 ++++ include/swift/AST/TypeCheckerTypeIDZone.def | 2 + include/swift/Frontend/Frontend.h | 41 +--- lib/AST/Module.cpp | 47 ++--- lib/AST/TypeCheckRequests.cpp | 10 + lib/Frontend/Frontend.cpp | 216 ++++++-------------- lib/IDE/CompletionInstance.cpp | 13 +- lib/IDE/REPLCodeCompletion.cpp | 34 ++- lib/Immediate/REPL.cpp | 37 ++-- lib/Parse/Parser.cpp | 3 +- lib/Sema/ImportResolution.cpp | 89 +++++++- lib/Sema/SourceLoader.cpp | 12 +- unittests/AST/TestContext.cpp | 5 +- 19 files changed, 334 insertions(+), 295 deletions(-) diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def index 0a49cbc03c8eb..103b382e9ba50 100644 --- a/include/swift/AST/ASTTypeIDZone.def +++ b/include/swift/AST/ASTTypeIDZone.def @@ -19,6 +19,7 @@ SWIFT_TYPEID(AncestryFlags) SWIFT_TYPEID(CtorInitializerKind) SWIFT_TYPEID(FunctionBuilderBodyPreCheck) SWIFT_TYPEID(GenericSignature) +SWIFT_TYPEID(ImplicitImport) SWIFT_TYPEID(ImplicitMemberAction) SWIFT_TYPEID(ParamSpecifier) SWIFT_TYPEID(PropertyWrapperBackingPropertyInfo) diff --git a/include/swift/AST/ASTTypeIDs.h b/include/swift/AST/ASTTypeIDs.h index 5adba9595746c..c4bebdfade92b 100644 --- a/include/swift/AST/ASTTypeIDs.h +++ b/include/swift/AST/ASTTypeIDs.h @@ -36,6 +36,7 @@ class GenericTypeParamType; class InfixOperatorDecl; class IterableDeclContext; class ModuleDecl; +struct ImplicitImport; class NamedPattern; class NominalTypeDecl; class OperatorDecl; diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index a5bebe4123280..954363a3fdef6 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -90,6 +90,10 @@ ERROR(attr_only_on_parameters, none, ERROR(function_type_no_parens,none, "single argument function types require parentheses", ()) +// Used by both the Frontend and Sema. +ERROR(error_underlying_module_not_found,none, + "underlying Objective-C module %0 not found", (Identifier)) + // Used by -verify-generic-signatures ERROR(generic_signature_not_minimal,none, "generic requirement '%0' is redundant in %1", (StringRef, StringRef)) diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 4ed1d7a62d92e..7294b0a274344 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -138,8 +138,6 @@ ERROR(error_stdlib_module_name,none, ERROR(error_stdlib_not_found,Fatal, "unable to load standard library for target '%0'", (StringRef)) -ERROR(error_underlying_module_not_found,none, - "underlying Objective-C module %0 not found", (Identifier)) ERROR(error_unable_to_load_supplementary_output_file_map, none, "unable to load supplementary output file map '%0': %1", diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index ea7ee3c24b85d..d127620e12fb8 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -59,6 +59,7 @@ namespace swift { class FuncDecl; class InfixOperatorDecl; class LinkLibrary; + struct ImplicitImport; class ModuleLoader; class NominalTypeDecl; class EnumElementDecl; @@ -158,6 +159,42 @@ 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. @@ -245,6 +282,10 @@ class ModuleDecl : public DeclContext, public TypeDecl { llvm::SmallDenseMap> declaredCrossImports; + /// A description of what should be implicitly imported by each file of this + /// module. + const ImplicitImportInfo ImportInfo; + std::unique_ptr Cache; SourceLookupCache &getSourceLookupCache() const; @@ -274,15 +315,29 @@ class ModuleDecl : public DeclContext, public TypeDecl { /// \see EntryPointInfoTy EntryPointInfoTy EntryPointInfo; - ModuleDecl(Identifier name, ASTContext &ctx); + ModuleDecl(Identifier name, ASTContext &ctx, ImplicitImportInfo importInfo); public: - static ModuleDecl *create(Identifier name, ASTContext &ctx) { - return new (ctx) ModuleDecl(name, ctx); + /// Creates a new module with a given \p name. + /// + /// \param importInfo Information about which modules should be implicitly + /// imported by each file of this module. + static ModuleDecl * + create(Identifier name, ASTContext &ctx, + ImplicitImportInfo importInfo = ImplicitImportInfo()) { + return new (ctx) ModuleDecl(name, ctx, importInfo); } using Decl::getASTContext; + /// Retrieves information about which modules are implicitly imported by + /// each file of this module. + const ImplicitImportInfo &getImplicitImportInfo() const { return ImportInfo; } + + /// Retrieve a list of modules that each file of this module implicitly + /// imports. + ArrayRef getImplicitImports() const; + ArrayRef getFiles() { return Files; } diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index b3fcb9ac66973..c219d82bc0bf0 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -33,13 +33,6 @@ class SourceFile final : public FileUnit { class Impl; struct SourceFileSyntaxInfo; - /// The implicit module import that the SourceFile should get. - enum class ImplicitModuleImportKind { - None, - Builtin, - Stdlib - }; - /// Possible attributes for imports in source files. enum class ImportFlags { /// The imported module is exposed to anyone who imports the parent module. @@ -335,8 +328,8 @@ class SourceFile final : public FileUnit { llvm::StringMap getInfoForUsedFilePaths() const; SourceFile(ModuleDecl &M, SourceFileKind K, Optional bufferID, - ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens = false, - bool KeepSyntaxTree = false, ParsingOptions parsingOpts = {}); + bool KeepParsedTokens = false, bool KeepSyntaxTree = false, + ParsingOptions parsingOpts = {}); ~SourceFile(); diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index ee53927a86ebd..202a12b212847 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -23,6 +23,7 @@ #include "swift/AST/Evaluator.h" #include "swift/AST/Pattern.h" #include "swift/AST/SimpleRequest.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeResolutionStage.h" #include "swift/Basic/AnyValue.h" #include "swift/Basic/Statistic.h" @@ -2344,6 +2345,45 @@ 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 *), + RequestFlags::Cached> { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + ArrayRef + evaluate(Evaluator &evaluator, ModuleDecl *module) const; + +public: + // Cached. + bool isCached() const { return true; } +}; + // Allow AnyValue to compare two Type values, even though Type doesn't // support ==. template<> diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index ea2ffdf7144a3..b86811ae0981a 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -128,6 +128,8 @@ SWIFT_REQUEST(TypeChecker, ValidatePrecedenceGroupRequest, Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, MangleLocalTypeDeclRequest, std::string(const TypeDecl *), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, ModuleImplicitImportsRequest, + ArrayRef(ModuleDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, NamingPatternRequest, NamedPattern *(VarDecl *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, OpaqueReadOwnershipRequest, diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 7718407233f5d..a1b2197fd13a9 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -335,14 +335,15 @@ class CompilerInvocation { /// in generating a cached PCH file for the bridging header. std::string getPCHHash() const; - SourceFile::ImplicitModuleImportKind getImplicitModuleImportKind() const { + /// Retrieve the stdlib kind to implicitly import. + ImplicitStdlibKind getImplicitStdlibKind() const { if (getInputKind() == InputFileKind::SIL) { - return SourceFile::ImplicitModuleImportKind::None; + return ImplicitStdlibKind::None; } if (getParseStdlib()) { - return SourceFile::ImplicitModuleImportKind::Builtin; + return ImplicitStdlibKind::Builtin; } - return SourceFile::ImplicitModuleImportKind::Stdlib; + return ImplicitStdlibKind::Stdlib; } /// Performs input setup common to these tools: @@ -654,7 +655,6 @@ class CompilerInstance { private: SourceFile * createSourceFileForMainModule(SourceFileKind FileKind, - SourceFile::ImplicitModuleImportKind ImportKind, Optional BufferID, SourceFile::ParsingOptions options = {}); @@ -667,38 +667,17 @@ class CompilerInstance { private: /// Load stdlib & return true if should continue, i.e. no error bool loadStdlib(); - ModuleDecl *importUnderlyingModule(); - ModuleDecl *importBridgingHeader(); - void - getImplicitlyImportedModules(SmallVectorImpl &importModules); - -public: // for static functions in Frontend.cpp - struct ImplicitImports { - SourceFile::ImplicitModuleImportKind kind; - ModuleDecl *objCModuleUnderlyingMixedFramework; - ModuleDecl *headerModule; - SmallVector modules; - - explicit ImplicitImports(CompilerInstance &compiler); - }; - - static void addAdditionalInitialImportsTo( - SourceFile *SF, const ImplicitImports &implicitImports); - -private: - void addMainFileToModule(const ImplicitImports &implicitImports); + /// Retrieve a description of which modules should be implicitly imported. + ImplicitImportInfo getImplicitImportInfo() const; void performSemaUpTo(SourceFile::ASTStage_t LimitStage); - void parseAndCheckTypesUpTo(const ImplicitImports &implicitImports, - SourceFile::ASTStage_t LimitStage); + void parseAndCheckTypesUpTo(SourceFile::ASTStage_t LimitStage); - void parseLibraryFile(unsigned BufferID, - const ImplicitImports &implicitImports); + void parseLibraryFile(unsigned BufferID); /// Return true if had load error - bool - parsePartialModulesAndLibraryFiles(const ImplicitImports &implicitImports); + bool parsePartialModulesAndLibraryFiles(); void forEachFileToTypeCheck(llvm::function_ref fn); diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 6399871c0f737..0dad2439f4ee8 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -464,9 +464,11 @@ void SourceLookupCache::invalidate() { // Module Implementation //===----------------------------------------------------------------------===// -ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx) - : DeclContext(DeclContextKind::Module, nullptr), - TypeDecl(DeclKind::Module, &ctx, name, SourceLoc(), { }) { +ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx, + ImplicitImportInfo importInfo) + : DeclContext(DeclContextKind::Module, nullptr), + TypeDecl(DeclKind::Module, &ctx, name, SourceLoc(), {}), + ImportInfo(importInfo) { ctx.addDestructorCleanup(*this); setImplicit(); @@ -475,6 +477,13 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx) setAccess(AccessLevel::Public); } +ArrayRef ModuleDecl::getImplicitImports() const { + auto &evaluator = getASTContext().evaluator; + auto *mutableThis = const_cast(this); + return evaluateOrDefault(evaluator, ModuleImplicitImportsRequest{mutableThis}, + {}); +} + bool ModuleDecl::isClangModule() const { return findUnderlyingClangModule() != nullptr; } @@ -2245,36 +2254,6 @@ SourceFile::getCachedVisibleDecls() const { return getCache().AllVisibleValues; } -static void performAutoImport( - SourceFile &SF, - SourceFile::ImplicitModuleImportKind implicitModuleImportKind) { - if (SF.Kind == SourceFileKind::SIL) - assert(implicitModuleImportKind == - SourceFile::ImplicitModuleImportKind::None); - - ASTContext &Ctx = SF.getASTContext(); - ModuleDecl *M = nullptr; - - switch (implicitModuleImportKind) { - case SourceFile::ImplicitModuleImportKind::None: - return; - case SourceFile::ImplicitModuleImportKind::Builtin: - M = Ctx.TheBuiltinModule; - break; - case SourceFile::ImplicitModuleImportKind::Stdlib: - M = Ctx.getStdlibModule(true); - break; - } - - assert(M && "unable to auto-import module"); - - // FIXME: These will be the same for most source files, but we copy them - // over and over again. - auto Imports = SourceFile::ImportedModuleDesc( - ModuleDecl::ImportedModule({}, M), SourceFile::ImportOptions()); - SF.addImports(Imports); -} - llvm::StringMap SourceFile::getInfoForUsedFilePaths() const { llvm::StringMap result; @@ -2415,14 +2394,12 @@ ModuleDecl::computeMagicFileStringMap(bool shouldDiagnose) const { SourceFile::SourceFile(ModuleDecl &M, SourceFileKind K, Optional bufferID, - ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens, bool BuildSyntaxTree, ParsingOptions parsingOpts) : FileUnit(FileUnitKind::Source, M), BufferID(bufferID ? *bufferID : -1), ParsingOpts(parsingOpts), Kind(K), SyntaxInfo(new SourceFileSyntaxInfo(BuildSyntaxTree)) { M.getASTContext().addDestructorCleanup(*this); - performAutoImport(*this, ModImpKind); if (isScriptMode()) { bool problem = M.registerEntryPointFile(this, SourceLoc(), None); diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 2f4c907fad789..426f21baf5625 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -1499,3 +1499,13 @@ TypeCheckFunctionBodyUntilRequest::readDependencySource(Evaluator &e) const { evaluator::DependencyScope::Private }; } + +//----------------------------------------------------------------------------// +// ModuleImplicitImportsRequest computation. +//----------------------------------------------------------------------------// + +void swift::simple_display(llvm::raw_ostream &out, + const ImplicitImport &import) { + out << "implicit import of "; + simple_display(out, import.Module); +} diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 76a1034c0d092..37eaf7cdb4330 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -692,57 +692,13 @@ std::unique_ptr CompilerInstance::takeSILModule() { return std::move(TheSILModule); } -ModuleDecl *CompilerInstance::getMainModule() const { - if (!MainModule) { - Identifier ID = Context->getIdentifier(Invocation.getModuleName()); - MainModule = ModuleDecl::create(ID, *Context); - if (Invocation.getFrontendOptions().EnableTesting) - MainModule->setTestingEnabled(); - if (Invocation.getFrontendOptions().EnablePrivateImports) - MainModule->setPrivateImportsEnabled(); - if (Invocation.getFrontendOptions().EnableImplicitDynamic) - MainModule->setImplicitDynamicEnabled(); - - if (Invocation.getFrontendOptions().EnableLibraryEvolution) - MainModule->setResilienceStrategy(ResilienceStrategy::Resilient); - } - return MainModule; -} - -void CompilerInstance::addAdditionalInitialImportsTo( - SourceFile *SF, const CompilerInstance::ImplicitImports &implicitImports) { - SmallVector additionalImports; - - if (implicitImports.objCModuleUnderlyingMixedFramework) - additionalImports.push_back(SourceFile::ImportedModuleDesc( - ModuleDecl::ImportedModule( - /*accessPath=*/{}, - implicitImports.objCModuleUnderlyingMixedFramework), - SourceFile::ImportFlags::Exported)); - if (implicitImports.headerModule) - additionalImports.push_back(SourceFile::ImportedModuleDesc( - ModuleDecl::ImportedModule(/*accessPath=*/{}, - implicitImports.headerModule), - SourceFile::ImportFlags::Exported)); - if (!implicitImports.modules.empty()) { - for (auto &importModule : implicitImports.modules) { - additionalImports.push_back(SourceFile::ImportedModuleDesc( - ModuleDecl::ImportedModule(/*accessPath=*/{}, importModule), - SourceFile::ImportOptions())); - } - } - - SF->addImports(additionalImports); -} - /// Implicitly import the SwiftOnoneSupport module in non-optimized /// builds. This allows for use of popular specialized functions /// from the standard library, which makes the non-optimized builds /// execute much faster. -static bool -shouldImplicityImportSwiftOnoneSupportModule(CompilerInvocation &Invocation) { - if (Invocation.getImplicitModuleImportKind() != - SourceFile::ImplicitModuleImportKind::Stdlib) +static bool shouldImplicityImportSwiftOnoneSupportModule( + const CompilerInvocation &Invocation) { + if (Invocation.getImplicitStdlibKind() != ImplicitStdlibKind::Stdlib) return false; if (Invocation.getSILOptions().shouldOptimize()) return false; @@ -764,6 +720,40 @@ shouldImplicityImportSwiftOnoneSupportModule(CompilerInvocation &Invocation) { || FrontendOptions::doesActionGenerateSIL(options.RequestedAction); } +ImplicitImportInfo CompilerInstance::getImplicitImportInfo() const { + auto &frontendOpts = Invocation.getFrontendOptions(); + + ImplicitImportInfo imports; + imports.StdlibKind = Invocation.getImplicitStdlibKind(); + + for (auto &moduleStr : frontendOpts.getImplicitImportModuleNames()) + imports.ModuleNames.push_back(Context->getIdentifier(moduleStr)); + + if (shouldImplicityImportSwiftOnoneSupportModule(Invocation)) + imports.ModuleNames.push_back(Context->getIdentifier(SWIFT_ONONE_SUPPORT)); + + imports.ShouldImportUnderlyingModule = frontendOpts.ImportUnderlyingModule; + imports.BridgingHeaderPath = frontendOpts.ImplicitObjCHeaderPath; + return imports; +} + +ModuleDecl *CompilerInstance::getMainModule() const { + if (!MainModule) { + Identifier ID = Context->getIdentifier(Invocation.getModuleName()); + MainModule = ModuleDecl::create(ID, *Context, getImplicitImportInfo()); + if (Invocation.getFrontendOptions().EnableTesting) + MainModule->setTestingEnabled(); + if (Invocation.getFrontendOptions().EnablePrivateImports) + MainModule->setPrivateImportsEnabled(); + if (Invocation.getFrontendOptions().EnableImplicitDynamic) + MainModule->setImplicitDynamicEnabled(); + + if (Invocation.getFrontendOptions().EnableLibraryEvolution) + MainModule->setResilienceStrategy(ResilienceStrategy::Resilient); + } + return MainModule; +} + void CompilerInstance::performParseAndResolveImportsOnly() { performSemaUpTo(SourceFile::ImportsResolved); } @@ -787,49 +777,33 @@ void CompilerInstance::performSemaUpTo(SourceFile::ASTStage_t LimitStage) { createSILModule(); } - if (Invocation.getImplicitModuleImportKind() == - SourceFile::ImplicitModuleImportKind::Stdlib) { + if (Invocation.getImplicitStdlibKind() == ImplicitStdlibKind::Stdlib) { if (!loadStdlib()) return; } - if (shouldImplicityImportSwiftOnoneSupportModule(Invocation)) { - Invocation.getFrontendOptions().ImplicitImportModuleNames.push_back( - SWIFT_ONONE_SUPPORT.str()); - } - const ImplicitImports implicitImports(*this); + // Force loading implicit imports. This is currently needed to allow + // deserialization to resolve cross references into bridging headers. + // FIXME: Once deserialization loads all the modules it needs for cross + // references, this can be removed. + (void)MainModule->getImplicitImports(); if (Invocation.getInputKind() == InputFileKind::SwiftREPL) { // Create the initial empty REPL file. This only exists to feed in the // implicit imports such as the standard library. - auto *replFile = createSourceFileForMainModule( - SourceFileKind::REPL, implicitImports.kind, /*BufferID*/ None); - addAdditionalInitialImportsTo(replFile, implicitImports); - - // Given this file is empty, we can go ahead and just mark it as having been - // type checked. - replFile->ASTStage = SourceFile::TypeChecked; + auto *replFile = + createSourceFileForMainModule(SourceFileKind::REPL, /*BufferID*/ None); + performImportResolution(*replFile); return; } // Make sure the main file is the first file in the module, so do this now. - if (MainBufferID != NO_SUCH_BUFFER) - addMainFileToModule(implicitImports); - - parseAndCheckTypesUpTo(implicitImports, LimitStage); -} - -CompilerInstance::ImplicitImports::ImplicitImports(CompilerInstance &compiler) { - kind = compiler.Invocation.getImplicitModuleImportKind(); - - objCModuleUnderlyingMixedFramework = - compiler.Invocation.getFrontendOptions().ImportUnderlyingModule - ? compiler.importUnderlyingModule() - : nullptr; - - compiler.getImplicitlyImportedModules(modules); + if (MainBufferID != NO_SUCH_BUFFER) { + (void)createSourceFileForMainModule(Invocation.getSourceFileKind(), + MainBufferID); + } - headerModule = compiler.importBridgingHeader(); + parseAndCheckTypesUpTo(LimitStage); } bool CompilerInstance::loadStdlib() { @@ -851,72 +825,11 @@ bool CompilerInstance::loadStdlib() { return true; } -ModuleDecl *CompilerInstance::importUnderlyingModule() { - FrontendStatsTracer tracer(getStatsReporter(), "import-underlying-module"); - ModuleDecl *objCModuleUnderlyingMixedFramework = - static_cast(Context->getClangModuleLoader()) - ->loadModule(SourceLoc(), - { Located(MainModule->getName(), SourceLoc()) }); - if (objCModuleUnderlyingMixedFramework) - return objCModuleUnderlyingMixedFramework; - Diagnostics.diagnose(SourceLoc(), diag::error_underlying_module_not_found, - MainModule->getName()); - return nullptr; -} - -ModuleDecl *CompilerInstance::importBridgingHeader() { - FrontendStatsTracer tracer(getStatsReporter(), "import-bridging-header"); - const StringRef implicitHeaderPath = - Invocation.getFrontendOptions().ImplicitObjCHeaderPath; - auto clangImporter = - static_cast(Context->getClangModuleLoader()); - if (implicitHeaderPath.empty() || - clangImporter->importBridgingHeader(implicitHeaderPath, MainModule)) - return nullptr; - ModuleDecl *importedHeaderModule = clangImporter->getImportedHeaderModule(); - assert(importedHeaderModule); - return importedHeaderModule; -} - -void CompilerInstance::getImplicitlyImportedModules( - SmallVectorImpl &importModules) { - FrontendStatsTracer tracer(getStatsReporter(), "get-implicitly-imported-modules"); - for (auto &ImplicitImportModuleName : - Invocation.getFrontendOptions().getImplicitImportModuleNames()) { - if (Lexer::isIdentifier(ImplicitImportModuleName)) { - auto moduleID = Context->getIdentifier(ImplicitImportModuleName); - ModuleDecl *importModule = - Context->getModule({ Located(moduleID, SourceLoc()) }); - if (importModule) { - importModules.push_back(importModule); - } else { - Diagnostics.diagnose(SourceLoc(), diag::sema_no_import, - ImplicitImportModuleName); - if (Invocation.getSearchPathOptions().SDKPath.empty() && - llvm::Triple(llvm::sys::getProcessTriple()).isMacOSX()) { - Diagnostics.diagnose(SourceLoc(), diag::sema_no_import_no_sdk); - Diagnostics.diagnose(SourceLoc(), diag::sema_no_import_no_sdk_xcrun); - } - } - } else { - Diagnostics.diagnose(SourceLoc(), diag::error_bad_module_name, - ImplicitImportModuleName, false); - } - } -} - -void CompilerInstance::addMainFileToModule( - const ImplicitImports &implicitImports) { - auto *MainFile = createSourceFileForMainModule( - Invocation.getSourceFileKind(), implicitImports.kind, MainBufferID); - addAdditionalInitialImportsTo(MainFile, implicitImports); -} - void CompilerInstance::parseAndCheckTypesUpTo( - const ImplicitImports &implicitImports, SourceFile::ASTStage_t limitStage) { + SourceFile::ASTStage_t limitStage) { FrontendStatsTracer tracer(getStatsReporter(), "parse-and-check-types"); - bool hadLoadError = parsePartialModulesAndLibraryFiles(implicitImports); + bool hadLoadError = parsePartialModulesAndLibraryFiles(); if (Invocation.isCodeCompletion()) { // When we are doing code completion, make sure to emit at least one // diagnostic, so that ASTContext is marked as erroneous. In this case @@ -972,20 +885,17 @@ void CompilerInstance::parseAndCheckTypesUpTo( finishTypeChecking(); } -void CompilerInstance::parseLibraryFile( - unsigned BufferID, const ImplicitImports &implicitImports) { +void CompilerInstance::parseLibraryFile(unsigned BufferID) { FrontendStatsTracer tracer(getStatsReporter(), "parse-library-file"); - auto *NextInput = createSourceFileForMainModule( - SourceFileKind::Library, implicitImports.kind, BufferID); - addAdditionalInitialImportsTo(NextInput, implicitImports); + auto *NextInput = + createSourceFileForMainModule(SourceFileKind::Library, BufferID); // Import resolution will lazily trigger parsing of the file. performImportResolution(*NextInput); } -bool CompilerInstance::parsePartialModulesAndLibraryFiles( - const ImplicitImports &implicitImports) { +bool CompilerInstance::parsePartialModulesAndLibraryFiles() { FrontendStatsTracer tracer(getStatsReporter(), "parse-partial-modules-and-library-files"); bool hadLoadError = false; @@ -1002,7 +912,7 @@ bool CompilerInstance::parsePartialModulesAndLibraryFiles( // Then parse all the library files. for (auto BufferID : InputSourceCodeBufferIDs) { if (BufferID != MainBufferID) { - parseLibraryFile(BufferID, implicitImports); + parseLibraryFile(BufferID); } } return hadLoadError; @@ -1077,8 +987,8 @@ void CompilerInstance::finishTypeChecking() { } SourceFile *CompilerInstance::createSourceFileForMainModule( - SourceFileKind fileKind, SourceFile::ImplicitModuleImportKind importKind, - Optional bufferID, SourceFile::ParsingOptions opts) { + SourceFileKind fileKind, Optional bufferID, + SourceFile::ParsingOptions opts) { ModuleDecl *mainModule = getMainModule(); auto isPrimary = bufferID && isPrimaryInput(*bufferID); @@ -1092,7 +1002,7 @@ SourceFile *CompilerInstance::createSourceFileForMainModule( } SourceFile *inputFile = new (*Context) - SourceFile(*mainModule, fileKind, bufferID, importKind, + SourceFile(*mainModule, fileKind, bufferID, Invocation.getLangOptions().CollectParsedToken, Invocation.getLangOptions().BuildSyntaxTree, opts); MainModule->addFile(*inputFile); @@ -1132,7 +1042,6 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals, assert(Kind == InputFileKind::Swift || Kind == InputFileKind::SwiftModuleInterface); createSourceFileForMainModule(Invocation.getSourceFileKind(), - SourceFile::ImplicitModuleImportKind::None, MainBufferID, parsingOpts); } @@ -1142,8 +1051,7 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals, continue; SourceFile *NextInput = createSourceFileForMainModule( - SourceFileKind::Library, SourceFile::ImplicitModuleImportKind::None, - BufferID, parsingOpts); + SourceFileKind::Library, BufferID, parsingOpts); // Force the parsing of the top level decls. (void)NextInput->getTopLevelDecls(); diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 546aa36ffa0ce..cb3f8c965b577 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -208,9 +208,7 @@ bool CompletionInstance::performCachedOperationIfPossible( registerTypeCheckerRequestFunctions(tmpCtx->evaluator); registerSILGenRequestFunctions(tmpCtx->evaluator); ModuleDecl *tmpM = ModuleDecl::create(Identifier(), *tmpCtx); - SourceFile *tmpSF = - new (*tmpCtx) SourceFile(*tmpM, oldSF->Kind, tmpBufferID, - SourceFile::ImplicitModuleImportKind::None); + SourceFile *tmpSF = new (*tmpCtx) SourceFile(*tmpM, oldSF->Kind, tmpBufferID); tmpSF->enableInterfaceHash(); // Ensure all non-function-body tokens are hashed into the interface hash tmpCtx->LangOpts.EnableTypeFingerprints = false; @@ -318,12 +316,11 @@ bool CompletionInstance::performCachedOperationIfPossible( // Create a new module and a source file using the current AST context. auto &Ctx = oldM->getASTContext(); - auto newM = ModuleDecl::create(oldM->getName(), Ctx); - CompilerInstance::ImplicitImports implicitImport(CI); - SourceFile *newSF = new (Ctx) SourceFile(*newM, SourceFileKind::Main, - newBufferID, implicitImport.kind); + auto *newM = + ModuleDecl::create(oldM->getName(), Ctx, oldM->getImplicitImportInfo()); + auto *newSF = + new (Ctx) SourceFile(*newM, SourceFileKind::Main, newBufferID); newM->addFile(*newSF); - CompilerInstance::addAdditionalInitialImportsTo(newSF, implicitImport); newSF->enableInterfaceHash(); // Tell the compiler instance we've replaced the code completion file. diff --git a/lib/IDE/REPLCodeCompletion.cpp b/lib/IDE/REPLCodeCompletion.cpp index 79e49dcc7dca1..70fc52edd8e5a 100644 --- a/lib/IDE/REPLCodeCompletion.cpp +++ b/lib/IDE/REPLCodeCompletion.cpp @@ -210,34 +210,30 @@ doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID, Ctx.SourceMgr.setCodeCompletionPoint(*BufferID, CodeCompletionOffset); - // Create a new module and file for the code completion buffer, similar to how - // we handle new lines of REPL input. - auto *newModule = - ModuleDecl::create(Ctx.getIdentifier("REPL_Code_Completion"), Ctx); - auto &newSF = - *new (Ctx) SourceFile(*newModule, SourceFileKind::REPL, *BufferID, - SourceFile::ImplicitModuleImportKind::None); - newModule->addFile(newSF); - // Import the last module. auto *lastModule = SF.getParentModule(); - ModuleDecl::ImportedModule importOfLastModule{/*AccessPath*/ {}, lastModule}; - newSF.addImports(SourceFile::ImportedModuleDesc(importOfLastModule, - SourceFile::ImportOptions())); + + ImplicitImportInfo implicitImports; + implicitImports.AdditionalModules.emplace_back(lastModule, + /*exported*/ false); // Carry over the private imports from the last module. SmallVector imports; lastModule->getImportedModules(imports, ModuleDecl::ImportFilterKind::Private); - if (!imports.empty()) { - SmallVector importsWithOptions; - for (auto &import : imports) { - importsWithOptions.emplace_back( - SourceFile::ImportedModuleDesc(import, SourceFile::ImportOptions())); - } - newSF.addImports(importsWithOptions); + for (auto &import : imports) { + implicitImports.AdditionalModules.emplace_back(import.second, + /*exported*/ false); } + // Create a new module and file for the code completion buffer, similar to how + // we handle new lines of REPL input. + auto *newModule = ModuleDecl::create( + Ctx.getIdentifier("REPL_Code_Completion"), Ctx, implicitImports); + auto &newSF = + *new (Ctx) SourceFile(*newModule, SourceFileKind::REPL, *BufferID); + newModule->addFile(newSF); + performImportResolution(newSF); bindExtensions(newSF); diff --git a/lib/Immediate/REPL.cpp b/lib/Immediate/REPL.cpp index b08ad619bde41..581a0885584c7 100644 --- a/lib/Immediate/REPL.cpp +++ b/lib/Immediate/REPL.cpp @@ -161,34 +161,29 @@ static void convertToUTF8(llvm::ArrayRef wide, static ModuleDecl * typeCheckREPLInput(ModuleDecl *MostRecentModule, StringRef Name, std::unique_ptr Buffer) { - using ImplicitModuleImportKind = SourceFile::ImplicitModuleImportKind; assert(MostRecentModule); ASTContext &Ctx = MostRecentModule->getASTContext(); - auto REPLModule = ModuleDecl::create(Ctx.getIdentifier(Name), Ctx); - auto BufferID = Ctx.SourceMgr.addNewSourceBuffer(std::move(Buffer)); - auto ImportKind = ImplicitModuleImportKind::None; - auto &REPLInputFile = *new (Ctx) SourceFile(*REPLModule, SourceFileKind::REPL, - BufferID, ImportKind); - REPLModule->addFile(REPLInputFile); - - ModuleDecl::ImportedModule ImportOfMostRecentModule{ - /*AccessPath*/{}, MostRecentModule}; - REPLInputFile.addImports(SourceFile::ImportedModuleDesc( - ImportOfMostRecentModule, SourceFile::ImportOptions())); + // Import the last module. + ImplicitImportInfo implicitImports; + implicitImports.AdditionalModules.emplace_back(MostRecentModule, + /*exported*/ false); - SmallVector Imports; - MostRecentModule->getImportedModules(Imports, + // Carry over the private imports from the last module. + SmallVector imports; + MostRecentModule->getImportedModules(imports, ModuleDecl::ImportFilterKind::Private); - if (!Imports.empty()) { - SmallVector ImportsWithOptions; - for (auto Import : Imports) { - ImportsWithOptions.emplace_back(SourceFile::ImportedModuleDesc( - Import, SourceFile::ImportFlags::Exported)); - } - REPLInputFile.addImports(ImportsWithOptions); + for (auto &import : imports) { + implicitImports.AdditionalModules.emplace_back(import.second, + /*exported*/ true); } + auto *REPLModule = + ModuleDecl::create(Ctx.getIdentifier(Name), Ctx, implicitImports); + auto BufferID = Ctx.SourceMgr.addNewSourceBuffer(std::move(Buffer)); + auto &REPLInputFile = + *new (Ctx) SourceFile(*REPLModule, SourceFileKind::REPL, BufferID); + REPLModule->addFile(REPLInputFile); performTypeChecking(REPLInputFile); return REPLModule; } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 9ba7f122a18de..d3b1986dca317 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1190,8 +1190,7 @@ struct ParserUnit::Implementation { Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, SM, Diags)), SF(new (Ctx) SourceFile( *ModuleDecl::create(Ctx.getIdentifier(ModuleName), Ctx), SFKind, - BufferID, SourceFile::ImplicitModuleImportKind::None, - Opts.CollectParsedToken, Opts.BuildSyntaxTree, + BufferID, Opts.CollectParsedToken, Opts.BuildSyntaxTree, SourceFile::ParsingFlags::DisableDelayedBodies | SourceFile::ParsingFlags::DisablePoundIfEvaluation)) {} diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index e5865dae19288..7f686cfe46a52 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -193,7 +193,19 @@ class ImportResolver final : public DeclVisitor { size_t nextModuleToCrossImport = 0; public: - ImportResolver(SourceFile &SF) : SF(SF), ctx(SF.getASTContext()) {} + ImportResolver(SourceFile &SF) : SF(SF), ctx(SF.getASTContext()) { + addImplicitImports(); + } + + void addImplicitImports() { + // TODO: Support cross-module imports. + for (auto &import : SF.getParentModule()->getImplicitImports()) { + assert(!(SF.Kind == SourceFileKind::SIL && + import.Module->isStdlibModule())); + ImportedModule importedMod(/*accessPath*/ {}, import.Module); + boundImports.emplace_back(importedMod, import.Options); + } + } /// Retrieve the finalized imports. ArrayRef getFinishedImports() const { @@ -399,6 +411,81 @@ UnboundImport::getTopLevelModule(ModuleDecl *M, SourceFile &SF) { return topLevelModule; } +//===----------------------------------------------------------------------===// +// MARK: Implicit imports +//===----------------------------------------------------------------------===// + +ArrayRef +ModuleImplicitImportsRequest::evaluate(Evaluator &evaluator, + ModuleDecl *module) const { + SmallVector imports; + + auto &ctx = module->getASTContext(); + auto &importInfo = module->getImplicitImportInfo(); + + // Add an implicit stdlib if needed. + switch (importInfo.StdlibKind) { + case ImplicitStdlibKind::None: + break; + case ImplicitStdlibKind::Builtin: + imports.emplace_back(ctx.TheBuiltinModule); + break; + case ImplicitStdlibKind::Stdlib: { + auto *stdlib = ctx.getStdlibModule(/*loadIfAbsent*/ true); + assert(stdlib && "Missing stdlib?"); + imports.emplace_back(stdlib); + break; + } + } + + // Add any modules we were asked to implicitly import. + for (auto moduleName : importInfo.ModuleNames) { + auto *importModule = ctx.getModule({{moduleName, SourceLoc()}}); + 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); + } + + // Add any pre-loaded modules. + for (auto &module : importInfo.AdditionalModules) { + imports.emplace_back(module.first, module.second ? ImportFlags::Exported + : ImportOptions()); + } + + auto *clangImporter = + static_cast(ctx.getClangModuleLoader()); + + // Implicitly import the bridging header module if needed. + auto bridgingHeaderPath = importInfo.BridgingHeaderPath; + if (!bridgingHeaderPath.empty() && + !clangImporter->importBridgingHeader(bridgingHeaderPath, module)) { + auto *headerModule = clangImporter->getImportedHeaderModule(); + assert(headerModule && "Didn't load bridging header?"); + imports.emplace_back(headerModule, ImportFlags::Exported); + } + + // Implicitly import the underlying Clang half of this module if needed. + if (importInfo.ShouldImportUnderlyingModule) { + auto *underlyingMod = clangImporter->loadModule( + SourceLoc(), {Located(module->getName(), SourceLoc())}); + if (underlyingMod) { + imports.emplace_back(underlyingMod, ImportFlags::Exported); + } else { + ctx.Diags.diagnose(SourceLoc(), diag::error_underlying_module_not_found, + module->getName()); + } + } + + return ctx.AllocateCopy(imports); +} + //===----------------------------------------------------------------------===// // MARK: Import validation (except for scoped imports) //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SourceLoader.cpp b/lib/Sema/SourceLoader.cpp index 92d736f23c5c6..a1dfa86b9b14c 100644 --- a/lib/Sema/SourceLoader.cpp +++ b/lib/Sema/SourceLoader.cpp @@ -115,17 +115,17 @@ ModuleDecl *SourceLoader::loadModule(SourceLoc importLoc, else bufferID = Ctx.SourceMgr.addNewSourceBuffer(std::move(inputFile)); - auto *importMod = ModuleDecl::create(moduleID.Item, Ctx); + ImplicitImportInfo importInfo; + importInfo.StdlibKind = Ctx.getStdlibModule() ? ImplicitStdlibKind::Stdlib + : ImplicitStdlibKind::None; + + auto *importMod = ModuleDecl::create(moduleID.Item, Ctx, importInfo); if (EnableLibraryEvolution) importMod->setResilienceStrategy(ResilienceStrategy::Resilient); Ctx.LoadedModules[moduleID.Item] = importMod; - auto implicitImportKind = SourceFile::ImplicitModuleImportKind::Stdlib; - if (!Ctx.getStdlibModule()) - implicitImportKind = SourceFile::ImplicitModuleImportKind::None; - auto *importFile = new (Ctx) SourceFile(*importMod, SourceFileKind::Library, - bufferID, implicitImportKind, + bufferID, Ctx.LangOpts.CollectParsedToken, Ctx.LangOpts.BuildSyntaxTree); importMod->addFile(*importFile); diff --git a/unittests/AST/TestContext.cpp b/unittests/AST/TestContext.cpp index 49605a2fa2f19..eb2439f3bc27e 100644 --- a/unittests/AST/TestContext.cpp +++ b/unittests/AST/TestContext.cpp @@ -42,11 +42,8 @@ TestContext::TestContext(ShouldDeclareOptionalTypes optionals) auto *module = ModuleDecl::create(stdlibID, Ctx); Ctx.LoadedModules[stdlibID] = module; - using ImplicitModuleImportKind = SourceFile::ImplicitModuleImportKind; FileForLookups = new (Ctx) SourceFile(*module, SourceFileKind::Library, - /*buffer*/None, - ImplicitModuleImportKind::None, - /*keeps token*/false); + /*buffer*/ None, /*keeps token*/ false); module->addFile(*FileForLookups); if (optionals == DeclareOptionalTypes) { From b500f371fe6b825b41b6018d1f0acf315bff788e Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 17 Mar 2020 10:27:09 -0700 Subject: [PATCH 3/4] [Sema] Don't skip import resolution for empty file The associated comment appears to outdated. Make sure we continue to record implicit imports for empty files. --- lib/Sema/ImportResolution.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 7f686cfe46a52..876bec9e076a0 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -276,17 +276,12 @@ class ImportResolver final : public DeclVisitor { /// /// Import resolution operates on a parsed but otherwise unvalidated AST. void swift::performImportResolution(SourceFile &SF) { - FrontendStatsTracer tracer(SF.getASTContext().Stats, - "Import resolution"); - - // Make sure we skip adding the standard library imports if the - // source file is empty. - if (SF.ASTStage == SourceFile::ImportsResolved || - SF.getTopLevelDecls().empty()) { - SF.ASTStage = SourceFile::ImportsResolved; + // If we've already performed import resolution, bail. + if (SF.ASTStage == SourceFile::ImportsResolved) return; - } + FrontendStatsTracer tracer(SF.getASTContext().Stats, + "Import resolution"); ImportResolver resolver(SF); // Resolve each import declaration. From 92103a7c634d333a9b1c76b72125e8596eeef18c Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 14 Apr 2020 08:32:02 -0700 Subject: [PATCH 4/4] [AST] Remove SourceFile::addImports Temporarily replace with `SourceFile::setImports` until import resolution is requestified. Now imports are only set once for a given SourceFile. Because we're now asserting in more places that import resolution must have run before querying imports, this commit also adds `getCachedUnderlyingType` to TypeAliasDecl to stop the ASTDumper from trying to query imports for a -dump-parse invocation. --- include/swift/AST/Decl.h | 4 ++++ include/swift/AST/SourceFile.h | 8 +++++--- lib/AST/ASTDumper.cpp | 2 +- lib/AST/Module.cpp | 34 ++++++++++++++-------------------- lib/Sema/ImportResolution.cpp | 2 +- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 37d1980786131..ea92c738d39a0 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3032,6 +3032,10 @@ class TypeAliasDecl : public GenericTypeDecl { Type getUnderlyingType() const; void setUnderlyingType(Type type); + /// Returns the interface type of the underlying type if computed, null + /// otherwise. Should only be used for dumping. + Type getCachedUnderlyingType() const { return UnderlyingTy.getType(); } + /// For generic typealiases, return the unbound generic type. UnboundGenericType *getUnboundGenericType() const; diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index c219d82bc0bf0..3ca6abb78dae0 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -121,8 +121,8 @@ class SourceFile final : public FileUnit { /// This is the list of modules that are imported by this module. /// - /// This is filled in by the import resolution phase. - ArrayRef Imports; + /// This is \c None until it is filled in by the import resolution phase. + 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 @@ -333,7 +333,9 @@ class SourceFile final : public FileUnit { ~SourceFile(); - void addImports(ArrayRef IM); + /// Set the imports for this source file. This gets called by import + /// resolution. + void setImports(ArrayRef imports); enum ImportQueryKind { /// Return the results for testable or private imports. diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index dbd73c8776156..a2d864c93dae7 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -631,7 +631,7 @@ namespace { void visitTypeAliasDecl(TypeAliasDecl *TAD) { printCommon(TAD, "typealias"); PrintWithColorRAII(OS, TypeColor) << " type='"; - if (auto underlying = TAD->getUnderlyingType()) { + if (auto underlying = TAD->getCachedUnderlyingType()) { PrintWithColorRAII(OS, TypeColor) << underlying.getString(); } else { diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 0dad2439f4ee8..e4c80e2b86e47 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -1103,7 +1103,7 @@ class SourceFile::Impl { /// Only intended for use by lookupOperatorDeclForName. static ArrayRef getImportsForSourceFile(const SourceFile &SF) { - return SF.Imports; + return *SF.Imports; } }; @@ -1408,7 +1408,10 @@ SourceFile::getImportedModules(SmallVectorImpl &modu // We currently handle this for a direct import from the overlay, but not when // it happens through other imports. assert(filter && "no imports requested?"); - for (auto desc : Imports) { + if (!Imports) + return; + + for (auto desc : *Imports) { ModuleDecl::ImportFilter requiredFilter; if (desc.importOptions.contains(ImportFlags::Exported)) requiredFilter |= ModuleDecl::ImportFilterKind::Public; @@ -2036,23 +2039,14 @@ void SourceFile::print(ASTPrinter &Printer, const PrintOptions &PO) { } } -void SourceFile::addImports(ArrayRef IM) { - if (IM.empty()) - return; - ASTContext &ctx = getASTContext(); - auto newBuf = - ctx.AllocateUninitialized(Imports.size() + IM.size()); - - auto iter = newBuf.begin(); - iter = std::uninitialized_copy(Imports.begin(), Imports.end(), iter); - iter = std::uninitialized_copy(IM.begin(), IM.end(), iter); - assert(iter == newBuf.end()); - - Imports = newBuf; +void SourceFile::setImports(ArrayRef imports) { + assert(!Imports && "Already computed imports"); + Imports = getASTContext().AllocateCopy(imports); // Update the HasImplementationOnlyImports flag. + // TODO: Requestify this. if (!HasImplementationOnlyImports) { - for (auto &desc : IM) { + for (auto &desc : imports) { if (desc.importOptions.contains(ImportFlags::ImplementationOnly)) HasImplementationOnlyImports = true; } @@ -2070,7 +2064,7 @@ bool SourceFile::hasTestableOrPrivateImport( // filename does not need to match (and we don't serialize it for such // decls). return std::any_of( - Imports.begin(), Imports.end(), + Imports->begin(), Imports->end(), [module, queryKind](ImportedModuleDesc desc) -> bool { if (queryKind == ImportQueryKind::TestableAndPrivate) return desc.module.second == module && @@ -2112,7 +2106,7 @@ bool SourceFile::hasTestableOrPrivateImport( if (filename.empty()) return false; - return std::any_of(Imports.begin(), Imports.end(), + return std::any_of(Imports->begin(), Imports->end(), [module, filename](ImportedModuleDesc desc) -> bool { return desc.module.second == module && desc.importOptions.contains( @@ -2130,7 +2124,7 @@ bool SourceFile::isImportedImplementationOnly(const ModuleDecl *module) const { auto &imports = getASTContext().getImportCache(); // Look at the imports of this source file. - for (auto &desc : Imports) { + for (auto &desc : *Imports) { // Ignore implementation-only imports. if (desc.importOptions.contains(ImportFlags::ImplementationOnly)) continue; @@ -2147,7 +2141,7 @@ bool SourceFile::isImportedImplementationOnly(const ModuleDecl *module) const { void SourceFile::lookupImportedSPIGroups(const ModuleDecl *importedModule, SmallVectorImpl &spiGroups) const { - for (auto &import : Imports) { + for (auto &import : *Imports) { if (import.importOptions.contains(ImportFlags::SPIAccessControl) && importedModule == std::get(import.module)) { auto importedSpis = import.spiGroups; diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 876bec9e076a0..38a85685bc1aa 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -288,7 +288,7 @@ void swift::performImportResolution(SourceFile &SF) { for (auto D : SF.getTopLevelDecls()) resolver.visit(D); - SF.addImports(resolver.getFinishedImports()); + SF.setImports(resolver.getFinishedImports()); SF.ASTStage = SourceFile::ImportsResolved; verify(SF);