Skip to content

Commit aba3b6c

Browse files
committed
Introduce a package interface.
It has an extension .package.swiftinterface and contains package decls as well as SPIs and public/inlinable decls. When a module is loaded from interface, it now looks up the package-name in the interface and checks if the importer is in the same package. If so, it uses that package interface found to load the module. If not, uses the existing logic to load modules. Resolves rdar://104617854
1 parent 24dc372 commit aba3b6c

27 files changed

+367
-64
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ struct ShouldPrintChecker {
118118
virtual ~ShouldPrintChecker() = default;
119119
};
120120

121+
enum class PrintInterfaceContentMode : uint8_t {
122+
Public, // prints public/inlinable decls
123+
Private, // prints SPI and public/inlinable decls
124+
Package // prints package, SPI, and public/inlinable decls
125+
};
126+
121127
/// Options for printing AST nodes.
122128
///
123129
/// A default-constructed PrintOptions is suitable for printing to users;
@@ -299,8 +305,7 @@ struct PrintOptions {
299305
/// Whether to skip keywords with a prefix of underscore such as __consuming.
300306
bool SkipUnderscoredKeywords = false;
301307

302-
// Print SPI attributes and decls that are visible only as SPI.
303-
bool PrintSPIs = true;
308+
PrintInterfaceContentMode InterfaceContentMode;
304309

305310
/// Prints type variables and unresolved types in an expanded notation suitable
306311
/// for debugging.
@@ -684,7 +689,7 @@ struct PrintOptions {
684689
static PrintOptions printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
685690
bool preferTypeRepr,
686691
bool printFullConvention,
687-
bool printSPIs,
692+
PrintInterfaceContentMode interfaceContentMode,
688693
bool useExportedModuleNames,
689694
bool aliasModuleNames,
690695
llvm::SmallSet<StringRef, 4>

include/swift/Basic/FileTypes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ TYPE("swiftmodule", SwiftModuleFile, "swiftmodule", "")
5151
TYPE("swiftdoc", SwiftModuleDocFile, "swiftdoc", "")
5252
TYPE("swiftinterface", SwiftModuleInterfaceFile, "swiftinterface", "")
5353
TYPE("private-swiftinterface", PrivateSwiftModuleInterfaceFile, "private.swiftinterface", "")
54+
TYPE("package-swiftinterface", PackageSwiftModuleInterfaceFile, "package.swiftinterface", "")
5455
TYPE("swiftmodulesummary", SwiftModuleSummaryFile, "swiftmodulesummary", "")
5556
TYPE("swiftsourceinfo", SwiftSourceInfoFile, "swiftsourceinfo", "")
5657
TYPE("assembly", Assembly, "s", "")

include/swift/Basic/SupplementaryOutputPaths.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,14 @@ OUTPUT(ModuleInterfaceOutputPath, TY_SwiftModuleInterfaceFile)
137137
OUTPUT(PrivateModuleInterfaceOutputPath,
138138
TY_PrivateSwiftModuleInterfaceFile)
139139

140+
/// The path to which we should emit a package module interface.
141+
///
142+
/// The package interface contains package decls, SPIs, and public/inlinable decls.
143+
///
144+
/// \sa ModuleInterfaceOutputPath
145+
OUTPUT(PackageModuleInterfaceOutputPath,
146+
TY_PackageSwiftModuleInterfaceFile)
147+
140148
/// The path to which we should emit module summary file.
141149
OUTPUT(ModuleSummaryOutputPath, TY_SwiftModuleSummaryFile)
142150

include/swift/Driver/Action.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ class VerifyModuleInterfaceJobAction : public JobAction {
408408
: JobAction(Action::Kind::VerifyModuleInterfaceJob, { ModuleEmitter },
409409
file_types::TY_Nothing), inputType(inputType) {
410410
assert(inputType == file_types::TY_SwiftModuleInterfaceFile ||
411-
inputType == file_types::TY_PrivateSwiftModuleInterfaceFile);
411+
inputType == file_types::TY_PrivateSwiftModuleInterfaceFile ||
412+
inputType == file_types::TY_PackageSwiftModuleInterfaceFile);
412413
}
413414

414415
file_types::ID getInputType() const { return inputType; }

include/swift/Frontend/Frontend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ class CompilerInvocation {
432432
/// fail an assert if not in that mode.
433433
std::string getModuleInterfaceOutputPathForWholeModule() const;
434434
std::string getPrivateModuleInterfaceOutputPathForWholeModule() const;
435+
std::string getPackageModuleInterfaceOutputPathForWholeModule() const;
435436

436437
/// APIDescriptorPath only makes sense in whole module compilation mode,
437438
/// so return the APIDescriptorPath when in that mode and fail an assert

include/swift/Frontend/FrontendInputsAndOutputs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ class FrontendInputsAndOutputs {
264264
bool hasModuleSourceInfoOutputPath() const;
265265
bool hasModuleInterfaceOutputPath() const;
266266
bool hasPrivateModuleInterfaceOutputPath() const;
267+
bool hasPackageModuleInterfaceOutputPath() const;
267268
bool hasABIDescriptorOutputPath() const;
268269
bool hasAPIDescriptorOutputPath() const;
269270
bool hasConstValuesOutputPath() const;

include/swift/Frontend/ModuleInterfaceSupport.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ struct ModuleInterfaceOptions {
5555
/// e.g. -package-name PACKAGE_ID
5656
std::string IgnorablePrivateFlags;
5757

58-
/// Print for a private swiftinterface file, SPI decls and attributes.
59-
bool PrintPrivateInterfaceContent = false;
58+
/// Prints package, SPIs, or public/inlinable decls depending on the mode.
59+
PrintInterfaceContentMode InterfaceContentMode = PrintInterfaceContentMode::Public;
6060

6161
/// Print imports with both @_implementationOnly and @_spi, only applies
6262
/// when PrintSPIs is true.

include/swift/Option/Options.td

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ def ModuleInterfaceOption : OptionFlag;
5656
// The option can be safely ignored by the older compiler.
5757
def ModuleInterfaceOptionIgnorable : OptionFlag;
5858

59-
// The option should be written into a .private.swiftinterface module interface file,
60-
// and read/parsed from there when reconstituting a .swiftmodule from it.
59+
// The option should be written into a .private.swiftinterface or
60+
// .package.swiftinterface module interface file, and read/parsed from
61+
// there when reconstituting a .swiftmodule from it.
6162
// The option can be safely ignored by the older compiler.
6263
def ModuleInterfaceOptionIgnorablePrivate : OptionFlag;
6364

@@ -593,6 +594,12 @@ def emit_private_module_interface_path :
593594
ArgumentIsPath, SupplementaryOutput, CacheInvariant]>,
594595
MetaVarName<"<path>">, HelpText<"Output private module interface file to <path>">;
595596

597+
def emit_package_module_interface_path :
598+
Separate<["-"], "emit-package-module-interface-path">,
599+
Flags<[FrontendOption, NoInteractiveOption, HelpHidden,
600+
ArgumentIsPath, SupplementaryOutput, CacheInvariant]>,
601+
MetaVarName<"<path>">, HelpText<"Output package module interface file to <path>">;
602+
596603
def verify_emitted_module_interface :
597604
Flag<["-"], "verify-emitted-module-interface">,
598605
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,16 @@ struct SerializedModuleBaseName {
6262
/// Gets the filename with a particular extension appended to it.
6363
std::string getName(file_types::ID fileTy) const;
6464

65-
/// If the interface with \p baseName exists, returns its path (which may be
66-
/// the private interface if there is one). Return an empty optional
67-
/// otherwise.
65+
/// If the interface with \p baseName exists, returns its path (which may be the
66+
/// package interface if applicable (in the same package as the main module) or
67+
/// private interface if there is one, else public). Return an empty optional otherwise.
6868
llvm::Optional<std::string>
69-
findInterfacePath(llvm::vfs::FileSystem &fs) const;
69+
findInterfacePath(llvm::vfs::FileSystem &fs, ASTContext &ctx) const;
70+
71+
/// Returns the .package.swiftinterface path if its package-name also applies to
72+
/// the the importing module. Returns an empty optional otherwise.
73+
llvm::Optional<std::string>
74+
getPackageInterfacePathIfInSamePackage(llvm::vfs::FileSystem &fs, ASTContext &ctx) const;
7075
};
7176

7277
/// Common functionality shared between \c ImplicitSerializedModuleLoader,

lib/AST/ASTPrinter.cpp

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,24 @@ static bool isPublicOrUsableFromInline(Type ty) {
117117
});
118118
}
119119

120+
static bool isPackage(const ValueDecl *VD) {
121+
AccessScope scope =
122+
VD->getFormalAccessScope(/*useDC*/nullptr,
123+
/*treatUsableFromInlineAsPublic*/true);
124+
return scope.isPackage();
125+
}
126+
127+
static bool isPackage(Type ty) {
128+
// \see isPublicOrUsableFromInline(Type ty)
129+
return !ty.findIf([](Type typePart) -> bool {
130+
if (auto *aliasTy = dyn_cast<TypeAliasType>(typePart.getPointer()))
131+
return !isPackage(aliasTy->getDecl());
132+
if (auto *nominal = typePart->getAnyNominal())
133+
return !isPackage(nominal);
134+
return false;
135+
});
136+
}
137+
120138
static bool isPrespecilizationDeclWithTarget(const ValueDecl *vd) {
121139
// Add exported prespecialized symbols.
122140
for (auto *attr : vd->getAttrs().getAttributes<SpecializeAttr>()) {
@@ -156,7 +174,7 @@ static bool shouldTypeCheck(const PrintOptions &options) {
156174
PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
157175
bool preferTypeRepr,
158176
bool printFullConvention,
159-
bool printSPIs,
177+
PrintInterfaceContentMode interfaceContentMode,
160178
bool useExportedModuleNames,
161179
bool aliasModuleNames,
162180
llvm::SmallSet<StringRef, 4>
@@ -188,7 +206,7 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
188206
result.PrintFunctionRepresentationAttrs =
189207
PrintOptions::FunctionRepresentationMode::Full;
190208
result.AlwaysTryPrintParameterLabels = true;
191-
result.PrintSPIs = printSPIs;
209+
result.InterfaceContentMode = interfaceContentMode;
192210
result.DesugarExistentialConstraint = true;
193211

194212
// We should print __consuming, __owned, etc for the module interface file.
@@ -220,7 +238,7 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
220238
return false;
221239

222240
// Skip SPI decls if `PrintSPIs`.
223-
if (!options.PrintSPIs && D->isSPI())
241+
if (options.InterfaceContentMode == PrintInterfaceContentMode::Public && D->isSPI())
224242
return false;
225243

226244
if (auto *VD = dyn_cast<ValueDecl>(D)) {
@@ -234,7 +252,8 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
234252
if (contributesToParentTypeStorage(ASD))
235253
return true;
236254

237-
return false;
255+
if (options.InterfaceContentMode != PrintInterfaceContentMode::Package || !isPackage(VD))
256+
return false;
238257
}
239258

240259
// Skip member implementations and @objc overrides in @objcImpl
@@ -268,15 +287,19 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
268287
}
269288

270289
for (const Requirement &req : ED->getGenericRequirements()) {
271-
if (!isPublicOrUsableFromInline(req.getFirstType()))
272-
return false;
290+
if (!isPublicOrUsableFromInline(req.getFirstType())) {
291+
if (options.InterfaceContentMode != PrintInterfaceContentMode::Package || !isPackage(req.getSecondType()))
292+
return false;
293+
}
273294

274295
switch (req.getKind()) {
275296
case RequirementKind::Conformance:
276297
case RequirementKind::Superclass:
277298
case RequirementKind::SameType:
278-
if (!isPublicOrUsableFromInline(req.getSecondType()))
279-
return false;
299+
if (!isPublicOrUsableFromInline(req.getSecondType())) {
300+
if (options.InterfaceContentMode != PrintInterfaceContentMode::Package || !isPackage(req.getSecondType()))
301+
return false;
302+
}
280303
break;
281304
case RequirementKind::SameShape:
282305
case RequirementKind::Layout:
@@ -1181,8 +1204,8 @@ void PrintAST::printAttributes(const Decl *D) {
11811204
}
11821205
}
11831206

1184-
// SPI groups
1185-
if (Options.PrintSPIs &&
1207+
// Add SPIs to both private and package interfaces
1208+
if (Options.InterfaceContentMode != PrintInterfaceContentMode::Public &&
11861209
DeclAttribute::canAttributeAppearOnDeclKind(
11871210
DAK_SPIAccessControl, D->getKind())) {
11881211
interleave(D->getSPIGroups(),
@@ -1270,6 +1293,10 @@ static bool mustPrintPropertyName(VarDecl *decl, const PrintOptions &opts) {
12701293
// if we serialized references to them using field indices.
12711294
if (contributesToParentTypeStorage(decl)) return true;
12721295

1296+
// Print a package decl if in print package mode (for .package.swiftinterface),
1297+
if (opts.InterfaceContentMode == PrintInterfaceContentMode::Package && isPackage(decl))
1298+
return true;
1299+
12731300
// If it's public or @usableFromInline, we must print the name because it's a
12741301
// visible entry-point.
12751302
if (isPublicOrUsableFromInline(decl)) return true;
@@ -5979,8 +6006,8 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
59796006
ModuleDecl::ImportFilter Filter = ModuleDecl::ImportFilterKind::Exported;
59806007
Filter |= ModuleDecl::ImportFilterKind::Default;
59816008

5982-
// For private swiftinterfaces, also look through @_spiOnly imports.
5983-
if (Options.PrintSPIs)
6009+
// For private or package swiftinterfaces, also look through @_spiOnly imports.
6010+
if (Options.InterfaceContentMode != PrintInterfaceContentMode::Public)
59846011
Filter |= ModuleDecl::ImportFilterKind::SPIOnly;
59856012

59866013
SmallVector<ImportedModule, 4> Imports;

lib/AST/Attr.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
10481048
return true;
10491049

10501050
case DAK_SPIAccessControl: {
1051-
if (!Options.PrintSPIs) return false;
1051+
if (Options.InterfaceContentMode == PrintInterfaceContentMode::Public) return false;
10521052

10531053
auto spiAttr = static_cast<const SPIAccessControlAttr*>(this);
10541054
interleave(spiAttr->getSPIGroups(),
@@ -1100,7 +1100,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
11001100
auto Attr = cast<AvailableAttr>(this);
11011101
if (Options.SuppressNoAsyncAvailabilityAttr && Attr->isNoAsync())
11021102
return false;
1103-
if (!Options.PrintSPIs && Attr->IsSPI) {
1103+
if (Options.InterfaceContentMode == PrintInterfaceContentMode::Public && Attr->IsSPI) {
11041104
assert(Attr->hasPlatform());
11051105
assert(Attr->Introduced.has_value());
11061106
Printer.printAttrName("@available");
@@ -1196,7 +1196,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
11961196
auto *attr = cast<SpecializeAttr>(this);
11971197
// Don't print the _specialize attribute if it is marked spi and we are
11981198
// asked to skip SPI.
1199-
if (!Options.PrintSPIs && !attr->getSPIGroups().empty())
1199+
if (Options.InterfaceContentMode == PrintInterfaceContentMode::Public && !attr->getSPIGroups().empty())
12001200
return false;
12011201

12021202
// Don't print the _specialize attribute if we are asked to skip the ones

lib/Basic/FileTypes.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ bool file_types::isTextual(ID Id) {
8282
case file_types::TY_YAMLOptRecord:
8383
case file_types::TY_SwiftModuleInterfaceFile:
8484
case file_types::TY_PrivateSwiftModuleInterfaceFile:
85+
case file_types::TY_PackageSwiftModuleInterfaceFile:
8586
case file_types::TY_SwiftOverlayFile:
8687
case file_types::TY_JSONDependencies:
8788
case file_types::TY_JSONFeatures:
@@ -161,6 +162,7 @@ bool file_types::isAfterLLVM(ID Id) {
161162
case file_types::TY_BitstreamOptRecord:
162163
case file_types::TY_SwiftModuleInterfaceFile:
163164
case file_types::TY_PrivateSwiftModuleInterfaceFile:
165+
case file_types::TY_PackageSwiftModuleInterfaceFile:
164166
case file_types::TY_JSONDependencies:
165167
case file_types::TY_JSONFeatures:
166168
case file_types::TY_IndexUnitOutputPath:
@@ -203,6 +205,7 @@ bool file_types::isPartOfSwiftCompilation(ID Id) {
203205
case file_types::TY_SwiftModuleDocFile:
204206
case file_types::TY_SwiftModuleInterfaceFile:
205207
case file_types::TY_PrivateSwiftModuleInterfaceFile:
208+
case file_types::TY_PackageSwiftModuleInterfaceFile:
206209
case file_types::TY_SwiftSourceInfoFile:
207210
case file_types::TY_SwiftCrossImportDir:
208211
case file_types::TY_SwiftOverlayFile:
@@ -263,6 +266,7 @@ bool file_types::isProducedFromDiagnostics(ID Id) {
263266
case file_types::TY_SwiftModuleDocFile:
264267
case file_types::TY_SwiftModuleInterfaceFile:
265268
case file_types::TY_PrivateSwiftModuleInterfaceFile:
269+
case file_types::TY_PackageSwiftModuleInterfaceFile:
266270
case file_types::TY_SwiftSourceInfoFile:
267271
case file_types::TY_SwiftCrossImportDir:
268272
case file_types::TY_SwiftOverlayFile:

lib/Driver/Driver.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,7 +1711,8 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
17111711
options::OPT_emit_objc_header_path,
17121712
options::OPT_emit_module_interface,
17131713
options::OPT_emit_module_interface_path,
1714-
options::OPT_emit_private_module_interface_path) &&
1714+
options::OPT_emit_private_module_interface_path,
1715+
options::OPT_emit_package_module_interface_path) &&
17151716
OI.CompilerMode != OutputInfo::Mode::SingleCompile) {
17161717
// An option has been passed which requires whole-module knowledge, but we
17171718
// don't have that. Generate a module, but treat it as an intermediate
@@ -2095,6 +2096,7 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
20952096
case file_types::TY_BitstreamOptRecord:
20962097
case file_types::TY_SwiftModuleInterfaceFile:
20972098
case file_types::TY_PrivateSwiftModuleInterfaceFile:
2099+
case file_types::TY_PackageSwiftModuleInterfaceFile:
20982100
case file_types::TY_SwiftModuleSummaryFile:
20992101
case file_types::TY_SwiftCrossImportDir:
21002102
case file_types::TY_SwiftOverlayFile:
@@ -2346,6 +2348,11 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
23462348
C.createAction<VerifyModuleInterfaceJobAction>(MergeModuleAction,
23472349
file_types::TY_PrivateSwiftModuleInterfaceFile));
23482350
}
2351+
if (Args.hasArgNoClaim(options::OPT_emit_package_module_interface_path)) {
2352+
TopLevelActions.push_back(
2353+
C.createAction<VerifyModuleInterfaceJobAction>(MergeModuleAction,
2354+
file_types::TY_PackageSwiftModuleInterfaceFile));
2355+
}
23492356
}
23502357
}
23512358

@@ -2988,6 +2995,10 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
29882995
chooseModuleInterfacePath(C, JA, workingDirectory, Buf,
29892996
file_types::TY_PrivateSwiftModuleInterfaceFile, Output.get());
29902997

2998+
if (C.getArgs().hasArg(options::OPT_emit_package_module_interface_path))
2999+
chooseModuleInterfacePath(C, JA, workingDirectory, Buf,
3000+
file_types::TY_PackageSwiftModuleInterfaceFile, Output.get());
3001+
29913002
if (C.getArgs().hasArg(options::OPT_update_code) && isa<CompileJobAction>(JA))
29923003
chooseRemappingOutputPath(C, OutputMap, Output.get());
29933004

@@ -3351,9 +3362,11 @@ void Driver::chooseModuleInterfacePath(Compilation &C, const JobAction *JA,
33513362
llvm_unreachable("these modes aren't usable with 'swiftc'");
33523363
}
33533364

3354-
auto pathOpt = fileType == file_types::TY_SwiftModuleInterfaceFile?
3355-
options::OPT_emit_module_interface_path:
3356-
options::OPT_emit_private_module_interface_path;
3365+
auto pathOpt = options::OPT_emit_module_interface_path;
3366+
if (fileType == file_types::TY_PrivateSwiftModuleInterfaceFile)
3367+
pathOpt = options::OPT_emit_private_module_interface_path;
3368+
else if (fileType == file_types::TY_PackageSwiftModuleInterfaceFile)
3369+
pathOpt = options::OPT_emit_package_module_interface_path;
33573370

33583371
StringRef outputPath = *getOutputFilenameFromPathArgOrAsTopLevel(
33593372
C.getOutputInfo(), C.getArgs(), pathOpt, fileType,

0 commit comments

Comments
 (0)