Prevent PrintOptions from being implicitly copied.

NFC *except* that I noticed a bug by inspection where we suppress
`@escaping` when print enum element types. Since this affects
recursive positions, we end up suppressing `@escaping` in places
we shouldn't. This is unlikely to affect much real code, but should
still obviously be fixed.

The new design is a little sketchy in that we're using `const` to
prevent direct use (and allow initialization of `const &` parameters)
but still relying on modification of the actual object.  Essentially,
we are treating the `const`-ness of the reference as a promise to leave
the original value in the object after computation rather than a
guarantee of not modifying the object. This is okay --- a temporary
bound to a `const` reference is still a non-`const` object formally
and can be modified without invoking UB --- but makes me a little
uncomfortable.
This commit is contained in:
John McCall
2025-06-04 22:28:33 -04:00
parent 67b55566fe
commit b3493bfa23
17 changed files with 411 additions and 241 deletions

View File

@@ -442,7 +442,7 @@ StringRef getAccessorKindString(AccessorKind value);
/// may be called multiple times if the declaration uses suppressible
/// features.
void printWithCompatibilityFeatureChecks(ASTPrinter &printer,
PrintOptions &options,
const PrintOptions &options,
Decl *decl,
llvm::function_ref<void()> printBody);

View File

@@ -502,8 +502,8 @@ public:
ArrayRef<GenericTypeParamType *> genericParams,
ArrayRef<Requirement> requirements);
void print(raw_ostream &OS, PrintOptions Options = PrintOptions()) const;
void print(ASTPrinter &Printer, PrintOptions Opts = PrintOptions()) const;
void print(raw_ostream &OS, const PrintOptions &Options = PrintOptions()) const;
void print(ASTPrinter &Printer, const PrintOptions &Opts = PrintOptions()) const;
SWIFT_DEBUG_DUMP;
std::string getAsString() const;

View File

@@ -19,6 +19,7 @@
#include "swift/Basic/STLExtras.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/STLExtras.h"
#include <limits.h>
#include <optional>
#include <vector>
@@ -72,15 +73,15 @@ public:
CloseExtension(CloseExtension),
CloseNominal(CloseNominal) {}
bool shouldOpenExtension(const Decl *D) {
bool shouldOpenExtension(const Decl *D) const {
return D != Target || OpenExtension;
}
bool shouldCloseExtension(const Decl *D) {
bool shouldCloseExtension(const Decl *D) const {
return D != Target || CloseExtension;
}
bool shouldCloseNominal(const Decl *D) {
bool shouldCloseNominal(const Decl *D) const {
return D != Target || CloseNominal;
}
};
@@ -127,7 +128,39 @@ struct ShouldPrintChecker {
///
/// A default-constructed PrintOptions is suitable for printing to users;
/// there are also factory methods for specific use cases.
///
/// The value semantics of PrintOptions are a little messed up. We generally
/// pass around options by const reference in order to (1) make it
/// easier to pass in temporaries and (2) discourage direct local mutation
/// in favor of the OverrideScope system below. However, that override
/// system assumes that PrintOptions objects are always actually mutable.
struct PrintOptions {
/// Explicitly copy these print options. You should generally aim to
/// avoid doing this, especially in deeply-embedded code, because
/// PrintOptions is a relatively heavyweight type (and is likely to
/// only get more heavyweight). Instead, try to use OverrideScope.
PrintOptions clone() const { return *this; }
/// Allow move construction and assignment. We don't expect to
/// actually use these much, but there isn't too much harm from
/// them.
PrintOptions(PrintOptions &&) = default;
PrintOptions &operator=(PrintOptions &&) = default;
private:
/// Disallow implicit copying, but make it available privately for the
/// use of clone().
PrintOptions(const PrintOptions &) = default;
/// Disallow copy assignment completely, which we don't even need
/// privately.
PrintOptions &operator=(const PrintOptions &) = delete;
public:
// defined later in this file
class OverrideScope;
/// The indentation width.
unsigned Indent = 2;
@@ -749,6 +782,8 @@ struct PrintOptions {
void setBaseType(Type T);
void initForSynthesizedExtension(TypeOrExtensionDecl D);
void initForSynthesizedExtensionInScope(TypeOrExtensionDecl D,
OverrideScope &scope) const;
void clearSynthesizedExtension();
@@ -823,7 +858,87 @@ struct PrintOptions {
PO.AlwaysTryPrintParameterLabels = true;
return PO;
}
/// An RAII scope for performing temporary adjustments to a PrintOptions
/// object. Even with the abstraction inherent in this design, this can
/// be significantly cheaper than copying the options just to modify a few
/// fields.
///
/// At its core, this is just a stack of arbitrary functions to run
/// when the scope is destroyed.
class OverrideScope {
public:
/// The mutable options exposed by the scope. Generally, you should not
/// access this directly.
PrintOptions &Options;
private:
/// A stack of finalizer functions, each of which generally undoes some
/// change that was made to the options.
SmallVector<std::function<void(PrintOptions &)>, 4> Finalizers;
public:
OverrideScope(const PrintOptions &options)
: Options(const_cast<PrintOptions &>(options)) {}
// Disallow all copies and moves.
OverrideScope(const OverrideScope &scope) = delete;
OverrideScope &operator=(const OverrideScope &scope) = delete;
~OverrideScope() {
// Run the finalizers in the opposite order that they were added.
for (auto &finalizer : llvm::reverse(Finalizers)) {
finalizer(Options);
}
}
template <class Fn>
void addFinalizer(Fn &&fn) {
Finalizers.emplace_back(std::move(fn));
}
void addExcludedAttr(AnyAttrKind kind) {
Options.ExcludeAttrList.push_back(kind);
addFinalizer([](PrintOptions &options) {
options.ExcludeAttrList.pop_back();
});
}
};
};
}
/// Override a print option within an OverrideScope. Does a check to see if
/// the new value is the same as the old before actually doing anything, so
/// it only works if the type provides ==.
///
/// Signature is:
/// void (OverrideScope &scope, <FIELD NAME>, T &&newValue)
#define OVERRIDE_PRINT_OPTION(SCOPE, FIELD_NAME, VALUE) \
do { \
auto _newValue = (VALUE); \
if ((SCOPE).Options.FIELD_NAME != _newValue) { \
auto finalizer = \
[_oldValue=(SCOPE).Options.FIELD_NAME](PrintOptions &opts) { \
opts.FIELD_NAME = _oldValue; \
}; \
(SCOPE).Options.FIELD_NAME = std::move(_newValue); \
(SCOPE).addFinalizer(std::move(finalizer)); \
} \
} while(0)
/// Override a print option within an OverrideScope. Works for any type.
///
/// Signature is:
/// void (OverrideScope &scope, <FIELD NAME>, T &&newValue)
#define OVERRIDE_PRINT_OPTION_UNCONDITIONAL(SCOPE, FIELD_NAME, VALUE) \
do { \
auto finalizer = \
[_oldValue=(SCOPE).Options.FIELD_NAME](PrintOptions &opts) { \
opts.FIELD_NAME = _oldValue; \
}; \
(SCOPE).Options.FIELD_NAME = (VALUE); \
(SCOPE).addFinalizer(std::move(finalizer)); \
} while(0)
} // end namespace swift
#endif // LLVM_SWIFT_AST_PRINTOPTIONS_H

View File

@@ -216,7 +216,7 @@ private:
/// Print this graph node.
void print(llvm::raw_ostream &out, unsigned indent,
PrintOptions PO = PrintOptions()) const;
const PrintOptions &PO = PrintOptions()) const;
SWIFT_DEBUG_DUMP;

View File

@@ -197,7 +197,7 @@ namespace swift {
Implementation &Impl;
public:
SynthesizedExtensionAnalyzer(NominalTypeDecl *Target,
PrintOptions Options,
PrintOptions &&Options,
bool IncludeUnconditional = true);
~SynthesizedExtensionAnalyzer();

View File

@@ -1720,7 +1720,8 @@ namespace {
/// Prints a type as a field. If writing a parsable output format, the
/// `PrintOptions` are ignored and the type is written as a USR; otherwise,
/// the type is stringified using the `PrintOptions`.
void printTypeField(Type Ty, Label label, PrintOptions opts = PrintOptions(),
void printTypeField(Type Ty, Label label,
const PrintOptions &opts = PrintOptions(),
TerminalColor Color = TypeColor) {
if (Writer.isParsable()) {
printField(typeUSR(Ty), label, Color);

View File

@@ -103,6 +103,13 @@ void PrintOptions::initForSynthesizedExtension(TypeOrExtensionDecl D) {
TransformContext = TypeTransformContext(D);
}
void PrintOptions::initForSynthesizedExtensionInScope(TypeOrExtensionDecl D,
OverrideScope &scope) const {
assert(this == &scope.Options);
OVERRIDE_PRINT_OPTION_UNCONDITIONAL(scope, TransformContext,
TypeTransformContext(D));
}
void PrintOptions::clearSynthesizedExtension() {
TransformContext.reset();
}
@@ -197,9 +204,9 @@ bool PrintOptions::excludeAttr(const DeclAttribute *DA) const {
/// Forces printing types with the `some` keyword, instead of the full stable
/// reference.
struct PrintWithOpaqueResultTypeKeywordRAII {
PrintWithOpaqueResultTypeKeywordRAII(PrintOptions &Options)
: Options(Options) {
SavedMode = Options.OpaqueReturnTypePrinting;
PrintWithOpaqueResultTypeKeywordRAII(const PrintOptions &options)
: Options(const_cast<PrintOptions&>(options)) {
SavedMode = options.OpaqueReturnTypePrinting;
Options.OpaqueReturnTypePrinting =
PrintOptions::OpaqueReturnTypePrintingMode::WithOpaqueKeyword;
}
@@ -376,9 +383,9 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
if (auto *element = ECD->getFirstElement()) {
// Enum elements are usually not printed, so we have to override the
// print option controlling that.
PrintOptions optionsCopy = options;
optionsCopy.ExplodeEnumCaseDecls = true;
if (!shouldPrint(element, optionsCopy))
PrintOptions::OverrideScope scope(options);
OVERRIDE_PRINT_OPTION(scope, ExplodeEnumCaseDecls, true);
if (!shouldPrint(element, options))
return false;
}
}
@@ -671,7 +678,7 @@ namespace {
/// AST pretty-printer.
class PrintAST : public ASTVisitor<PrintAST> {
ASTPrinter &Printer;
PrintOptions Options;
const PrintOptions &Options;
unsigned IndentLevel = 0;
Decl *Current = nullptr;
Type CurrentType;
@@ -936,11 +943,14 @@ class PrintAST : public ASTVisitor<PrintAST> {
return T;
}
void printTransformedTypeWithOptions(Type T, PrintOptions options) {
void printTransformedTypeWithOptions(Type T,
const PrintOptions &options) {
T = getTransformedType(T);
PrintOptions::OverrideScope scope(options);
if (CurrentType && Current && CurrentType->mayHaveMembers())
options.TransformContext = TypeTransformContext(CurrentType);
OVERRIDE_PRINT_OPTION_UNCONDITIONAL(scope, TransformContext,
TypeTransformContext(CurrentType));
printTypeWithOptions(T, options);
}
@@ -981,9 +991,9 @@ class PrintAST : public ASTVisitor<PrintAST> {
}
void printTypeLocForImplicitlyUnwrappedOptional(TypeLoc TL, bool IUO) {
PrintOptions options = Options;
options.PrintOptionalAsImplicitlyUnwrapped = IUO;
printTypeLocWithOptions(TL, options);
PrintOptions::OverrideScope scope(Options);
OVERRIDE_PRINT_OPTION(scope, PrintOptionalAsImplicitlyUnwrapped, IUO);
printTypeLocWithOptions(TL, Options);
}
void printContextIfNeeded(const Decl *decl) {
@@ -1095,11 +1105,12 @@ private:
bool printASTNodes(const ArrayRef<ASTNode> &Elements, bool NeedIndent = true);
void printOneParameter(const ParamDecl *param, ParameterTypeFlags paramFlags,
bool ArgNameIsAPIByDefault);
bool ArgNameIsAPIByDefault, bool isEnumElement);
void printParameterList(ParameterList *PL,
ArrayRef<AnyFunctionType::Param> params,
bool isAPINameByDefault);
bool isAPINameByDefault,
bool isEnumElement);
/// Print the function parameters in curried or selector style,
/// to match the original function declaration.
@@ -1289,12 +1300,18 @@ void PrintAST::printAttributes(const Decl *D) {
// for each decl They cannot be shared across different decls.
assert(Options.ExcludeCustomAttrList.empty());
PrintOptions::OverrideScope scope(Options);
scope.addFinalizer([originalExcludeAttrCount](PrintOptions &options) {
options.ExcludeAttrList.resize(originalExcludeAttrCount);
options.ExcludeCustomAttrList.clear();
});
// If there is an `@abi` attr, we need to print it first so that it isn't
// affected by subsequent mutation of `Options.ExcludeAttrList`.
if (auto abiAttr = attrs.getAttribute<ABIAttr>()) {
if (Options.PrintImplicitAttrs && !Options.excludeAttr(abiAttr)) {
abiAttr->print(Printer, Options, D);
Options.ExcludeAttrList.push_back(DeclAttrKind::ABI);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::ABI);
}
}
@@ -1315,7 +1332,7 @@ void PrintAST::printAttributes(const Decl *D) {
Printer.printEscapedStringLiteral(
"this compiler cannot match the ABI specified by the @abi attribute");
Printer << ")\n";
Options.ExcludeAttrList.push_back(DeclAttrKind::Available);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Available);
}
}
@@ -1324,7 +1341,7 @@ void PrintAST::printAttributes(const Decl *D) {
// Don't print a redundant 'final' if we are printing a 'static' decl.
if (D->getDeclContext()->getSelfClassDecl() &&
getCorrectStaticSpelling(D) == StaticSpellingKind::KeywordStatic) {
Options.ExcludeAttrList.push_back(DeclAttrKind::Final);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Final);
}
if (auto vd = dyn_cast<VarDecl>(D)) {
@@ -1333,7 +1350,7 @@ void PrintAST::printAttributes(const Decl *D) {
// @objcImplementation extension (where final properties should appear
// computed).
if (vd->isInitExposedToClients() || vd->isResilient() || isInObjCImpl(vd))
Options.ExcludeAttrList.push_back(DeclAttrKind::HasInitialValue);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::HasInitialValue);
if (!Options.PrintForSIL) {
// Don't print @_hasStorage if the value is simply stored, or the
@@ -1341,7 +1358,7 @@ void PrintAST::printAttributes(const Decl *D) {
if (vd->isResilient() || isInObjCImpl(vd) ||
(vd->getImplInfo().isSimpleStored() &&
!hasLessAccessibleSetter(vd)))
Options.ExcludeAttrList.push_back(DeclAttrKind::HasStorage);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::HasStorage);
}
}
@@ -1356,14 +1373,14 @@ void PrintAST::printAttributes(const Decl *D) {
Printer << "(" << spiName << ") ";
},
[&] { Printer << ""; });
Options.ExcludeAttrList.push_back(DeclAttrKind::SPIAccessControl);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::SPIAccessControl);
}
// Don't print any contextual decl modifiers.
// We will handle 'mutating' and 'nonmutating' separately.
if (isa<AccessorDecl>(D)) {
#define EXCLUDE_ATTR(Class) \
Options.ExcludeAttrList.push_back(DeclAttrKind::Class);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Class);
#define CONTEXTUAL_DECL_ATTR(X, Class, ...) EXCLUDE_ATTR(Class)
#define CONTEXTUAL_SIMPLE_DECL_ATTR(X, Class, ...) EXCLUDE_ATTR(Class)
#define CONTEXTUAL_DECL_ATTR_ALIAS(X, Class) EXCLUDE_ATTR(Class)
@@ -1398,32 +1415,28 @@ void PrintAST::printAttributes(const Decl *D) {
if (auto ED = dyn_cast<ExtensionDecl>(D)) {
if (ED->isObjCImplementation() &&
Options.excludeAttrKind(DeclAttrKind::ObjCImplementation)) {
Options.ExcludeAttrList.push_back(DeclAttrKind::ObjC);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::ObjC);
}
}
// We will handle ownership specifiers separately.
if (isa<FuncDecl>(D)) {
Options.ExcludeAttrList.push_back(DeclAttrKind::Mutating);
Options.ExcludeAttrList.push_back(DeclAttrKind::NonMutating);
Options.ExcludeAttrList.push_back(DeclAttrKind::LegacyConsuming);
Options.ExcludeAttrList.push_back(DeclAttrKind::Consuming);
Options.ExcludeAttrList.push_back(DeclAttrKind::Borrowing);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Mutating);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::NonMutating);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::LegacyConsuming);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Consuming);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Borrowing);
}
if (isa<DestructorDecl>(D) && Options.SuppressIsolatedDeinit) {
Options.ExcludeAttrList.push_back(DeclAttrKind::Nonisolated);
Options.ExcludeAttrList.push_back(DeclAttrKind::Isolated);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Nonisolated);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Isolated);
if (auto globalActor = D->getGlobalActorAttr()) {
Options.ExcludeCustomAttrList.push_back(globalActor->first);
scope.Options.ExcludeCustomAttrList.push_back(globalActor->first);
}
}
attrs.print(Printer, Options, D);
Options.ExcludeAttrList.resize(originalExcludeAttrCount);
Options.ExcludeCustomAttrList.clear();
}
void PrintAST::printTypedPattern(const TypedPattern *TP) {
@@ -3063,13 +3076,9 @@ void PrintAST::visitUsingDecl(UsingDecl *decl) {
}
void PrintAST::printExtendedTypeName(TypeLoc ExtendedTypeLoc) {
bool OldFullyQualifiedTypesIfAmbiguous =
Options.FullyQualifiedTypesIfAmbiguous;
Options.FullyQualifiedTypesIfAmbiguous =
Options.FullyQualifiedExtendedTypesIfAmbiguous;
SWIFT_DEFER {
Options.FullyQualifiedTypesIfAmbiguous = OldFullyQualifiedTypesIfAmbiguous;
};
PrintOptions::OverrideScope scope(Options);
OVERRIDE_PRINT_OPTION(scope, FullyQualifiedTypesIfAmbiguous,
Options.FullyQualifiedExtendedTypesIfAmbiguous);
// Strip off generic arguments, if any.
auto Ty = ExtendedTypeLoc.getType()->getAnyNominal()->getDeclaredType();
@@ -3128,10 +3137,10 @@ void PrintAST::printSynthesizedExtensionImpl(Type ExtendedType,
if (auto *NTD = Target->getExtendedNominal()) {
// Update the current decl and type transform for Target rather than
// ExtDecl.
PrintOptions Adjusted = Options;
Adjusted.initForSynthesizedExtension(NTD);
PrintOptions::OverrideScope scope(Options);
Options.initForSynthesizedExtensionInScope(NTD, scope);
llvm::SaveAndRestore<Decl*> TempCurrent(Current, NTD);
llvm::SaveAndRestore<PrintOptions> TempOptions(Options, Adjusted);
printRequirementsFrom(Target, IsFirst);
}
}
@@ -3317,8 +3326,13 @@ suppressingFeatureExtensibleAttribute(PrintOptions &options,
}
/// Suppress the printing of a particular feature.
static void suppressingFeature(PrintOptions &options, Feature feature,
static void suppressingFeature(const PrintOptions &_options, Feature feature,
llvm::function_ref<void()> action) {
// Just as we do in OverrideScope, we assume that PrintOptions objects are
// always actually temporarily mutable. We do this here to avoid needing
// a const_cast in each of the individual suppression functions above.
auto &options = const_cast<PrintOptions&>(_options);
switch (feature) {
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
case Feature::FeatureName: \
@@ -3367,7 +3381,7 @@ static void printCompatibilityCheckIf(ASTPrinter &printer, bool isElseIf,
/// Generate a #if ... #elseif ... #endif chain for the given
/// suppressible feature checks.
static void printWithSuppressibleFeatureChecks(ASTPrinter &printer,
PrintOptions &options,
const PrintOptions &options,
bool firstInChain,
bool includeCompilerCheck,
FeatureSet::SuppressibleGenerator &generator,
@@ -3422,7 +3436,7 @@ static void printWithSuppressibleFeatureChecks(ASTPrinter &printer,
/// #endif
/// ```
void swift::printWithCompatibilityFeatureChecks(ASTPrinter &printer,
PrintOptions &options,
const PrintOptions &options,
Decl *decl,
llvm::function_ref<void()> printBody) {
// A single accessor does not get a feature check,
@@ -3621,8 +3635,8 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) {
//
// Remove this when we have a way to represent non-canonical archetypes
// preserving sugar.
llvm::SaveAndRestore<const GenericSignatureImpl *> setGenericSig(
Options.GenericSig, decl->getGenericSignature().getPointer());
PrintOptions::OverrideScope scope(Options);
OVERRIDE_PRINT_OPTION(scope, GenericSig, decl->getGenericSignature().getPointer());
printTypeLoc(TypeLoc(decl->getUnderlyingTypeRepr(), Ty));
printDeclGenericRequirements(decl);
}
@@ -3998,7 +4012,8 @@ void PrintAST::visitParamDecl(ParamDecl *decl) {
void PrintAST::printOneParameter(const ParamDecl *param,
ParameterTypeFlags paramFlags,
bool ArgNameIsAPIByDefault) {
bool ArgNameIsAPIByDefault,
bool isEnumElement) {
Printer.callPrintStructurePre(PrintStructureKind::FunctionParameter, param);
SWIFT_DEFER {
Printer.printStructurePost(PrintStructureKind::FunctionParameter, param);
@@ -4076,8 +4091,11 @@ void PrintAST::printOneParameter(const ParamDecl *param,
if (!param->isVariadic() &&
!willUseTypeReprPrinting(TheTypeLoc, CurrentType, Options)) {
auto type = TheTypeLoc.getType();
// We suppress `@escaping` on enum element parameters because it cannot
// be written explicitly in this position.
printParameterFlags(Printer, Options, param, paramFlags,
isEscaping(type),
isEscaping(type) && !isEnumElement,
param->isCallerIsolated());
}
@@ -4121,8 +4139,10 @@ void PrintAST::printOneParameter(const ParamDecl *param,
void PrintAST::printParameterList(ParameterList *PL,
ArrayRef<AnyFunctionType::Param> params,
bool isAPINameByDefault) {
llvm::SaveAndRestore<bool> scope(Options.PrintSyntheticSILGenName, false);
bool isAPINameByDefault,
bool isEnumElement) {
PrintOptions::OverrideScope scope(Options);
OVERRIDE_PRINT_OPTION(scope, PrintSyntheticSILGenName, false);
Printer.printStructurePre(PrintStructureKind::FunctionParameterList);
SWIFT_DEFER {
@@ -4137,7 +4157,7 @@ void PrintAST::printParameterList(ParameterList *PL,
? params[i].getParameterFlags()
: ParameterTypeFlags();
printOneParameter(PL->get(i), paramFlags,
isAPINameByDefault);
isAPINameByDefault, isEnumElement);
}
Printer << ")";
}
@@ -4172,7 +4192,8 @@ void PrintAST::printFunctionParameters(AbstractFunctionDecl *AFD) {
parameterListTypes = funTy->getParams();
printParameterList(BodyParams, parameterListTypes,
AFD->argumentNameIsAPIByDefault());
AFD->argumentNameIsAPIByDefault(),
/*isEnumElement*/false);
if (AFD->hasAsync() || AFD->hasThrows()) {
Printer.printStructurePre(PrintStructureKind::EffectsSpecifiers);
@@ -4383,9 +4404,9 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) {
// ourselves.
bool usedTypeReprPrinting = false;
{
llvm::SaveAndRestore<PrintOptions> printOptions(Options);
Options.PrintOptionalAsImplicitlyUnwrapped =
decl->isImplicitlyUnwrappedOptional();
PrintOptions::OverrideScope scope(Options);
OVERRIDE_PRINT_OPTION(scope, PrintOptionalAsImplicitlyUnwrapped,
decl->isImplicitlyUnwrappedOptional());
if (willUseTypeReprPrinting(ResultTyLoc, CurrentType, Options)) {
if (auto repr = ResultTyLoc.getTypeRepr()) {
// If we are printing a sending result... and we found that we have
@@ -4427,10 +4448,9 @@ void PrintAST::printEnumElement(EnumElementDecl *elt) {
});
if (auto *PL = elt->getParameterList()) {
llvm::SaveAndRestore<PrintOptions::ArgAndParamPrintingMode>
mode(Options.ArgAndParamPrinting,
PrintOptions::ArgAndParamPrintingMode::EnumElement);
PrintOptions::OverrideScope scope(Options);
OVERRIDE_PRINT_OPTION(scope, ArgAndParamPrinting,
PrintOptions::ArgAndParamPrintingMode::EnumElement);
auto params = ArrayRef<AnyFunctionType::Param>();
if (!elt->isInvalid()) {
@@ -4443,12 +4463,9 @@ void PrintAST::printEnumElement(EnumElementDecl *elt) {
->getParams();
}
// @escaping is not valid in enum element position, even though the
// attribute is implicitly added. Ignore it when printing the parameters.
Options.ExcludeAttrList.push_back(TypeAttrKind::Escaping);
printParameterList(PL, params,
/*isAPINameByDefault*/true);
Options.ExcludeAttrList.pop_back();
/*isAPINameByDefault*/true,
/*isEnumElement*/true);
}
switch (Options.EnumRawValues) {
@@ -4536,7 +4553,8 @@ void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) {
params = type->castTo<AnyFunctionType>()->getParams();
}
printParameterList(decl->getIndices(), params,
/*isAPINameByDefault*/false);
/*isAPINameByDefault*/false,
/*isEnumElement*/false);
});
{
@@ -4765,7 +4783,8 @@ void PrintAST::visitMacroDecl(MacroDecl *decl) {
params = type->castTo<AnyFunctionType>()->getParams();
}
printParameterList(
decl->parameterList, params, /*isAPINameByDefault*/true);
decl->parameterList, params, /*isAPINameByDefault*/true,
/*isEnumElement*/false);
}
}
);
@@ -6402,13 +6421,14 @@ public:
}
}
}
PrintOptions innerOptions = Options;
innerOptions.SynthesizeSugarOnTypes = false;
PrintOptions::OverrideScope scope(Options);
OVERRIDE_PRINT_OPTION(scope, SynthesizeSugarOnTypes, false);
if (auto sugarType = dyn_cast<SyntaxSugarType>(T.getPointer()))
T = sugarType->getImplementationType();
TypePrinter(Printer, innerOptions).printWithParensIfNotSimple(T);
TypePrinter(Printer, Options).printWithParensIfNotSimple(T);
Printer << ".";
}
@@ -6954,77 +6974,73 @@ public:
// Yeah, this is fiddly. In the end, we probably want all decls to have
// substituted types in terms of a generic signature declared on the decl,
// which would make this logic more uniform.
TypePrinter *sub = this;
std::optional<TypePrinter> subBuffer;
PrintOptions subOptions = Options;
if (auto substitutions = T->getPatternSubstitutions()) {
subOptions.GenericSig = nullptr;
subBuffer.emplace(Printer, subOptions);
sub = &*subBuffer;
GenericSignature sig = substitutions.getGenericSignature();
{
PrintOptions::OverrideScope scope(Options);
// The substituted signature is printed without inverse requirement
// desugaring, but also we drop conformances to Copyable and Escapable
// when constructing it.
sub->Printer << "@substituted ";
sub->printGenericSignature(sig,
PrintAST::PrintParams |
PrintAST::PrintRequirements);
sub->Printer << " ";
}
if (auto substitutions = T->getPatternSubstitutions()) {
OVERRIDE_PRINT_OPTION(scope, GenericSig, nullptr);
// Capture list used here to ensure we don't print anything using `this`
// printer, but only the sub-Printer.
[T, sub, &subOptions] {
sub->Printer << "(";
GenericSignature sig = substitutions.getGenericSignature();
// The substituted signature is printed without inverse requirement
// desugaring, but also we drop conformances to Copyable and Escapable
// when constructing it.
Printer << "@substituted ";
printGenericSignature(sig,
PrintAST::PrintParams |
PrintAST::PrintRequirements);
Printer << " ";
}
Printer << "(";
bool first = true;
unsigned paramIndex = 0;
for (auto param : T->getParameters()) {
sub->Printer.printSeparator(first, ", ");
param.print(sub->Printer, subOptions,
Printer.printSeparator(first, ", ");
param.print(Printer, Options,
T->getLifetimeDependenceFor(paramIndex));
paramIndex++;
}
sub->Printer << ") -> ";
Printer << ") -> ";
sub->Printer.printLifetimeDependence(T->getLifetimeDependenceForResult());
Printer.printLifetimeDependence(T->getLifetimeDependenceForResult());
bool parenthesizeResults = mustParenthesizeResults(T);
if (parenthesizeResults)
sub->Printer << "(";
Printer << "(";
first = true;
for (auto yield : T->getYields()) {
sub->Printer.printSeparator(first, ", ");
sub->Printer << "@yields ";
Printer.printSeparator(first, ", ");
Printer << "@yields ";
// TODO: Fix lifetime dependence printing here
yield.print(sub->Printer, subOptions);
yield.print(Printer, Options);
}
for (auto result : T->getResults()) {
sub->Printer.printSeparator(first, ", ");
result.print(sub->Printer, subOptions);
Printer.printSeparator(first, ", ");
result.print(Printer, Options);
}
if (T->hasErrorResult()) {
sub->Printer.printSeparator(first, ", ");
Printer.printSeparator(first, ", ");
if (T->getErrorResult().getConvention() == ResultConvention::Owned)
sub->Printer << "@error ";
Printer << "@error ";
else if (T->getErrorResult().getConvention() == ResultConvention::Indirect)
sub->Printer << "@error_indirect ";
Printer << "@error_indirect ";
else if (T->getErrorResult().getConvention() == ResultConvention::Unowned)
sub->Printer << "@error_unowned ";
Printer << "@error_unowned ";
else {
assert(false && "Should have error, error_indirect, or error_unowned");
}
T->getErrorResult().getInterfaceType().print(sub->Printer, subOptions);
T->getErrorResult().getInterfaceType().print(Printer, Options);
}
if (parenthesizeResults)
sub->Printer << ")";
}();
Printer << ")";
}
// Both the pattern and invocation substitution types are always in
// terms of the outer environment. But this wouldn't necessarily be
@@ -7071,31 +7087,26 @@ public:
{
// A box layout has its own independent generic environment. Don't try
// to print it with the environment's generic params.
PrintOptions subOptions = Options;
subOptions.GenericSig = nullptr;
TypePrinter sub(Printer, subOptions);
PrintOptions::OverrideScope scope(Options);
OVERRIDE_PRINT_OPTION(scope, GenericSig, nullptr);
// Capture list used here to ensure we don't print anything using `this`
// printer, but only the sub-Printer.
[&sub, T, options=Options]{
if (auto sig = T->getLayout()->getGenericSignature()) {
sub.printGenericSignature(sig,
PrintAST::PrintParams |
PrintAST::defaultGenericRequirementFlags(options));
sub.Printer << " ";
}
sub.Printer << "{";
interleave(T->getLayout()->getFields(),
[&](const SILField &field) {
sub.Printer <<
(field.isMutable() ? " var " : " let ");
sub.visit(field.getLoweredType());
},
[&]{
sub.Printer << ",";
});
sub.Printer << " }";
}();
if (auto sig = T->getLayout()->getGenericSignature()) {
printGenericSignature(sig,
PrintAST::PrintParams |
PrintAST::defaultGenericRequirementFlags(Options));
Printer << " ";
}
Printer << "{";
interleave(T->getLayout()->getFields(),
[&](const SILField &field) {
Printer <<
(field.isMutable() ? " var " : " let ");
visit(field.getLoweredType());
},
[&]{
Printer << ",";
});
Printer << " }";
}
// The arguments to the layout, if any, do come from the outer environment.
@@ -7259,10 +7270,9 @@ public:
auto &ctx = selfTy->getASTContext();
newAlternativeTypeNames[selfTy->getCanonicalType()] = ctx.Id_Self;
PrintOptions subOptions = Options;
subOptions.AlternativeTypeNames = &newAlternativeTypeNames;
TypePrinter sub(Printer, subOptions);
sub.visit(interfaceTy);
PrintOptions::OverrideScope scope(Options);
OVERRIDE_PRINT_OPTION(scope, AlternativeTypeNames, &newAlternativeTypeNames);
visit(interfaceTy);
} else {
visit(T->getExistentialType());
}
@@ -7646,10 +7656,12 @@ void LayoutConstraintInfo::print(ASTPrinter &Printer,
}
}
void GenericSignatureImpl::print(raw_ostream &OS, PrintOptions PO) const {
void GenericSignatureImpl::print(raw_ostream &OS,
const PrintOptions &PO) const {
GenericSignature(const_cast<GenericSignatureImpl *>(this)).print(OS, PO);
}
void GenericSignatureImpl::print(ASTPrinter &Printer, PrintOptions PO) const {
void GenericSignatureImpl::print(ASTPrinter &Printer,
const PrintOptions &PO) const {
GenericSignature(const_cast<GenericSignatureImpl *>(this)).print(Printer, PO);
}

View File

@@ -1380,9 +1380,10 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
if (typeErased)
Printer << "@_noMetadata ";
}
auto OptionsCopy = Options;
OptionsCopy.PrintInternalLayoutName = typeErased;
req.print(Printer, OptionsCopy);
PrintOptions::OverrideScope scope(Options);
OVERRIDE_PRINT_OPTION(scope, PrintInternalLayoutName, typeErased);
req.print(Printer, Options);
},
[&] { Printer << ", "; });
@@ -1703,7 +1704,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
->getVarAtSimilarStructuralPosition(
const_cast<VarDecl *>(cast<VarDecl>(D)));
if (abiDecl) {
auto optionsCopy = Options;
PrintOptions::OverrideScope scope(Options);
// Don't print any attributes marked with `ForbiddenInABIAttr`.
// (Reminder: There is manual logic in `PrintAST::printAttributes()`
@@ -1715,12 +1716,12 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
continue;
if (attrKind == DeclAttrKind::AccessControl)
optionsCopy.PrintAccess = false;
OVERRIDE_PRINT_OPTION(scope, PrintAccess, false);
else
optionsCopy.ExcludeAttrList.push_back(attrKind);
scope.addExcludedAttr(attrKind);
}
abiDecl->print(Printer, optionsCopy);
abiDecl->print(Printer, Options);
}
Printer << ")";

View File

@@ -704,8 +704,9 @@ public:
// Preserve the behavior of previous implementations which formatted of
// empty extensions compactly with '{}' on the same line.
PrintOptions extensionPrintOptions = printOptions;
extensionPrintOptions.PrintEmptyMembersOnSameLine = true;
PrintOptions::OverrideScope extensionPrintingScope(printOptions);
OVERRIDE_PRINT_OPTION(extensionPrintingScope,
PrintEmptyMembersOnSameLine, true);
// Then walk the remaining ones, and see what we need to print.
// FIXME: This will pick the availability attributes from the first sight
@@ -744,7 +745,7 @@ public:
!M->isImportedImplementationOnly(inherited->getParentModule())) {
auto protoAndAvailability = ProtocolAndAvailability(
inherited, availability, isUnchecked, otherAttrs);
printSynthesizedExtension(out, extensionPrintOptions, M, nominal,
printSynthesizedExtension(out, printOptions, M, nominal,
protoAndAvailability);
return TypeWalker::Action::SkipNode;
}

View File

@@ -408,7 +408,8 @@ void CodeCompletionResultBuilder::withNestedGroup(
--CurrentNestingLevel;
}
void CodeCompletionResultBuilder::addTypeAnnotation(Type T, PrintOptions PO,
void CodeCompletionResultBuilder::addTypeAnnotation(Type T,
const PrintOptions &PO,
StringRef suffix) {
T = T->getReferenceStorageReferent();

View File

@@ -468,7 +468,7 @@ public:
getLastChunk().setIsAnnotation();
}
void addTypeAnnotation(Type T, PrintOptions PO, StringRef suffix = "");
void addTypeAnnotation(Type T, const PrintOptions &PO, StringRef suffix = "");
void addBraceStmtWithCursor(StringRef Description = "") {
addChunkWithText(

View File

@@ -286,12 +286,12 @@ struct SynthesizedExtensionAnalyzer::Implementation {
Implementation(NominalTypeDecl *Target,
bool IncludeUnconditional,
PrintOptions Options):
PrintOptions &&Options):
Target(Target),
BaseType(Target->getDeclaredInterfaceType()),
DC(Target),
IncludeUnconditional(IncludeUnconditional),
Options(Options), AllGroups(MergeGroupVector()),
Options(std::move(Options)), AllGroups(MergeGroupVector()),
InfoMap(collectSynthesizedExtensionInfo(AllGroups)) {}
unsigned countInherits(ExtensionDecl *ED) {
@@ -484,14 +484,14 @@ struct SynthesizedExtensionAnalyzer::Implementation {
auto handleExtension = [&](ExtensionDecl *E, bool Synthesized,
ExtensionDecl *EnablingE,
NormalProtocolConformance *Conf) {
PrintOptions AdjustedOpts = Options;
PrintOptions::OverrideScope AdjustedOpts(Options);
if (Synthesized) {
// Members from underscored system protocols should still appear as
// members of the target type, even if the protocols themselves are not
// printed.
AdjustedOpts.SkipUnderscoredSystemProtocols = false;
OVERRIDE_PRINT_OPTION(AdjustedOpts, SkipUnderscoredSystemProtocols, false);
}
if (AdjustedOpts.shouldPrint(E)) {
if (Options.shouldPrint(E)) {
auto Pair = isApplicable(E, Synthesized, EnablingE, Conf);
if (Pair.first) {
InfoMap.insert({E, Pair.first});
@@ -556,8 +556,8 @@ struct SynthesizedExtensionAnalyzer::Implementation {
};
SynthesizedExtensionAnalyzer::SynthesizedExtensionAnalyzer(
NominalTypeDecl *Target, PrintOptions Options, bool IncludeUnconditional)
: Impl(*(new Implementation(Target, IncludeUnconditional, Options))) {}
NominalTypeDecl *Target, PrintOptions &&Options, bool IncludeUnconditional)
: Impl(*(new Implementation(Target, IncludeUnconditional, std::move(Options)))) {}
SynthesizedExtensionAnalyzer::~SynthesizedExtensionAnalyzer() {delete &Impl;}

View File

@@ -94,15 +94,15 @@ printTypeInterface(ModuleDecl *M, StringRef TypeUSR, ASTPrinter &Printer,
Printer, TypeName, Error);
}
static void adjustPrintOptions(PrintOptions &AdjustedOptions) {
static void adjustPrintOptions(PrintOptions::OverrideScope &Options) {
// Don't print empty curly braces while printing the module interface.
AdjustedOptions.FunctionDefinitions = false;
OVERRIDE_PRINT_OPTION(Options, FunctionDefinitions, false);
AdjustedOptions.PrintGetSetOnRWProperties = false;
OVERRIDE_PRINT_OPTION(Options, PrintGetSetOnRWProperties, false);
// Print var declarations separately, one variable per decl.
AdjustedOptions.ExplodePatternBindingDecls = true;
AdjustedOptions.VarInitializers = false;
OVERRIDE_PRINT_OPTION(Options, ExplodePatternBindingDecls, true);
OVERRIDE_PRINT_OPTION(Options, VarInitializers, false);
}
void swift::ide::collectModuleGroups(ModuleDecl *M,
@@ -138,7 +138,7 @@ std::optional<StringRef> swift::ide::findGroupNameForUSR(ModuleDecl *M,
/// \returns Whether the given decl was printed.
static bool printModuleInterfaceDecl(Decl *D,
ASTPrinter &Printer,
PrintOptions &Options,
const PrintOptions &Options,
bool PrintSynthesizedExtensions,
StringRef LeadingComment = StringRef()) {
if (!Options.shouldPrint(D)) {
@@ -156,16 +156,27 @@ static bool printModuleInterfaceDecl(Decl *D,
return false;
}
}
// It'd be nice to avoid cloning the options here, but that would require
// SynthesizedExtensionAnalyzer to promise to stay within the lifetime of
// the options it was constructed with, and besides, it isn't easy to see
// whether the mutations we make to Options here are meant to be independent
// of what might be done with the analyzer.
PrintOptions::OverrideScope OptionAdjustment(Options);
std::unique_ptr<SynthesizedExtensionAnalyzer> pAnalyzer;
if (auto NTD = dyn_cast<NominalTypeDecl>(D)) {
if (PrintSynthesizedExtensions) {
pAnalyzer.reset(new SynthesizedExtensionAnalyzer(NTD, Options));
Options.BracketOptions = {
pAnalyzer.reset(new SynthesizedExtensionAnalyzer(NTD, Options.clone()));
BracketOptions NewBracketOptions = {
NTD, true, true,
!pAnalyzer->hasMergeGroup(
SynthesizedExtensionAnalyzer::MergeGroupKind::MergeableWithTypeDef
)
};
OVERRIDE_PRINT_OPTION_UNCONDITIONAL(OptionAdjustment, BracketOptions,
NewBracketOptions);
}
}
if (!LeadingComment.empty() && Options.shouldPrint(D)) {
@@ -175,7 +186,8 @@ static bool printModuleInterfaceDecl(Decl *D,
if (D->print(Printer, Options)) {
if (Options.BracketOptions.shouldCloseNominal(D))
Printer.printNewline();
Options.BracketOptions = BracketOptions();
OVERRIDE_PRINT_OPTION_UNCONDITIONAL(OptionAdjustment, BracketOptions,
BracketOptions());
if (auto NTD = dyn_cast<NominalTypeDecl>(D)) {
std::queue<NominalTypeDecl *> SubDecls{{NTD}};
@@ -222,15 +234,18 @@ static bool printModuleInterfaceDecl(Decl *D,
SynthesizedExtensionAnalyzer::MergeGroupKind::MergeableWithTypeDef,
[&](ArrayRef<ExtensionInfo> Decls) {
for (auto ET : Decls) {
Options.BracketOptions = {
PrintOptions::OverrideScope ETOptionsScope(Options);
BracketOptions NewBracketOptions = {
ET.Ext, false, Decls.back().Ext == ET.Ext, true
};
OVERRIDE_PRINT_OPTION_UNCONDITIONAL(ETOptionsScope, BracketOptions,
NewBracketOptions);
if (ET.IsSynthesized)
Options.initForSynthesizedExtension(NTD);
Options.initForSynthesizedExtensionInScope(NTD, ETOptionsScope);
ET.Ext->print(Printer, Options);
if (ET.IsSynthesized)
Options.clearSynthesizedExtension();
if (Options.BracketOptions.shouldCloseExtension(ET.Ext))
if (NewBracketOptions.shouldCloseExtension(ET.Ext))
Printer.printNewline();
}
});
@@ -238,7 +253,7 @@ static bool printModuleInterfaceDecl(Decl *D,
// If the printed Decl is not the top-level one, reset analyzer.
if (!IsTopLevelDecl)
pAnalyzer.reset(new SynthesizedExtensionAnalyzer(NTD, Options));
pAnalyzer.reset(new SynthesizedExtensionAnalyzer(NTD, Options.clone()));
// Print the rest as synthesized extensions.
pAnalyzer->forEachExtensionMergeGroup(
@@ -251,10 +266,15 @@ static bool printModuleInterfaceDecl(Decl *D,
// Whether we've started the extension merge group in printing.
bool Opened = false;
for (auto ET : Decls) {
Options.BracketOptions = {
PrintOptions::OverrideScope ETOptionsScope(Options);
BracketOptions NewBracketOptions = {
ET.Ext, !Opened, Decls.back().Ext == ET.Ext, true
};
if (Options.BracketOptions.shouldOpenExtension(ET.Ext)) {
OVERRIDE_PRINT_OPTION_UNCONDITIONAL(ETOptionsScope, BracketOptions,
NewBracketOptions);
if (NewBracketOptions.shouldOpenExtension(ET.Ext)) {
Printer.printNewline();
if (Options.shouldPrint(ET.Ext) && !LeadingComment.empty()) {
Printer << LeadingComment;
@@ -263,20 +283,19 @@ static bool printModuleInterfaceDecl(Decl *D,
}
if (ET.IsSynthesized) {
if (ET.EnablingExt)
Options.initForSynthesizedExtension(ET.EnablingExt);
Options.initForSynthesizedExtensionInScope(ET.EnablingExt,
ETOptionsScope);
else
Options.initForSynthesizedExtension(NTD);
Options.initForSynthesizedExtensionInScope(NTD, ETOptionsScope);
}
// Set opened if we actually printed this extension.
Opened |= ET.Ext->print(Printer, Options);
if (ET.IsSynthesized)
Options.clearSynthesizedExtension();
if (Options.BracketOptions.shouldCloseExtension(ET.Ext)) {
if (NewBracketOptions.shouldCloseExtension(ET.Ext)) {
Printer.printNewline();
}
}
});
Options.BracketOptions = BracketOptions();
}
}
return true;
@@ -395,7 +414,7 @@ getDeclsFromCrossImportOverlay(ModuleDecl *Overlay, ModuleDecl *Declaring,
static void printCrossImportOverlays(ModuleDecl *Declaring, ASTContext &Ctx,
ASTPrinter &Printer,
PrintOptions Options,
const PrintOptions &Options,
bool PrintSynthesizedExtensions) {
SmallVector<Decl *, 1> OverlayDecls;
SmallVector<Identifier, 1> Bystanders;
@@ -483,8 +502,8 @@ void swift::ide::printModuleInterface(
auto &Importer =
static_cast<ClangImporter &>(*SwiftContext.getClangModuleLoader());
auto AdjustedOptions = Options;
adjustPrintOptions(AdjustedOptions);
PrintOptions::OverrideScope OptionAdjustment(Options);
adjustPrintOptions(OptionAdjustment);
llvm::DenseSet<const void *> SeenImportedDecls;
SmallVector<ModuleDecl *, 1> ModuleList;
@@ -722,7 +741,7 @@ void swift::ide::printModuleInterface(
std::stable_sort(SwiftDecls.begin(), SwiftDecls.end(), compareSwiftDecls);
auto PrintDecl = [&](Decl *D) {
return printModuleInterfaceDecl(D, Printer, AdjustedOptions,
return printModuleInterfaceDecl(D, Printer, Options,
PrintSynthesizedExtensions);
};
@@ -767,7 +786,7 @@ void swift::ide::printModuleInterface(
// is the underlying module of, transitively.
if (GroupNames.empty()) {
printCrossImportOverlays(TargetMod, SwiftContext, Printer,
AdjustedOptions, PrintSynthesizedExtensions);
Options, PrintSynthesizedExtensions);
}
}
// Flush pending newlines.
@@ -842,8 +861,8 @@ void swift::ide::printHeaderInterface(
ASTContext &Ctx,
ASTPrinter &Printer,
const PrintOptions &Options) {
auto AdjustedOptions = Options;
adjustPrintOptions(AdjustedOptions);
PrintOptions::OverrideScope OptionAdjustment(Options);
adjustPrintOptions(OptionAdjustment);
auto &Importer = static_cast<ClangImporter &>(*Ctx.getClangModuleLoader());
auto &ClangSM = Importer.getClangASTContext().getSourceManager();
@@ -874,11 +893,11 @@ void swift::ide::printHeaderInterface(
// equivalent Swift decl may not be. E.g. a top-level function may be mapped
// to a property accessor in Swift.
D = getTopLevelDecl(D);
if (!AdjustedOptions.shouldPrint(D)) {
if (!Options.shouldPrint(D)) {
Printer.callAvoidPrintDeclPost(D);
continue;
}
if (D->print(Printer, AdjustedOptions))
if (D->print(Printer, Options))
Printer.printNewline();
}
Printer.forceNewlines();

View File

@@ -4665,7 +4665,7 @@ void SILDebugScope::print(SILModule &Mod) const {
void SILSpecializeAttr::print(llvm::raw_ostream &OS) const {
SILPrintContext Ctx(OS);
// Print other types as their Swift representation.
PrintOptions SubPrinter = PrintOptions::printSIL();
PrintOptions options = PrintOptions::printSIL();
auto exported = isExported() ? "true" : "false";
auto kind = isPartialSpecialization() ? "partial" : "full";
@@ -4699,7 +4699,7 @@ void SILSpecializeAttr::print(llvm::raw_ostream &OS) const {
requirements,
[&](Requirement req) {
if (!genericSig) {
req.print(OS, SubPrinter);
req.print(OS, options);
return;
}
@@ -4717,13 +4717,15 @@ void SILSpecializeAttr::print(llvm::raw_ostream &OS) const {
if (req.getKind() != RequirementKind::Layout) {
auto SecondTy = genericSig->getSugaredType(req.getSecondType());
Requirement ReqWithDecls(req.getKind(), FirstTy, SecondTy);
ReqWithDecls.print(OS, SubPrinter);
ReqWithDecls.print(OS, options);
} else {
Requirement ReqWithDecls(req.getKind(), FirstTy,
req.getLayoutConstraint());
auto SubPrinterCopy = SubPrinter;
SubPrinterCopy.PrintInternalLayoutName = erased;
ReqWithDecls.print(OS, SubPrinterCopy);
PrintOptions::OverrideScope scope(options);
OVERRIDE_PRINT_OPTION(scope, PrintInternalLayoutName, erased);
ReqWithDecls.print(OS, options);
}
},
[&] { OS << ", "; });

View File

@@ -987,7 +987,7 @@ void ConstraintGraph::incrementConstraintsPerContractionCounter() {
#pragma mark Debugging output
void ConstraintGraphNode::print(llvm::raw_ostream &out, unsigned indent,
PrintOptions PO) const {
const PrintOptions &PO) const {
out.indent(indent);
Type(TypeVar).print(out, PO);
out << ":\n";

View File

@@ -0,0 +1,16 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name Test
// RUN: %FileCheck %s < %t.swiftinterface
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name Test
// This test fails if we suppress the @escaping attribute recursively
// when printing enum element parameter lists instead of only suppressing
// it when printing the immediate type of the enum payload.
public enum A {
case function(_: (@escaping () -> Void) -> Void)
}
// CHECK-LABEL: public enum A {
// CHECK-NEXT: case function((@escaping () -> Swift.Void) -> Swift.Void)
// CHECK-NEXT: }

View File

@@ -4636,41 +4636,43 @@ int main(int argc, char *argv[]) {
}
}
PrintOptions PrintOpts;
if (options::PrintInterface) {
PrintOpts = PrintOptions::printModuleInterface(
PrintOptions PrintOpts = [&] {
if (options::PrintInterface) {
return PrintOptions::printModuleInterface(
InitInvok.getFrontendOptions().PrintFullConvention);
} else if (options::PrintInterfaceForDoc) {
PrintOpts = PrintOptions::printDocInterface();
} else {
PrintOpts = PrintOptions::printEverything();
PrintOpts.FullyQualifiedTypes = options::FullyQualifiedTypes;
PrintOpts.FullyQualifiedTypesIfAmbiguous =
options::FullyQualifiedTypesIfAmbiguous;
PrintOpts.SynthesizeSugarOnTypes = options::SynthesizeSugarOnTypes;
PrintOpts.AbstractAccessors = options::AbstractAccessors;
PrintOpts.FunctionDefinitions = options::FunctionDefinitions;
PrintOpts.PrintExprs = options::Expressions;
PrintOpts.PreferTypeRepr = options::PreferTypeRepr;
PrintOpts.ExplodePatternBindingDecls = options::ExplodePatternBindingDecls;
PrintOpts.PrintImplicitAttrs = options::PrintImplicitAttrs;
PrintOpts.PrintAccess = options::PrintAccess;
PrintOpts.AccessFilter = options::AccessFilter;
PrintOpts.PrintDocumentationComments = !options::SkipDocumentationComments;
PrintOpts.SkipPrivateSystemDecls = options::SkipPrivateSystemDecls;
PrintOpts.SkipUnsafeCXXMethods = options::SkipUnsafeCXXMethods;
PrintOpts.SkipUnavailable = options::SkipUnavailable;
PrintOpts.SkipDeinit = options::SkipDeinit;
PrintOpts.SkipImports = options::SkipImports;
PrintOpts.SkipOverrides = options::SkipOverrides;
if (options::SkipParameterNames) {
PrintOpts.ArgAndParamPrinting
= PrintOptions::ArgAndParamPrintingMode::ArgumentOnly;
} else if (options::AlwaysArgumentLabels) {
PrintOpts.ArgAndParamPrinting
= PrintOptions::ArgAndParamPrintingMode::BothAlways;
} else if (options::PrintInterfaceForDoc) {
return PrintOptions::printDocInterface();
} else {
auto PrintOpts = PrintOptions::printEverything();
PrintOpts.FullyQualifiedTypes = options::FullyQualifiedTypes;
PrintOpts.FullyQualifiedTypesIfAmbiguous =
options::FullyQualifiedTypesIfAmbiguous;
PrintOpts.SynthesizeSugarOnTypes = options::SynthesizeSugarOnTypes;
PrintOpts.AbstractAccessors = options::AbstractAccessors;
PrintOpts.FunctionDefinitions = options::FunctionDefinitions;
PrintOpts.PrintExprs = options::Expressions;
PrintOpts.PreferTypeRepr = options::PreferTypeRepr;
PrintOpts.ExplodePatternBindingDecls = options::ExplodePatternBindingDecls;
PrintOpts.PrintImplicitAttrs = options::PrintImplicitAttrs;
PrintOpts.PrintAccess = options::PrintAccess;
PrintOpts.AccessFilter = options::AccessFilter;
PrintOpts.PrintDocumentationComments = !options::SkipDocumentationComments;
PrintOpts.SkipPrivateSystemDecls = options::SkipPrivateSystemDecls;
PrintOpts.SkipUnsafeCXXMethods = options::SkipUnsafeCXXMethods;
PrintOpts.SkipUnavailable = options::SkipUnavailable;
PrintOpts.SkipDeinit = options::SkipDeinit;
PrintOpts.SkipImports = options::SkipImports;
PrintOpts.SkipOverrides = options::SkipOverrides;
if (options::SkipParameterNames) {
PrintOpts.ArgAndParamPrinting
= PrintOptions::ArgAndParamPrintingMode::ArgumentOnly;
} else if (options::AlwaysArgumentLabels) {
PrintOpts.ArgAndParamPrinting
= PrintOptions::ArgAndParamPrintingMode::BothAlways;
}
return PrintOpts;
}
}
}();
if (options::SkipUnderscoredSystemProtocols)
PrintOpts.SkipUnderscoredSystemProtocols = true;
if (options::PrintOriginalSourceText)