Add @_implementationOnly

This is an attribute that gets put on an import in library FooKit to
keep it from being a requirement to import FooKit. It's not checked at
all, meaning that in this form it is up to the author of FooKit to
make sure nothing in its API or ABI depends on the implementation-only
dependency. There's also no debugging support here (debugging FooKit
/should/ import the implementation-only dependency if it's present).

The goal is to get to a point where it /can/ be checked, i.e. FooKit
developers are prevented from writing code that would rely on FooKit's
implementation-only dependency being present when compiling clients of
FooKit. But right now it's not.

rdar://problem/48985979
This commit is contained in:
Jordan Rose
2019-03-28 15:57:53 -07:00
parent 9ed3fe061d
commit 0ba6c495ba
36 changed files with 336 additions and 58 deletions

View File

@@ -1020,16 +1020,18 @@ void
SourceFile::getImportedModules(SmallVectorImpl<ModuleDecl::ImportedModule> &modules,
ModuleDecl::ImportFilter filter) const {
assert(ASTStage >= Parsed || Kind == SourceFileKind::SIL);
assert(filter && "no imports requested?");
for (auto desc : Imports) {
if (desc.importOptions.contains(ImportFlags::Exported)) {
if (!filter.contains(ModuleDecl::ImportFilterKind::Public))
continue;
} else {
if (!filter.contains(ModuleDecl::ImportFilterKind::Private))
continue;
}
ModuleDecl::ImportFilterKind requiredKind;
if (desc.importOptions.contains(ImportFlags::Exported))
requiredKind = ModuleDecl::ImportFilterKind::Public;
else if (desc.importOptions.contains(ImportFlags::ImplementationOnly))
requiredKind = ModuleDecl::ImportFilterKind::ImplementationOnly;
else
requiredKind = ModuleDecl::ImportFilterKind::Private;
modules.push_back(desc.module);
if (filter.contains(requiredKind))
modules.push_back(desc.module);
}
}
@@ -1275,7 +1277,11 @@ forAllImportedModules(ModuleDecl *topLevel, ModuleDecl::AccessPathTy thisPath,
ModuleDecl::ImportFilter filter = ModuleDecl::ImportFilterKind::Public;
if (!respectVisibility)
filter |= ModuleDecl::ImportFilterKind::Private;
topLevel->getImportedModules(stack, filter);
ModuleDecl::ImportFilter topLevelFilter = filter;
if (!respectVisibility)
topLevelFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
topLevel->getImportedModules(stack, topLevelFilter);
// Make sure the top-level module is first; we want pre-order-ish traversal.
AccessPathTy overridingPath;
@@ -1326,9 +1332,11 @@ bool FileUnit::forAllVisibleModules(
if (auto SF = dyn_cast<SourceFile>(this)) {
// Handle privately visible modules as well.
// FIXME: Should this apply to all FileUnits?
ModuleDecl::ImportFilter importFilter;
importFilter |= ModuleDecl::ImportFilterKind::Private;
importFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
SmallVector<ModuleDecl::ImportedModule, 4> imports;
SF->getImportedModules(imports, ModuleDecl::ImportFilterKind::Private);
SF->getImportedModules(imports, importFilter);
for (auto importPair : imports)
if (!importPair.second->forAllVisibleModules(importPair.first, fn))
return false;