Parser::Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF, SILParserTUStateBase *SIL, PersistentParserState *PersistentState) : SourceMgr(SF.getASTContext().SourceMgr), Diags(SF.getASTContext().Diags), SF(SF), L(Lex.release()), SIL(SIL), CurDeclContext(&SF), Context(SF.getASTContext()), TokReceiver(SF.shouldKeepSyntaxInfo() ? new TokenRecorder(SF) : new ConsumeTokenReceiver()), SyntaxContext(new SyntaxParsingContext(SyntaxContext, SF, Diags, SourceMgr, L->getBufferID())) { State = PersistentState; if (!State) { OwnedState.reset(new PersistentParserState()); State = OwnedState.get(); } // Set the token to a sentinel so that we know the lexer isn't primed yet. // This cannot be tok::unknown, since that is a token the lexer could produce. Tok.setKind(tok::NUM_TOKENS); auto ParserPos = State->takeParserPosition(); if (ParserPos.isValid() && L->isStateForCurrentBuffer(ParserPos.LS)) { restoreParserPosition(ParserPos); InPoundLineEnvironment = State->InPoundLineEnvironment; } }
Parser::Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF, SILParserState *SIL, PersistentParserState *PersistentState) : SourceMgr(SF.getASTContext().SourceMgr), Diags(SF.getASTContext().Diags), SF(SF), L(Lex.release()), SIL(SIL), CurDeclContext(&SF), Context(SF.getASTContext()) { State = PersistentState; if (!State) { OwnedState.reset(new PersistentParserState()); State = OwnedState.get(); } // Set the token to a sentinel so that we know the lexer isn't primed yet. // This cannot be tok::unknown, since that is a token the lexer could produce. Tok.setKind(tok::NUM_TOKENS); auto ParserPos = State->takeParserPosition(); if (ParserPos.isValid() && SourceMgr.findBufferContainingLoc(ParserPos.Loc) == L->getBufferID()) { auto BeginParserPosition = getParserPosition(ParserPos); restoreParserPosition(BeginParserPosition); InPoundLineEnvironment = State->InPoundLineEnvironment; } }
Parser::Parser(unsigned BufferID, SourceFile &SF, SILParserState *SIL, PersistentParserState *PersistentState) : Parser(std::unique_ptr<Lexer>( new Lexer(SF.getASTContext().LangOpts, SF.getASTContext().SourceMgr, BufferID, &SF.getASTContext().Diags, /*InSILMode=*/SIL != nullptr, SF.getASTContext().LangOpts.AttachCommentsToDecls ? CommentRetentionMode::AttachToNextToken : CommentRetentionMode::None)), SF, SIL, PersistentState) { }
Parser::Parser(unsigned BufferID, SourceFile &SF, SILParserTUStateBase *SIL, PersistentParserState *PersistentState) : Parser( std::unique_ptr<Lexer>(new Lexer( SF.getASTContext().LangOpts, SF.getASTContext().SourceMgr, BufferID, &SF.getASTContext().Diags, /*InSILMode=*/SIL != nullptr, SF.getASTContext().LangOpts.AttachCommentsToDecls ? CommentRetentionMode::AttachToNextToken : CommentRetentionMode::None, SF.shouldKeepSyntaxInfo() ? TriviaRetentionMode::WithTrivia : TriviaRetentionMode::WithoutTrivia)), SF, SIL, PersistentState) {}
void swift::performWholeModuleTypeChecking(SourceFile &SF) { auto &Ctx = SF.getASTContext(); Ctx.diagnoseAttrsRequiringFoundation(SF); Ctx.diagnoseObjCMethodConflicts(SF); Ctx.diagnoseObjCUnsatisfiedOptReqConflicts(SF); Ctx.diagnoseUnintendedObjCMethodOverrides(SF); }
static SourceLoc getDeclStartPosition(SourceFile &File) { SourceManager &SM = File.getASTContext().SourceMgr; SourceLoc Winner; auto tryUpdateStart = [&](SourceLoc Loc) -> bool { if (Loc.isInvalid()) return false; if (Winner.isInvalid()) { Winner = Loc; return true; } if (SM.isBeforeInBuffer(Loc, Winner)) { Winner = Loc; return true; } return false; }; for (auto D : File.Decls) { if (tryUpdateStart(D->getStartLoc())) { tryUpdateStart(D->getAttrs().getStartLoc()); auto RawComment = D->getRawComment(); if (!RawComment.isEmpty()) tryUpdateStart(RawComment.Comments.front().Range.getStart()); } } return Winner; }
void swift::finishTypeChecking(SourceFile &SF) { auto &Ctx = SF.getASTContext(); TypeChecker TC(Ctx); for (auto D : SF.Decls) if (auto PD = dyn_cast<ProtocolDecl>(D)) TC.inferDefaultWitnesses(PD); }
static void printUntilFirstDeclStarts(SourceFile &File, ASTPrinter &Printer) { if (!File.getBufferID().hasValue()) return; auto BufferID = *File.getBufferID(); auto &SM = File.getASTContext().SourceMgr; CharSourceRange TextRange = SM.getRangeForBuffer(BufferID); auto DeclStartLoc = getDeclStartPosition(File); if (DeclStartLoc.isValid()) { TextRange = CharSourceRange(SM, TextRange.getStart(), DeclStartLoc); } Printer << SM.extractText(TextRange, BufferID); }
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 REPLCompletions::populate(SourceFile &SF, StringRef EnteredCode) { Prefix = ""; Root.reset(); CurrentCompletionIdx = ~size_t(0); CompletionStrings.clear(); CookedResults.clear(); assert(SF.Kind == SourceFileKind::REPL && "Can't append to a non-REPL file"); unsigned BufferID; doCodeCompletion(SF, EnteredCode, &BufferID, CompletionCallbacksFactory.get()); ASTContext &Ctx = SF.getASTContext(); std::vector<Token> Tokens = tokenize(Ctx.LangOpts, Ctx.SourceMgr, BufferID); if (!Tokens.empty() && Tokens.back().is(tok::code_complete)) Tokens.pop_back(); if (!Tokens.empty()) { Token &LastToken = Tokens.back(); if (LastToken.is(tok::identifier) || LastToken.isKeyword()) { Prefix = LastToken.getText(); unsigned Offset = Ctx.SourceMgr.getLocOffsetInBuffer(LastToken.getLoc(), BufferID); doCodeCompletion(SF, EnteredCode.substr(0, Offset), &BufferID, CompletionCallbacksFactory.get()); } } if (CookedResults.empty()) State = CompletionState::Empty; else if (CookedResults.size() == 1) State = CompletionState::Unique; else State = CompletionState::CompletedRoot; }
void swift::performWholeModuleTypeChecking(SourceFile &SF) { auto &Ctx = SF.getASTContext(); FrontendStatsTracer tracer(Ctx.Stats, "perform-whole-module-type-checking"); Ctx.diagnoseAttrsRequiringFoundation(SF); Ctx.diagnoseObjCMethodConflicts(SF); Ctx.diagnoseObjCUnsatisfiedOptReqConflicts(SF); Ctx.diagnoseUnintendedObjCMethodOverrides(SF); // In whole-module mode, import verification is deferred until all files have // been type checked. This avoids caching imported declarations when a valid // type checker is not present. The same declaration may need to be fully // imported by subsequent files. // // FIXME: some playgrounds tests (playground_lvalues.swift) fail with // verification enabled. #if 0 if (SF.Kind != SourceFileKind::REPL && SF.Kind != SourceFileKind::SIL && !Ctx.LangOpts.DebuggerSupport) { Ctx.verifyAllLoadedModules(); } #endif }
void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, OptionSet<TypeCheckingFlags> Options, unsigned StartElem, unsigned WarnLongFunctionBodies, unsigned WarnLongExpressionTypeChecking, unsigned ExpressionTimeoutThreshold, unsigned SwitchCheckingInvocationThreshold) { if (SF.ASTStage == SourceFile::TypeChecked) return; auto &Ctx = SF.getASTContext(); // Make sure we have a type checker. TypeChecker &TC = createTypeChecker(Ctx); // Make sure that name binding has been completed before doing any type // checking. performNameBinding(SF, StartElem); { SharedTimer timer("Type checking / Semantic analysis"); TC.setWarnLongFunctionBodies(WarnLongFunctionBodies); TC.setWarnLongExpressionTypeChecking(WarnLongExpressionTypeChecking); if (ExpressionTimeoutThreshold != 0) TC.setExpressionTimeoutThreshold(ExpressionTimeoutThreshold); if (SwitchCheckingInvocationThreshold != 0) TC.setSwitchCheckingInvocationThreshold( SwitchCheckingInvocationThreshold); if (Options.contains(TypeCheckingFlags::DebugTimeFunctionBodies)) TC.enableDebugTimeFunctionBodies(); if (Options.contains(TypeCheckingFlags::DebugTimeExpressions)) TC.enableDebugTimeExpressions(); if (Options.contains(TypeCheckingFlags::ForImmediateMode)) TC.setInImmediateMode(true); // Lookup the swift module. This ensures that we record all known // protocols in the AST. (void) TC.getStdlibModule(&SF); if (!Ctx.LangOpts.DisableAvailabilityChecking) { // Build the type refinement hierarchy for the primary // file before type checking. TC.buildTypeRefinementContextHierarchy(SF, StartElem); } // Resolve extensions. This has to occur first during type checking, // because the extensions need to be wired into the AST for name lookup // to work. bindExtensions(SF, TC); // Look for bridging functions. This only matters when // -enable-source-import is provided. checkBridgedFunctions(TC.Context); // Type check the top-level elements of the source file. bool hasTopLevelCode = false; for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) { if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) { hasTopLevelCode = true; // Immediately perform global name-binding etc. TC.typeCheckTopLevelCodeDecl(TLCD); } else { TC.typeCheckDecl(D); } } if (hasTopLevelCode) { TC.contextualizeTopLevelCode(TLC, llvm::makeArrayRef(SF.Decls).slice(StartElem)); } // If we're in REPL mode, inject temporary result variables and other stuff // that the REPL needs to synthesize. if (SF.Kind == SourceFileKind::REPL && !Ctx.hadError()) TC.processREPLTopLevel(SF, TLC, StartElem); typeCheckFunctionsAndExternalDecls(SF, TC); } // Checking that benefits from having the whole module available. if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking)) { performWholeModuleTypeChecking(SF); } // Verify that we've checked types correctly. SF.ASTStage = SourceFile::TypeChecked; { SharedTimer timer("AST verification"); // Verify the SourceFile. verify(SF); // Verify imported modules. // // Skip per-file verification in whole-module mode. Verifying imports // between files could cause the importer to cache declarations without // adding them to the ASTContext. This happens when the importer registers a // declaration without a valid TypeChecker instance, as is the case during // verification. A subsequent file may require that declaration to be fully // imported (e.g. to synthesized a function body), but since it has already // been cached, it will never be added to the ASTContext. The solution is to // skip verification and avoid caching it. #ifndef NDEBUG if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking) && SF.Kind != SourceFileKind::REPL && SF.Kind != SourceFileKind::SIL && !Ctx.LangOpts.DebuggerSupport) { Ctx.verifyAllLoadedModules(); } #endif } }
void swift::typeCheckExternalDefinitions(SourceFile &SF) { assert(SF.ASTStage == SourceFile::TypeChecked); auto &Ctx = SF.getASTContext(); typeCheckFunctionsAndExternalDecls(SF, createTypeChecker(Ctx)); }
void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, OptionSet<TypeCheckingFlags> Options, unsigned StartElem, unsigned WarnLongFunctionBodies) { if (SF.ASTStage == SourceFile::TypeChecked) return; auto &Ctx = SF.getASTContext(); // Make sure we have a type checker. Optional<TypeChecker> MyTC; if (!Ctx.getLazyResolver()) MyTC.emplace(Ctx); // Make sure that name binding has been completed before doing any type // checking. { SharedTimer timer("Name binding"); performNameBinding(SF, StartElem); } { // NOTE: The type checker is scoped to be torn down before AST // verification. SharedTimer timer("Type checking / Semantic analysis"); if (MyTC) { MyTC->setWarnLongFunctionBodies(WarnLongFunctionBodies); if (Options.contains(TypeCheckingFlags::DebugTimeFunctionBodies)) MyTC->enableDebugTimeFunctionBodies(); if (Options.contains(TypeCheckingFlags::DebugTimeExpressions)) MyTC->enableDebugTimeExpressions(); if (Options.contains(TypeCheckingFlags::ForImmediateMode)) MyTC->setInImmediateMode(true); // Lookup the swift module. This ensures that we record all known // protocols in the AST. (void) MyTC->getStdlibModule(&SF); if (!Ctx.LangOpts.DisableAvailabilityChecking) { // Build the type refinement hierarchy for the primary // file before type checking. MyTC->buildTypeRefinementContextHierarchy(SF, StartElem); } } TypeChecker &TC = MyTC ? *MyTC : *static_cast<TypeChecker *>(Ctx.getLazyResolver()); // Resolve extensions. This has to occur first during type checking, // because the extensions need to be wired into the AST for name lookup // to work. // FIXME: We can have interesting ordering dependencies among the various // extensions, so we'll need to be smarter here. // FIXME: The current source file needs to be handled specially, because of // private extensions. SF.forAllVisibleModules([&](ModuleDecl::ImportedModule import) { // FIXME: Respect the access path? for (auto file : import.second->getFiles()) { auto SF = dyn_cast<SourceFile>(file); if (!SF) continue; for (auto D : SF->Decls) { if (auto ED = dyn_cast<ExtensionDecl>(D)) bindExtensionDecl(ED, TC); } } }); // FIXME: Check for cycles in class inheritance here? // Type check the top-level elements of the source file. for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) { if (isa<TopLevelCodeDecl>(D)) continue; TC.typeCheckDecl(D, /*isFirstPass*/true); } // At this point, we can perform general name lookup into any type. // We don't know the types of all the global declarations in the first // pass, which means we can't completely analyze everything. Perform the // second pass now. bool hasTopLevelCode = false; for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) { if (TopLevelCodeDecl *TLCD = dyn_cast<TopLevelCodeDecl>(D)) { hasTopLevelCode = true; // Immediately perform global name-binding etc. TC.typeCheckTopLevelCodeDecl(TLCD); } else { TC.typeCheckDecl(D, /*isFirstPass*/false); } } if (hasTopLevelCode) { TC.contextualizeTopLevelCode(TLC, llvm::makeArrayRef(SF.Decls).slice(StartElem)); } // If we're in REPL mode, inject temporary result variables and other stuff // that the REPL needs to synthesize. if (SF.Kind == SourceFileKind::REPL && !Ctx.hadError()) TC.processREPLTopLevel(SF, TLC, StartElem); typeCheckFunctionsAndExternalDecls(TC); } MyTC.reset(); // Checking that benefits from having the whole module available. if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking)) { performWholeModuleTypeChecking(SF); } // Verify that we've checked types correctly. SF.ASTStage = SourceFile::TypeChecked; { SharedTimer timer("AST verification"); // Verify the SourceFile. verify(SF); // Verify imported modules. #ifndef NDEBUG if (SF.Kind != SourceFileKind::REPL && SF.Kind != SourceFileKind::SIL && !Ctx.LangOpts.DebuggerSupport) { Ctx.verifyAllLoadedModules(); } #endif } }