static void bindExtensions(SourceFile &SF, TypeChecker &TC) { // Utility function to try and resolve the extended type without diagnosing. // If we succeed, we go ahead and bind the extension. Otherwise, return false. auto tryBindExtension = [&](ExtensionDecl *ext) -> bool { if (auto nominal = ext->getExtendedNominal()) { bindExtensionToNominal(ext, nominal); return true; } return false; }; // Phase 1 - try to bind each extension, adding those whose type cannot be // resolved to a worklist. SmallVector<ExtensionDecl *, 8> worklist; // 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)) if (!tryBindExtension(ED)) worklist.push_back(ED); } } }); // Phase 2 - repeatedly go through the worklist and attempt to bind each // extension there, removing it from the worklist if we succeed. bool changed; do { changed = false; auto last = std::remove_if(worklist.begin(), worklist.end(), tryBindExtension); if (last != worklist.end()) { worklist.erase(last, worklist.end()); changed = true; } } while(changed); // Any remaining extensions are invalid. They will be diagnosed later by // typeCheckDecl(). }
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 } }