@@ -548,8 +548,8 @@ void ModuleDependencyScanner::resolveImportDependencies(
548
548
// A scanning task to query a module by-name. If the module already exists
549
549
// in the cache, do nothing and return.
550
550
auto scanForModuleDependency = [this , &cache, &moduleLookupResult](
551
- StringRef moduleName, bool onlyClangModule,
552
- bool isTestable) {
551
+ StringRef moduleName, bool onlyClangModule,
552
+ bool isTestable) {
553
553
// If this is already in the cache, no work to do here
554
554
if (onlyClangModule) {
555
555
if (cache.hasDependency (moduleName, ModuleDependencyKind::Clang))
@@ -587,9 +587,10 @@ void ModuleDependencyScanner::resolveImportDependencies(
587
587
}
588
588
ScanningThreadPool.wait ();
589
589
590
+ std::vector<std::string> unresolvedImports;
590
591
// Aggregate both previously-cached and freshly-scanned module results
591
592
auto recordResolvedModuleImport =
592
- [this , &cache, &moduleLookupResult, &directDependencies,
593
+ [&cache, &moduleLookupResult, &unresolvedImports , &directDependencies,
593
594
moduleID](const std::string &moduleName, bool optionalImport) {
594
595
bool underlyingClangModule = moduleID.ModuleName == moduleName;
595
596
auto lookupResult = moduleLookupResult[moduleName];
@@ -606,19 +607,56 @@ void ModuleDependencyScanner::resolveImportDependencies(
606
607
directDependencies.insert ({moduleName, cachedInfo->getKind ()});
607
608
} else {
608
609
// Cache discovered module dependencies.
609
- cache. recordDependencies ( lookupResult.value ());
610
- if (! lookupResult.value (). empty ())
610
+ if (! lookupResult.value (). empty ()) {
611
+ cache. recordDependencies ( lookupResult.value ());
611
612
directDependencies.insert (
612
613
{moduleName, lookupResult.value ()[0 ].first .Kind });
613
- else if (!optionalImport)
614
- diagnoseScannerFailure (moduleName, Diagnostics, cache, moduleID);
614
+ } else if (!optionalImport) {
615
+ // Otherwise, we failed to resolve this dependency. We will try
616
+ // again using the cache after all other imports have been resolved.
617
+ // If that fails too, a scanning failure will be diagnosed.
618
+ unresolvedImports.push_back (moduleName);
619
+ }
615
620
}
616
621
};
617
- for (const auto &dependsOn : moduleDependencyInfo->getModuleImports ())
618
- recordResolvedModuleImport (dependsOn, false );
619
- for (const auto &optionallyDependsOn :
620
- moduleDependencyInfo->getOptionalModuleImports ())
621
- recordResolvedModuleImport (optionallyDependsOn, true );
622
+ for (const auto &import : moduleDependencyInfo->getModuleImports ())
623
+ recordResolvedModuleImport (import , /* optionalImport */ false );
624
+ for (const auto &import : moduleDependencyInfo->getOptionalModuleImports ())
625
+ recordResolvedModuleImport (import , /* optionalImport */ true );
626
+
627
+ // It is possible that import resolution failed because we are attempting to
628
+ // resolve a module which can only be brought in via a modulemap of a
629
+ // different Clang module dependency which is not otherwise on the current
630
+ // search paths. For example, suppose we are scanning a `.swiftinterface` for
631
+ // module `Foo`, which contains:
632
+ // -----
633
+ // @_exported import Foo
634
+ // import Bar
635
+ // ...
636
+ // -----
637
+ // Where `Foo` is the underlying Framework clang module whose .modulemap
638
+ // defines an auxiliary module `Bar`. Because Foo is a framework, its
639
+ // modulemap is under
640
+ // `<some_framework_search_path>/Foo.framework/Modules/module.modulemap`.
641
+ // Which means that lookup of `Bar` alone from Swift will not be able to
642
+ // locate the module in it. However, the lookup of Foo will itself bring in
643
+ // the auxiliary module becuase the Clang scanner instance scanning for clang
644
+ // module Foo will be able to find it in the corresponding framework module's
645
+ // modulemap and register it as a dependency which means it will be registered
646
+ // with the scanner's cache in the step above. To handle such cases, we
647
+ // first add all successfully-resolved modules and (for Clang modules) their
648
+ // transitive dependencies to the cache, and then attempt to re-query imports
649
+ // for which resolution originally failed from the cache. If this fails, then
650
+ // the scanner genuinely failed to resolve this dependency.
651
+ for (const auto &moduleName : unresolvedImports) {
652
+ auto optionalCachedModuleInfo =
653
+ cache.findDependency ({moduleName, ModuleDependencyKind::Clang});
654
+ if (optionalCachedModuleInfo.has_value ())
655
+ directDependencies.insert (
656
+ {moduleName, optionalCachedModuleInfo.value ()->getKind ()});
657
+ else
658
+ diagnoseScannerFailure (moduleName, Diagnostics, cache, moduleID);
659
+ }
622
660
}
623
661
624
662
void ModuleDependencyScanner::resolveBridgingHeaderDependencies (
0 commit comments