void CompilerInstance::parseAndCheckTypes( const ImplicitImports &implicitImports) { SharedTimer timer("performSema-parseAndCheckTypes"); // Delayed parsing callback for the primary file, or all files // in non-WMO mode. std::unique_ptr<DelayedParsingCallbacks> PrimaryDelayedCB{ computeDelayedParsingCallback(true)}; // Delayed parsing callback for non-primary files. Not used in // WMO mode. std::unique_ptr<DelayedParsingCallbacks> SecondaryDelayedCB{ computeDelayedParsingCallback(false)}; PersistentParserState PersistentState; bool hadLoadError = parsePartialModulesAndLibraryFiles( implicitImports, PersistentState, PrimaryDelayedCB.get(), SecondaryDelayedCB.get()); 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; OptionSet<TypeCheckingFlags> TypeCheckOptions = computeTypeCheckingOptions(); // Type-check main file after parsing all other files so that // it can use declarations from other files. // In addition, the main file has parsing and type-checking // interwined. if (MainBufferID != NO_SUCH_BUFFER) { parseAndTypeCheckMainFile(PersistentState, PrimaryDelayedCB.get(), TypeCheckOptions); } const auto &options = Invocation.getFrontendOptions(); forEachFileToTypeCheck([&](SourceFile &SF) { performTypeChecking(SF, PersistentState.getTopLevelContext(), TypeCheckOptions, /*curElem*/ 0, options.WarnLongFunctionBodies, options.WarnLongExpressionTypeChecking, options.SolverExpressionTimeThreshold); }); // Even if there were no source files, we should still record known // protocols. if (auto *stdlib = Context->getStdlibModule()) Context->recordKnownProtocols(stdlib); if (Invocation.isCodeCompletion()) { performDelayedParsing(MainModule, PersistentState, Invocation.getCodeCompletionFactory()); } finishTypeChecking(TypeCheckOptions); }
void CompilerInstance::parseAndTypeCheckMainFile( PersistentParserState &PersistentState, DelayedParsingCallbacks *DelayedParseCB, OptionSet<TypeCheckingFlags> TypeCheckOptions) { SharedTimer timer( "performSema-checkTypesWhileParsingMain-parseAndTypeCheckMainFile"); bool mainIsPrimary = (isWholeModuleCompilation() || 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, DelayedParseCB); if (mainIsPrimary) { const auto &options = Invocation.getFrontendOptions(); performTypeChecking(MainFile, PersistentState.getTopLevelContext(), TypeCheckOptions, CurTUElem, options.WarnLongFunctionBodies, options.WarnLongExpressionTypeChecking, options.SolverExpressionTimeThreshold); } CurTUElem = MainFile.Decls.size(); } while (!Done); Diags.setSuppressWarnings(DidSuppressWarnings); if (mainIsPrimary && !Context->hadError() && Invocation.getFrontendOptions().PCMacro) { performPCMacro(MainFile, PersistentState.getTopLevelContext()); } // Playground transform knows to look out for PCMacro's changes and not // to playground log them. if (mainIsPrimary && !Context->hadError() && Invocation.getFrontendOptions().PlaygroundTransform) performPlaygroundTransform( MainFile, Invocation.getFrontendOptions().PlaygroundHighPerformance); if (!mainIsPrimary) { performNameBinding(MainFile); } }
static void doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID, CodeCompletionCallbacksFactory *CompletionCallbacksFactory) { // Temporarily disable printing the diagnostics. ASTContext &Ctx = SF.getASTContext(); auto DiagnosticConsumers = Ctx.Diags.takeConsumers(); std::string AugmentedCode = EnteredCode.str(); AugmentedCode += '\0'; *BufferID = Ctx.SourceMgr.addMemBufferCopy(AugmentedCode, "<REPL Input>"); const unsigned CodeCompletionOffset = AugmentedCode.size() - 1; Ctx.SourceMgr.setCodeCompletionPoint(*BufferID, CodeCompletionOffset); // Parse, typecheck and temporarily insert the incomplete code into the AST. const unsigned OriginalDeclCount = SF.Decls.size(); unsigned CurElem = OriginalDeclCount; PersistentParserState PersistentState; std::unique_ptr<DelayedParsingCallbacks> DelayedCB( new CodeCompleteDelayedCallbacks(Ctx.SourceMgr.getCodeCompletionLoc())); bool Done; do { parseIntoSourceFile(SF, *BufferID, &Done, nullptr, &PersistentState, DelayedCB.get()); performTypeChecking(SF, PersistentState.getTopLevelContext(), None, CurElem); CurElem = SF.Decls.size(); } while (!Done); performDelayedParsing(&SF, PersistentState, CompletionCallbacksFactory); // Now we are done with code completion. Remove the declarations we // temporarily inserted. SF.Decls.resize(OriginalDeclCount); // Add the diagnostic consumers back. for (auto DC : DiagnosticConsumers) Ctx.Diags.addConsumer(*DC); Ctx.Diags.resetHadAnyError(); }
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); }
ModuleDecl *SourceLoader::loadModule(SourceLoc importLoc, ArrayRef<std::pair<Identifier, SourceLoc>> path) { // FIXME: Swift submodules? if (path.size() > 1) return nullptr; auto moduleID = path[0]; FileOrError inputFileOrError = findModule(Ctx, moduleID.first.str(), moduleID.second); if (!inputFileOrError) { auto err = inputFileOrError.getError(); if (err != std::errc::no_such_file_or_directory) { Ctx.Diags.diagnose(moduleID.second, diag::sema_opening_import, moduleID.first, err.message()); } return nullptr; } std::unique_ptr<llvm::MemoryBuffer> inputFile = std::move(inputFileOrError.get()); addDependency(inputFile->getBufferIdentifier()); // Turn off debugging while parsing other modules. llvm::SaveAndRestore<bool> turnOffDebug(Ctx.LangOpts.DebugConstraintSolver, false); unsigned bufferID; if (auto BufID = Ctx.SourceMgr.getIDForBufferIdentifier(inputFile->getBufferIdentifier())) bufferID = BufID.getValue(); else bufferID = Ctx.SourceMgr.addNewSourceBuffer(std::move(inputFile)); auto *importMod = ModuleDecl::create(moduleID.first, Ctx); if (EnableResilience) importMod->setResilienceStrategy(ResilienceStrategy::Resilient); Ctx.LoadedModules[moduleID.first] = importMod; auto implicitImportKind = SourceFile::ImplicitModuleImportKind::Stdlib; if (!Ctx.getStdlibModule()) implicitImportKind = SourceFile::ImplicitModuleImportKind::None; auto *importFile = new (Ctx) SourceFile(*importMod, SourceFileKind::Library, bufferID, implicitImportKind); importMod->addFile(*importFile); bool done; PersistentParserState persistentState; SkipNonTransparentFunctions delayCallbacks; parseIntoSourceFile(*importFile, bufferID, &done, nullptr, &persistentState, SkipBodies ? &delayCallbacks : nullptr); assert(done && "Parser returned early?"); (void)done; if (SkipBodies) performDelayedParsing(importMod, persistentState, nullptr); // FIXME: Support recursive definitions in immediate modes by making type // checking even lazier. if (SkipBodies) performNameBinding(*importFile); else performTypeChecking(*importFile, persistentState.getTopLevelContext(), None); return importMod; }