Skip to content

Commit 9e3f5f9

Browse files
committed
[ModuleInterface] Print missing imports in swiftinterface
Hack to fix swiftinterfaces in case of missing imports. We can get rid of this logic when we don't leak the use of non-locally imported things in API.
1 parent 9e4a00d commit 9e3f5f9

File tree

10 files changed

+77
-0
lines changed

10 files changed

+77
-0
lines changed

include/swift/AST/FileUnit.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,10 @@ class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
271271
getImportedModules(SmallVectorImpl<ImportedModule> &imports,
272272
ModuleDecl::ImportFilter filter) const {}
273273

274+
/// Lists modules that are not imported from this file and used in API.
275+
virtual void
276+
getMissingImportedModules(SmallVectorImpl<ImportedModule> &imports) const {}
277+
274278
/// \see ModuleDecl::getImportedModulesForLookup
275279
virtual void getImportedModulesForLookup(
276280
SmallVectorImpl<ImportedModule> &imports) const {

include/swift/AST/Module.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,10 @@ class ModuleDecl
713713
void getImportedModules(SmallVectorImpl<ImportedModule> &imports,
714714
ImportFilter filter = ImportFilterKind::Exported) const;
715715

716+
/// Lists modules that are not imported from a file and used in API.
717+
void
718+
getMissingImportedModules(SmallVectorImpl<ImportedModule> &imports) const;
719+
716720
/// Looks up which modules are imported by this module, ignoring any that
717721
/// won't contain top-level decls.
718722
///

include/swift/AST/SourceFile.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,15 @@ class SourceFile final : public FileUnit {
399399

400400
SWIFT_DEBUG_DUMPER(dumpSeparatelyImportedOverlays());
401401

402+
llvm::SmallDenseSet<ImportedModule> MissingImportedModules;
403+
404+
void addMissingImportedModule(ImportedModule module) const {
405+
const_cast<SourceFile *>(this)->MissingImportedModules.insert(module);
406+
}
407+
408+
void getMissingImportedModules(
409+
SmallVectorImpl<ImportedModule> &imports) const override;
410+
402411
void cacheVisibleDecls(SmallVectorImpl<ValueDecl *> &&globals) const;
403412
const SmallVectorImpl<ValueDecl *> &getCachedVisibleDecls() const;
404413

include/swift/Frontend/ModuleInterfaceSupport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ struct ModuleInterfaceOptions {
5353
/// when PrintSPIs is true.
5454
bool ExperimentalSPIImports = false;
5555

56+
/// Print imports that are missing from the source and used in API.
57+
bool PrintMissingImports = true;
58+
5659
/// Intentionally print invalid syntax into the file.
5760
bool DebugPrintInvalidSyntax = false;
5861

include/swift/Option/FrontendOptions.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,11 @@ def experimental_spi_imports :
900900
Flag<["-"], "experimental-spi-imports">,
901901
HelpText<"Enable experimental support for SPI imports">;
902902

903+
def disable_print_missing_imports_in_module_interface :
904+
Flag<["-"], "disable-print-missing-imports-in-module-interface">,
905+
HelpText<"Disable adding to the module interface imports used from API and "
906+
"missing from the sources">;
907+
903908
// [FIXME: Clang-type-plumbing] Make this a SIL-only option once we start
904909
// unconditionally emitting non-canonical Clang types in swiftinterfaces.
905910
def experimental_print_full_convention :

lib/AST/Module.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,11 @@ void ModuleDecl::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
15701570
FORWARD(getImportedModules, (modules, filter));
15711571
}
15721572

1573+
void ModuleDecl::getMissingImportedModules(
1574+
SmallVectorImpl<ImportedModule> &imports) const {
1575+
FORWARD(getMissingImportedModules, (imports));
1576+
}
1577+
15731578
void
15741579
SourceFile::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
15751580
ModuleDecl::ImportFilter filter) const {
@@ -1604,6 +1609,12 @@ SourceFile::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
16041609
}
16051610
}
16061611

1612+
void SourceFile::getMissingImportedModules(
1613+
SmallVectorImpl<ImportedModule> &modules) const {
1614+
for (auto module : MissingImportedModules)
1615+
modules.push_back(module);
1616+
}
1617+
16071618
void SourceFile::dumpSeparatelyImportedOverlays() const {
16081619
for (auto &pair : separatelyImportedOverlays) {
16091620
auto &underlying = std::get<0>(pair);
@@ -2535,6 +2546,20 @@ RestrictedImportKind SourceFile::getRestrictedImportKind(const ModuleDecl *modul
25352546
if (imports.isImportedBy(module, getParentModule()))
25362547
return RestrictedImportKind::None;
25372548

2549+
if (importKind == RestrictedImportKind::Implicit &&
2550+
module->getLibraryLevel() == LibraryLevel::API) {
2551+
// Hack to fix swiftinterfaces in case of missing imports.
2552+
// We can get rid of this logic when we don't leak the use of non-locally
2553+
// imported things in API.
2554+
ImportPath::Element pathElement = {module->getName(), SourceLoc()};
2555+
auto pathArray = getASTContext().AllocateCopy(
2556+
llvm::makeArrayRef(pathElement));
2557+
auto missingImport = ImportedModule(
2558+
ImportPath::Access(pathArray),
2559+
const_cast<ModuleDecl *>(module));
2560+
addMissingImportedModule(missingImport);
2561+
}
2562+
25382563
return importKind;
25392564
}
25402565

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,8 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts,
373373
Args.hasArg(OPT_experimental_spi_imports);
374374
Opts.DebugPrintInvalidSyntax |=
375375
Args.hasArg(OPT_debug_emit_invalid_swiftinterface_syntax);
376+
Opts.PrintMissingImports =
377+
!Args.hasArg(OPT_disable_print_missing_imports_in_module_interface);
376378

377379
if (const Arg *A = Args.getLastArg(OPT_library_level)) {
378380
StringRef contents = A->getValue();

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ static void printImports(raw_ostream &out,
219219

220220
SmallVector<ImportedModule, 8> allImports;
221221
M->getImportedModules(allImports, allImportFilter);
222+
223+
if (Opts.PrintMissingImports)
224+
M->getMissingImportedModules(allImports);
225+
222226
ImportedModule::removeDuplicates(allImports);
223227
diagnoseScopedImports(M->getASTContext().Diags, allImports);
224228

test/Sema/implicit-import-in-inlinable-code.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@
1616
/// In Swift 6, it's an error.
1717
// RUN: %target-swift-frontend -emit-module %t/clientFileA-Swift6.swift %t/clientFileB.swift -module-name client -o %t/client.swiftmodule -I %t -verify -swift-version 6
1818

19+
/// The swiftinterface is broken by the missing import without the workaround.
20+
// RUN: %target-swift-emit-module-interface(%t/ClientBroken.swiftinterface) %t/clientFileA-Swift5.swift %t/clientFileB.swift -I %t -disable-print-missing-imports-in-module-interface
21+
// RUN: not %target-swift-typecheck-module-from-interface(%t/ClientBroken.swiftinterface) -I %t
22+
23+
/// The swiftinterface parses fine with the workaround adding the missing imports.
24+
// RUN: %target-swift-emit-module-interface(%t/ClientFixed.swiftinterface) %t/clientFileA-Swift5.swift %t/clientFileB.swift -I %t
25+
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientFixed.swiftinterface) -I %t
26+
1927
// REQUIRES: asserts
2028

2129
// BEGIN empty.swift

test/Sema/implicit-import-typealias.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@
1111
// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesImplementationOnlyImport.swift -I %t
1212
// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesWithImport.swift -I %t
1313

14+
/// The swiftinterface is broken by the missing import without the workaround.
15+
// RUN: %target-swift-emit-module-interface(%t/UsesAliasesNoImport.swiftinterface) %t/UsesAliasesNoImport.swift -I %t \
16+
// RUN: -disable-print-missing-imports-in-module-interface
17+
// RUN: not %target-swift-typecheck-module-from-interface(%t/UsesAliasesNoImport.swiftinterface) -I %t
18+
19+
/// The swiftinterface parses fine with the workaround adding the missing imports.
20+
// RUN: %target-swift-emit-module-interface(%t/UsesAliasesNoImportFixed.swiftinterface) %t/UsesAliasesNoImport.swift -I %t
21+
// RUN: %target-swift-typecheck-module-from-interface(%t/UsesAliasesNoImportFixed.swiftinterface) -I %t
22+
23+
/// The module with an implementation-only import is not affected by the workaround and remains broken.
24+
// RUN: %target-swift-emit-module-interface(%t/UsesAliasesImplementationOnlyImport.swiftinterface) %t/UsesAliasesImplementationOnlyImport.swift -I %t \
25+
// RUN: -disable-print-missing-imports-in-module-interface
26+
// RUN: not %target-swift-typecheck-module-from-interface(%t/UsesAliasesImplementationOnlyImport.swiftinterface) -I %t
1427

1528
//--- Original.swift
1629

0 commit comments

Comments
 (0)