@@ -849,18 +849,16 @@ ASTContext::ASTContext(
849849 registerNameLookupRequestFunctions (evaluator);
850850
851851 // Register canImport module info.
852- for (auto &info: SearchPathOpts.CanImportModuleInfo ) {
853- addSucceededCanImportModule (info.ModuleName , false , info.Version );
854- addSucceededCanImportModule (info.ModuleName , true , info.UnderlyingVersion );
855- }
852+ for (auto &info: SearchPathOpts.CanImportModuleInfo )
853+ addSucceededCanImportModule (info.ModuleName , info.Version , info.UnderlyingVersion );
856854
857855 // Provide a default OnDiskOutputBackend if user didn't supply one.
858856 if (!OutputBackend)
859857 OutputBackend = llvm::makeIntrusiveRefCnt<llvm::vfs::OnDiskOutputBackend>();
858+
860859 // Insert all block list config paths.
861- for (auto path: langOpts.BlocklistConfigFilePaths ) {
860+ for (auto path: langOpts.BlocklistConfigFilePaths )
862861 blockListConfig.addConfigureFilePath (path);
863- }
864862}
865863
866864void ASTContext::Implementation::dump (llvm::raw_ostream &os) const {
@@ -2655,34 +2653,25 @@ static bool isClangModuleVersion(const ModuleLoader::ModuleVersionInfo &info) {
26552653 }
26562654}
26572655
2658- static StringRef
2659- getModuleVersionKindString (const ModuleLoader::ModuleVersionInfo &info) {
2660- switch (info.getSourceKind ()) {
2661- case ModuleLoader::ModuleVersionSourceKind::ClangModuleTBD:
2662- return " Clang" ;
2663- case ModuleLoader::ModuleVersionSourceKind::SwiftBinaryModule:
2664- case ModuleLoader::ModuleVersionSourceKind::SwiftInterface:
2665- return " Swift" ;
2666- }
2667- }
2668-
26692656void ASTContext::addSucceededCanImportModule (
2670- StringRef moduleName, bool underlyingVersion,
2671- const llvm::VersionTuple &versionInfo) {
2657+ StringRef moduleName,
2658+ const llvm::VersionTuple &versionInfo,
2659+ const llvm::VersionTuple &underlyingVersionInfo) {
2660+ // We have previously recorded a successful canImport
2661+ // information for this module.
2662+ if (CanImportModuleVersions.count (moduleName.str ()))
2663+ return ;
2664+
26722665 auto &entry = CanImportModuleVersions[moduleName.str ()];
2673- if (!versionInfo.empty ()) {
2674- if (underlyingVersion)
2675- entry.UnderlyingVersion = versionInfo;
2676- else
2677- entry.Version = versionInfo;
2678- }
2666+ entry.Version = versionInfo;
2667+ entry.UnderlyingVersion = underlyingVersionInfo;
26792668}
26802669
2681- bool ASTContext::canImportModuleImpl (ImportPath::Module ModuleName,
2682- SourceLoc loc, llvm::VersionTuple version,
2683- bool underlyingVersion ,
2684- bool updateFailingList ,
2685- llvm::VersionTuple &foundVersion ) const {
2670+ bool ASTContext::canImportModuleImpl (
2671+ ImportPath::Module ModuleName, SourceLoc loc, llvm::VersionTuple version,
2672+ bool underlyingVersion, bool isSourceCanImport ,
2673+ llvm::VersionTuple &foundVersion ,
2674+ llvm::VersionTuple &foundUnderlyingClangVersion ) const {
26862675 SmallString<64 > FullModuleName;
26872676 ModuleName.getString (FullModuleName);
26882677 auto ModuleNameStr = FullModuleName.str ().str ();
@@ -2691,6 +2680,20 @@ bool ASTContext::canImportModuleImpl(ImportPath::Module ModuleName,
26912680 if (FailedModuleImportNames.count (ModuleNameStr))
26922681 return false ;
26932682
2683+ auto missingVersion = [this , &loc, &ModuleName,
2684+ &underlyingVersion]() -> bool {
2685+ // The module version could not be parsed from the preferred source for
2686+ // this query. Diagnose and return `true` to indicate that the unversioned module
2687+ // will satisfy the query.
2688+ auto mID = ModuleName[0 ];
2689+ auto diagLoc = mID .Loc ;
2690+ if (mID .Loc .isInvalid ())
2691+ diagLoc = loc;
2692+ Diags.diagnose (diagLoc, diag::cannot_find_project_version, mID .Item .str (),
2693+ underlyingVersion);
2694+ return true ;
2695+ };
2696+
26942697 // If this module has already been checked or there is information for the
26952698 // module from commandline, use that information instead of loading the
26962699 // module.
@@ -2699,35 +2702,95 @@ bool ASTContext::canImportModuleImpl(ImportPath::Module ModuleName,
26992702 if (version.empty ())
27002703 return true ;
27012704
2702- if (underlyingVersion) {
2703- if (!Found->second .UnderlyingVersion .empty ())
2704- return version <= Found->second .UnderlyingVersion ;
2705- } else {
2706- if (!Found->second .Version .empty ())
2707- return version <= Found->second .Version ;
2705+ const auto &foundComparisonVersion = underlyingVersion
2706+ ? Found->second .UnderlyingVersion
2707+ : Found->second .Version ;
2708+ if (!foundComparisonVersion.empty ())
2709+ return version <= foundComparisonVersion;
2710+ else
2711+ return missingVersion ();
2712+ }
2713+
2714+ // When looking up a module, each module importer will report back
2715+ // if it finds a module with a specified version. This routine verifies
2716+ // whether said version is valid and if it superceeds the best
2717+ // previously-discovered version of this module found.
2718+ auto validateVersion =
2719+ [](const ModuleLoader::ModuleVersionInfo &bestVersionInfo,
2720+ const ModuleLoader::ModuleVersionInfo &versionInfo,
2721+ bool underlyingVersion) {
2722+ if (!versionInfo.isValid ())
2723+ return false ; // The loader didn't attempt to parse a version.
2724+
2725+ if (underlyingVersion && !isClangModuleVersion (versionInfo))
2726+ return false ; // We're only matching Clang module versions.
2727+
2728+ if (bestVersionInfo.isValid () &&
2729+ versionInfo.getSourceKind () <= bestVersionInfo.getSourceKind ())
2730+ return false ; // This module version's source is lower priority.
2731+
2732+ return true ;
2733+ };
2734+
2735+ // For each module loader, attempt to discover queried module,
2736+ // along the way record the discovered module's version as well as
2737+ // the discovered module's underlying Clang module's version.
2738+ auto lookupVersionedModule =
2739+ [&](ModuleLoader::ModuleVersionInfo &bestVersionInfo,
2740+ ModuleLoader::ModuleVersionInfo &bestUnderlyingVersionInfo) -> bool {
2741+ for (auto &importer : getImpl ().ModuleLoaders ) {
2742+ ModuleLoader::ModuleVersionInfo versionInfo;
2743+ if (!importer->canImportModule (ModuleName, loc, &versionInfo))
2744+ continue ; // The loader can't find the module.
2745+
2746+ if (validateVersion (bestVersionInfo, versionInfo,
2747+ /* underlyingVersion */ false ))
2748+ bestVersionInfo = versionInfo;
2749+ if (validateVersion (bestUnderlyingVersionInfo, versionInfo,
2750+ /* underlyingVersion */ true ))
2751+ bestUnderlyingVersionInfo = versionInfo;
27082752 }
27092753
2710- // If the canImport information is coming from the command-line, then no
2711- // need to continue the search, return false. For checking modules that are
2712- // not passed from command-line, allow fallback to the module loading since
2713- // this is not in a canImport request context that has already been resolved
2714- // by scanner.
2715- if (!SearchPathOpts.CanImportModuleInfo .empty ())
2754+ if (!underlyingVersion && !bestVersionInfo.isValid ())
27162755 return false ;
2717- }
2756+
2757+ if (underlyingVersion && !bestUnderlyingVersionInfo.isValid ())
2758+ return false ;
2759+
2760+ foundVersion = bestVersionInfo.getVersion ();
2761+ foundUnderlyingClangVersion = bestUnderlyingVersionInfo.getVersion ();
2762+ return true ;
2763+ };
2764+
2765+ // For queries which do not care about any kind of module information
2766+ // such as e.g. `testImportModule`, simply return `true` as soon
2767+ // as *any* loader can find the queried module.
2768+ auto lookupModule = [&]() -> bool {
2769+ for (auto &importer : getImpl ().ModuleLoaders ) {
2770+ ModuleLoader::ModuleVersionInfo versionInfo;
2771+ if (!importer->canImportModule (ModuleName, loc, &versionInfo))
2772+ continue ; // The loader can't find the module.
2773+ return true ;
2774+ }
2775+ return false ;
2776+ };
27182777
27192778 if (version.empty ()) {
27202779 // If this module has already been successfully imported, it is importable.
27212780 if (getLoadedModule (ModuleName) != nullptr )
27222781 return true ;
2782+
2783+ if (!isSourceCanImport)
2784+ return lookupModule ();
2785+
2786+ // Otherwise, ask whether any module loader can load the module,
2787+ // and record the module version that the succeeding loader
2788+ // observed.
2789+ ModuleLoader::ModuleVersionInfo versionInfo, underlyingVersionInfo;
2790+ if (lookupVersionedModule (versionInfo, underlyingVersionInfo))
2791+ return true ;
27232792
2724- // Otherwise, ask whether any module loader can load the module.
2725- for (auto &importer : getImpl ().ModuleLoaders ) {
2726- if (importer->canImportModule (ModuleName, loc, nullptr ))
2727- return true ;
2728- }
2729-
2730- if (updateFailingList)
2793+ if (isSourceCanImport)
27312794 FailedModuleImportNames.insert (ModuleNameStr);
27322795
27332796 return false ;
@@ -2736,43 +2799,15 @@ bool ASTContext::canImportModuleImpl(ImportPath::Module ModuleName,
27362799 // We need to check whether the version of the module is high enough.
27372800 // Retrieve a module version from each module loader that can find the module
27382801 // and use the best source available for the query.
2739- ModuleLoader::ModuleVersionInfo bestVersionInfo;
2740- for (auto &importer : getImpl ().ModuleLoaders ) {
2741- ModuleLoader::ModuleVersionInfo versionInfo;
2742-
2743- if (!importer->canImportModule (ModuleName, loc, &versionInfo))
2744- continue ; // The loader can't find the module.
2745-
2746- if (!versionInfo.isValid ())
2747- continue ; // The loader didn't attempt to parse a version.
2748-
2749- if (underlyingVersion && !isClangModuleVersion (versionInfo))
2750- continue ; // We're only matching Clang module versions.
2751-
2752- if (bestVersionInfo.isValid () &&
2753- versionInfo.getSourceKind () <= bestVersionInfo.getSourceKind ())
2754- continue ; // This module version's source is lower priority.
2755-
2756- bestVersionInfo = versionInfo;
2757- }
2758-
2759- if (!bestVersionInfo.isValid ())
2802+ ModuleLoader::ModuleVersionInfo versionInfo, underlyingVersionInfo;
2803+ if (!lookupVersionedModule (versionInfo, underlyingVersionInfo))
27602804 return false ;
27612805
2762- if (bestVersionInfo.getVersion ().empty ()) {
2763- // The module version could not be parsed from the preferred source for
2764- // this query. Diagnose and treat the query as if it succeeded.
2765- auto mID = ModuleName[0 ];
2766- auto diagLoc = mID .Loc ;
2767- if (mID .Loc .isInvalid ())
2768- diagLoc = loc;
2769- Diags.diagnose (diagLoc, diag::cannot_find_project_version,
2770- getModuleVersionKindString (bestVersionInfo), mID .Item .str ());
2771- return true ;
2772- }
2806+ const auto &queryVersion = underlyingVersion ? underlyingVersionInfo : versionInfo;
2807+ if (queryVersion.getVersion ().empty ())
2808+ return missingVersion ();
27732809
2774- foundVersion = bestVersionInfo.getVersion ();
2775- return version <= bestVersionInfo.getVersion ();
2810+ return version <= queryVersion.getVersion ();
27762811}
27772812
27782813void ASTContext::forEachCanImportVersionCheck (
@@ -2787,22 +2822,26 @@ bool ASTContext::canImportModule(ImportPath::Module moduleName, SourceLoc loc,
27872822 llvm::VersionTuple version,
27882823 bool underlyingVersion) {
27892824 llvm::VersionTuple versionInfo;
2825+ llvm::VersionTuple underlyingVersionInfo;
27902826 if (!canImportModuleImpl (moduleName, loc, version, underlyingVersion, true ,
2791- versionInfo))
2827+ versionInfo, underlyingVersionInfo ))
27922828 return false ;
27932829
27942830 SmallString<64 > fullModuleName;
27952831 moduleName.getString (fullModuleName);
2796- addSucceededCanImportModule (fullModuleName, underlyingVersion, versionInfo);
2832+
2833+ addSucceededCanImportModule (fullModuleName, versionInfo, underlyingVersionInfo);
27972834 return true ;
27982835}
27992836
28002837bool ASTContext::testImportModule (ImportPath::Module ModuleName,
28012838 llvm::VersionTuple version,
28022839 bool underlyingVersion) const {
28032840 llvm::VersionTuple versionInfo;
2841+ llvm::VersionTuple underlyingVersionInfo;
28042842 return canImportModuleImpl (ModuleName, SourceLoc (), version,
2805- underlyingVersion, false , versionInfo);
2843+ underlyingVersion, false , versionInfo,
2844+ underlyingVersionInfo);
28062845}
28072846
28082847ModuleDecl *
0 commit comments