void CompilerInstance::performParseOnly() { const InputFileKind Kind = Invocation.getInputKind(); Module *MainModule = getMainModule(); Context->LoadedModules[MainModule->getName()] = MainModule; assert((Kind == InputFileKind::IFK_Swift || Kind == InputFileKind::IFK_Swift_Library) && "only supports parsing a single .swift file"); assert(BufferIDs.size() == 1 && "only supports parsing a single file"); if (Kind == InputFileKind::IFK_Swift) SourceMgr.setHashbangBufferID(BufferIDs[0]); auto *Input = new (*Context) SourceFile(*MainModule, Invocation.getSourceFileKind(), BufferIDs[0], SourceFile::ImplicitModuleImportKind::None); MainModule->addFile(*Input); setPrimarySourceFile(Input); PersistentParserState PersistentState; bool Done; do { // Pump the parser multiple times if necessary. It will return early // after parsing any top level code in a main module. parseIntoSourceFile(*Input, Input->getBufferID().getValue(), &Done, nullptr, &PersistentState, nullptr); } while (!Done); assert(Context->LoadedModules.size() == 1 && "Loaded a module during parse-only"); }
void CompilerInstance::performSema() { const FrontendOptions &options = Invocation.getFrontendOptions(); const InputFileKind Kind = Invocation.getInputKind(); Module *MainModule = getMainModule(); Context->LoadedModules[MainModule->getName()] = MainModule; auto modImpKind = SourceFile::ImplicitModuleImportKind::Stdlib; if (Kind == InputFileKind::IFK_SIL) { assert(BufferIDs.size() == 1); assert(MainBufferID != NO_SUCH_BUFFER); // Assume WMO, if a -primary-file option was not provided. createSILModule(!options.PrimaryInput.hasValue()); modImpKind = SourceFile::ImplicitModuleImportKind::None; } else if (Invocation.getParseStdlib()) { modImpKind = SourceFile::ImplicitModuleImportKind::Builtin; } switch (modImpKind) { case SourceFile::ImplicitModuleImportKind::None: case SourceFile::ImplicitModuleImportKind::Builtin: break; case SourceFile::ImplicitModuleImportKind::Stdlib: { ModuleDecl *M = Context->getStdlibModule(true); if (!M) { Diagnostics.diagnose(SourceLoc(), diag::error_stdlib_not_found, Invocation.getTargetTriple()); return; } // If we failed to load, we should have already diagnosed if (M->failedToLoad()) { assert(Diagnostics.hadAnyError() && "Module failed to load but nothing was diagnosed?"); return; } const auto &silOptions = Invocation.getSILOptions(); if ((silOptions.Optimization <= SILOptions::SILOptMode::None && (options.RequestedAction == FrontendOptions::EmitObject || options.RequestedAction == FrontendOptions::Immediate || options.RequestedAction == FrontendOptions::EmitSIL)) || (silOptions.Optimization == SILOptions::SILOptMode::None && options.RequestedAction >= FrontendOptions::EmitSILGen)) { // 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. Invocation.getFrontendOptions() .ImplicitImportModuleNames.push_back(SWIFT_ONONE_SUPPORT); } break; } } auto clangImporter = static_cast<ClangImporter *>(Context->getClangModuleLoader()); Module *underlying = nullptr; if (options.ImportUnderlyingModule) { underlying = clangImporter->loadModule(SourceLoc(), std::make_pair(MainModule->getName(), SourceLoc())); if (!underlying) { Diagnostics.diagnose(SourceLoc(), diag::error_underlying_module_not_found, MainModule->getName()); } } Module *importedHeaderModule = nullptr; StringRef implicitHeaderPath = options.ImplicitObjCHeaderPath; if (!implicitHeaderPath.empty()) { if (!clangImporter->importBridgingHeader(implicitHeaderPath, MainModule)) { importedHeaderModule = clangImporter->getImportedHeaderModule(); assert(importedHeaderModule); } } SmallVector<Module *, 4> importModules; if (!options.ImplicitImportModuleNames.empty()) { for (auto &ImplicitImportModuleName : options.ImplicitImportModuleNames) { if (Lexer::isIdentifier(ImplicitImportModuleName)) { auto moduleID = Context->getIdentifier(ImplicitImportModuleName); Module *importModule = Context->getModule(std::make_pair(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); } } } auto addAdditionalInitialImports = [&](SourceFile *SF) { if (!underlying && !importedHeaderModule && importModules.empty()) return; using ImportPair = std::pair<Module::ImportedModule, SourceFile::ImportOptions>; SmallVector<ImportPair, 4> additionalImports; if (underlying) additionalImports.push_back({ { /*accessPath=*/{}, underlying }, SourceFile::ImportFlags::Exported }); if (importedHeaderModule) additionalImports.push_back({ { /*accessPath=*/{}, importedHeaderModule }, SourceFile::ImportFlags::Exported }); if (!importModules.empty()) { for (auto &importModule : importModules) { additionalImports.push_back({ { /*accessPath=*/{}, importModule }, {} }); } } SF->addImports(additionalImports); }; if (Kind == InputFileKind::IFK_Swift_REPL) { auto *SingleInputFile = new (*Context) SourceFile(*MainModule, Invocation.getSourceFileKind(), None, modImpKind); MainModule->addFile(*SingleInputFile); addAdditionalInitialImports(SingleInputFile); return; } std::unique_ptr<DelayedParsingCallbacks> DelayedCB; if (Invocation.isCodeCompletion()) { DelayedCB.reset( new CodeCompleteDelayedCallbacks(SourceMgr.getCodeCompletionLoc())); } else if (Invocation.isDelayedFunctionBodyParsing()) { DelayedCB.reset(new AlwaysDelayedCallbacks); } PersistentParserState PersistentState; // Make sure the main file is the first file in the module. This may only be // a source file, or it may be a SIL file, which requires pumping the parser. // We parse it last, though, to make sure that it can use decls from other // files in the module. if (MainBufferID != NO_SUCH_BUFFER) { assert(Kind == InputFileKind::IFK_Swift || Kind == InputFileKind::IFK_SIL); if (Kind == InputFileKind::IFK_Swift) SourceMgr.setHashbangBufferID(MainBufferID); auto *MainFile = new (*Context) SourceFile(*MainModule, Invocation.getSourceFileKind(), MainBufferID, modImpKind); MainModule->addFile(*MainFile); addAdditionalInitialImports(MainFile); if (MainBufferID == PrimaryBufferID) setPrimarySourceFile(MainFile); } bool hadLoadError = false; // Parse all the partial modules first. for (auto &PM : PartialModules) { assert(PM.ModuleBuffer); if (!SML->loadAST(*MainModule, SourceLoc(), std::move(PM.ModuleBuffer), std::move(PM.ModuleDocBuffer))) hadLoadError = true; } // Then parse all the library files. for (auto BufferID : BufferIDs) { if (BufferID == MainBufferID) continue; auto *NextInput = new (*Context) SourceFile(*MainModule, SourceFileKind::Library, BufferID, modImpKind); MainModule->addFile(*NextInput); addAdditionalInitialImports(NextInput); if (BufferID == PrimaryBufferID) setPrimarySourceFile(NextInput); auto &Diags = NextInput->getASTContext().Diags; auto DidSuppressWarnings = Diags.getSuppressWarnings(); auto IsPrimary = PrimaryBufferID == NO_SUCH_BUFFER || BufferID == PrimaryBufferID; Diags.setSuppressWarnings(DidSuppressWarnings || !IsPrimary); bool Done; do { // Parser may stop at some erroneous constructions like #else, #endif // or '}' in some cases, continue parsing until we are done parseIntoSourceFile(*NextInput, BufferID, &Done, nullptr, &PersistentState, DelayedCB.get()); } while (!Done); Diags.setSuppressWarnings(DidSuppressWarnings); performNameBinding(*NextInput); } 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 // various parts of the compiler (for example, AST verifier) have less // strict assumptions about the AST. Diagnostics.diagnose(SourceLoc(), diag::error_doing_code_completion); } if (hadLoadError) return; // Compute the options we want to use for type checking. OptionSet<TypeCheckingFlags> TypeCheckOptions; if (PrimaryBufferID == NO_SUCH_BUFFER) { TypeCheckOptions |= TypeCheckingFlags::DelayWholeModuleChecking; } if (Invocation.getFrontendOptions().DebugTimeFunctionBodies) { TypeCheckOptions |= TypeCheckingFlags::DebugTimeFunctionBodies; } if (Invocation.getFrontendOptions().actionIsImmediate()) { TypeCheckOptions |= TypeCheckingFlags::ForImmediateMode; } // Parse the main file last. if (MainBufferID != NO_SUCH_BUFFER) { bool mainIsPrimary = (PrimaryBufferID == NO_SUCH_BUFFER || MainBufferID == PrimaryBufferID); SourceFile &MainFile = MainModule->getMainSourceFile(Invocation.getSourceFileKind()); auto &Diags = MainFile.getASTContext().Diags; auto DidSuppressWarnings = Diags.getSuppressWarnings(); Diags.setSuppressWarnings(DidSuppressWarnings || !mainIsPrimary); SILParserState SILContext(TheSILModule.get()); unsigned CurTUElem = 0; bool Done; do { // Pump the parser multiple times if necessary. It will return early // after parsing any top level code in a main module, or in SIL mode when // there are chunks of swift decls (e.g. imports and types) interspersed // with 'sil' definitions. parseIntoSourceFile(MainFile, MainFile.getBufferID().getValue(), &Done, TheSILModule ? &SILContext : nullptr, &PersistentState, DelayedCB.get()); if (mainIsPrimary) { performTypeChecking(MainFile, PersistentState.getTopLevelContext(), TypeCheckOptions, CurTUElem); } CurTUElem = MainFile.Decls.size(); } while (!Done); Diags.setSuppressWarnings(DidSuppressWarnings); if (mainIsPrimary && !Context->hadError() && Invocation.getFrontendOptions().PlaygroundTransform) performPlaygroundTransform(MainFile, Invocation.getFrontendOptions().PlaygroundHighPerformance); if (!mainIsPrimary) performNameBinding(MainFile); } // Type-check each top-level input besides the main source file. for (auto File : MainModule->getFiles()) if (auto SF = dyn_cast<SourceFile>(File)) if (PrimaryBufferID == NO_SUCH_BUFFER || SF == PrimarySourceFile) performTypeChecking(*SF, PersistentState.getTopLevelContext(), TypeCheckOptions); // Even if there were no source files, we should still record known // protocols. if (auto *stdlib = Context->getStdlibModule()) Context->recordKnownProtocols(stdlib); if (DelayedCB) { performDelayedParsing(MainModule, PersistentState, Invocation.getCodeCompletionFactory()); } // Perform whole-module type checking. if (TypeCheckOptions & TypeCheckingFlags::DelayWholeModuleChecking) { for (auto File : MainModule->getFiles()) if (auto SF = dyn_cast<SourceFile>(File)) performWholeModuleTypeChecking(*SF); } for (auto File : MainModule->getFiles()) if (auto SF = dyn_cast<SourceFile>(File)) if (PrimaryBufferID == NO_SUCH_BUFFER || SF == PrimarySourceFile) finishTypeChecking(*SF); }