Skip to content

Commit 545844c

Browse files
committed
ASTPrinter: fix nested signatures with inverses
A generic signature's `getInnermostGenericParams` will find the generic parameters in the innermost scope. That's not quite right for printing inverses, since we don't want to print an inverse for `T` when emitting the generic signature of `f` below: ```swift struct S<T: ~Copyable, E> { func f() where E == Never {} } ``` Since `f` has its own generic signature, but doesn't define any generic parameters, it shouldn't have an inverse emitted. The solution here is to filter inverses by depth of the generic parameter. We also want to print _all_ of the inverses in other situations, rather than just the innermost ones. This aids in debugging and other tools like the API digester. resolves rdar://130179698
1 parent 05f5e51 commit 545844c

File tree

6 files changed

+95
-36
lines changed

6 files changed

+95
-36
lines changed

include/swift/AST/ASTPrinter.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,29 @@ enum class PrintStructureKind {
107107
FunctionParameterType,
108108
};
109109

110+
/// ---------------------------------
111+
/// MARK: inverse filtering functors
112+
113+
/// An inverse filter is just a function-object. Use one of the functors below
114+
/// to create such a filter.
115+
using InverseFilter = std::function<bool(const InverseRequirement &)>;
116+
117+
/// Include all of them!
118+
class AllInverses {
119+
public:
120+
bool operator()(const InverseRequirement &) const { return true; }
121+
};
122+
123+
/// Only prints inverses on generic parameters defined in the specified
124+
/// generic context.
125+
class InversesAtDepth {
126+
std::optional<unsigned> includedDepth;
127+
public:
128+
InversesAtDepth(GenericContext *level);
129+
bool operator()(const InverseRequirement &) const;
130+
};
131+
/// ---------------------------------
132+
110133
/// An abstract class used to print an AST.
111134
class ASTPrinter {
112135
unsigned CurrentIndentation = 0;

lib/AST/ASTPrinter.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,6 @@ class PrintAST : public ASTVisitor<PrintAST> {
974974
SwapSelfAndDependentMemberType = 8,
975975
PrintInherited = 16,
976976
PrintInverseRequirements = 32,
977-
IncludeOuterInverses = 64,
978977
};
979978

980979
/// The default generic signature flags for printing requirements.
@@ -1004,7 +1003,8 @@ class PrintAST : public ASTVisitor<PrintAST> {
10041003
void
10051004
printGenericSignature(GenericSignature genericSig,
10061005
unsigned flags,
1007-
llvm::function_ref<bool(const Requirement &)> filter);
1006+
llvm::function_ref<bool(const Requirement &)> filter,
1007+
InverseFilter inverseFilter);
10081008
void printSingleDepthOfGenericSignature(
10091009
ArrayRef<GenericTypeParamType *> genericParams,
10101010
ArrayRef<Requirement> requirements,
@@ -1693,9 +1693,13 @@ static unsigned getDepthOfRequirement(const Requirement &req) {
16931693

16941694
void PrintAST::printGenericSignature(GenericSignature genericSig,
16951695
unsigned flags) {
1696+
ASSERT(!((flags & InnermostOnly) && (flags & PrintInverseRequirements))
1697+
&& "InnermostOnly + PrintInverseRequirements is not handled");
1698+
16961699
printGenericSignature(genericSig, flags,
16971700
// print everything
1698-
[&](const Requirement &) { return true; });
1701+
[&](const Requirement &) { return true; },
1702+
AllInverses());
16991703
}
17001704

17011705
// Erase any requirements involving invertible protocols.
@@ -1710,16 +1714,35 @@ static void eraseInvertibleProtocolConformances(
17101714
});
17111715
}
17121716

1717+
InversesAtDepth::InversesAtDepth(GenericContext *level) {
1718+
includedDepth = std::nullopt;
1719+
// Does this generic context have its own generic parameters?
1720+
if (auto *list = level->getGenericParams()) {
1721+
includedDepth = list->getParams().back()->getDepth(); // use this depth.
1722+
}
1723+
}
1724+
bool InversesAtDepth::operator()(const InverseRequirement &inverse) const {
1725+
if (includedDepth) {
1726+
auto d = inverse.subject->castTo<GenericTypeParamType>()->getDepth();
1727+
return d == includedDepth.value();
1728+
}
1729+
return false;
1730+
}
1731+
17131732
void PrintAST::printGenericSignature(
17141733
GenericSignature genericSig,
17151734
unsigned flags,
1716-
llvm::function_ref<bool(const Requirement &)> filter) {
1735+
llvm::function_ref<bool(const Requirement &)> filter,
1736+
InverseFilter inverseFilter) {
17171737

17181738
SmallVector<Requirement, 2> requirements;
17191739
SmallVector<InverseRequirement, 2> inverses;
17201740

17211741
if (flags & PrintInverseRequirements) {
17221742
genericSig->getRequirementsWithInverses(requirements, inverses);
1743+
llvm::erase_if(inverses, [&](InverseRequirement inverse) -> bool {
1744+
return !inverseFilter(inverse);
1745+
});
17231746
} else {
17241747
requirements.append(genericSig.getRequirements().begin(),
17251748
genericSig.getRequirements().end());
@@ -1728,17 +1751,6 @@ void PrintAST::printGenericSignature(
17281751
eraseInvertibleProtocolConformances(requirements);
17291752
}
17301753

1731-
// Unless `IncludeOuterInverses` is enabled, limit inverses to the
1732-
// innermost generic parameters.
1733-
if (!(flags & IncludeOuterInverses) && !inverses.empty()) {
1734-
auto innerParams = genericSig.getInnermostGenericParams();
1735-
SmallPtrSet<TypeBase *, 4> innerParamSet(innerParams.begin(),
1736-
innerParams.end());
1737-
llvm::erase_if(inverses, [&](InverseRequirement inverse) -> bool {
1738-
return !innerParamSet.contains(inverse.subject.getPointer());
1739-
});
1740-
}
1741-
17421754
if (flags & InnermostOnly) {
17431755
auto genericParams = genericSig.getInnermostGenericParams();
17441756

@@ -2772,8 +2784,9 @@ void PrintAST::printDeclGenericRequirements(GenericContext *decl) {
27722784
// In many cases, inverses should not be printed for outer generic parameters.
27732785
// Exceptions to that include extensions, as it's valid to write an inverse
27742786
// on the generic parameters they get from the extended nominal.
2775-
if (isa<ExtensionDecl>(decl))
2776-
flags |= IncludeOuterInverses;
2787+
InverseFilter inverseFilter = AllInverses();
2788+
if (!isa<ExtensionDecl>(decl))
2789+
inverseFilter = InversesAtDepth(decl);
27772790

27782791
Printer.printStructurePre(PrintStructureKind::DeclGenericParameterClause);
27792792
printGenericSignature(genericSig,
@@ -2782,7 +2795,8 @@ void PrintAST::printDeclGenericRequirements(GenericContext *decl) {
27822795
if (parentSig)
27832796
return !parentSig->isRequirementSatisfied(req);
27842797
return true;
2785-
});
2798+
},
2799+
inverseFilter);
27862800
Printer.printStructurePost(PrintStructureKind::DeclGenericParameterClause);
27872801
}
27882802

@@ -3040,24 +3054,22 @@ void PrintAST::printExtension(ExtensionDecl *decl) {
30403054
assert(baseGenericSig &&
30413055
"an extension can't be generic if the base type isn't");
30423056

3043-
auto genSigFlags = defaultGenericRequirementFlags()
3044-
| IncludeOuterInverses;
3057+
auto genSigFlags = defaultGenericRequirementFlags();
30453058

30463059
// Disable printing inverses if the extension is adding a conformance
30473060
// for an invertible protocol itself, as we do not infer any requirements
30483061
// in such an extension. We need to print the whole signature:
30493062
// extension S: Copyable where T: Copyable
3050-
if (decl->isAddingConformanceToInvertible()) {
3063+
if (decl->isAddingConformanceToInvertible())
30513064
genSigFlags &= ~PrintInverseRequirements;
3052-
genSigFlags &= ~IncludeOuterInverses;
3053-
}
30543065

30553066
printGenericSignature(genericSig,
30563067
genSigFlags,
30573068
[baseGenericSig](const Requirement &req) -> bool {
30583069
// Only include constraints that are not satisfied by the base type.
30593070
return !baseGenericSig->isRequirementSatisfied(req);
3060-
});
3071+
},
3072+
AllInverses());
30613073
}
30623074
}
30633075
if (Options.TypeDefinitions) {

test/ModuleInterface/Inputs/NoncopyableGenerics_Misc.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,8 @@ public struct Generic<T: Publik & ~Copyable> : (P & ~Copyable) {}
137137
public struct VeryNested: (P & (Q & ~Copyable & Publik) & (P & ~Copyable)) {}
138138
public struct Twice: P & ~Copyable, Q & ~Copyable {}
139139
public struct RegularTwice: ~Copyable, ~Copyable {}
140+
141+
// coverage for rdar://130179698
142+
public struct Continuation<T: ~Copyable, E: Error> {
143+
public func resume(returning value: consuming T) where E == Never {}
144+
}

test/ModuleInterface/noncopyable_generics.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ import NoncopyableGenerics_Misc
215215
// CHECK-MISC-NEXT: public struct RegularTwice : ~Swift.Copyable, ~Swift.Copyable {
216216
// CHECK-MISC-NEXT: }
217217

218+
// CHECK-MISC-NEXT: #if compiler(>=5.3) && $NoncopyableGenerics
219+
// CHECK-MISC-NEXT: public struct Continuation<T, E> where E : Swift.Error, T : ~Copyable {
220+
// CHECK-MISC-NOT: ~
221+
// CHECK-MISC: #endif
222+
218223
// NOTE: below are extensions emitted at the end of NoncopyableGenerics_Misc.swift
219224
// CHECK-MISC: extension {{.*}}.VeryNested : {{.*}}.Publik {}
220225

test/SILGen/mangling_inverse_generics.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,18 +285,30 @@ public struct E<T: ~Copyable>: ~Copyable {
285285
public func __existential2__(_ t: consuming any ~Copyable) {}
286286

287287
// DEMANGLED: test.E.something<A>() -> A1
288-
// CHECK: sil [ossa] @$s4test1EV9somethingqd__ylF : $@convention(method) <T><U where U : ~Copyable> (@guaranteed E<T>) -> @out U {
288+
// CHECK: sil [ossa] @$s4test1EV9somethingqd__ylF : $@convention(method) <T where T : ~Copyable><U where U : ~Copyable> (@guaranteed E<T>) -> @out U {
289289
@_preInverseGenerics
290290
public func something<U: ~Copyable>() -> U {
291291
fatalError()
292292
}
293293

294294
// DEMANGLED: (extension in test):test.E< where A: ~Swift.Copyable>.something<A>() -> A1
295-
// CHECK: sil [ossa] @$s4test1EVAARi_zrlE9somethingqd__ylF : $@convention(method) <T><U> (@guaranteed E<T>) -> @out U {
295+
// CHECK: sil [ossa] @$s4test1EVAARi_zrlE9somethingqd__ylF : $@convention(method) <T where T : ~Copyable><U> (@guaranteed E<T>) -> @out U {
296296
public func something<U>() -> U {
297297
fatalError()
298298
}
299299

300+
// DEMANGLED: test.E.something2<A>() -> A1
301+
// CHECK: sil [ossa] @$s4test1EV10something2qd__ylF : $@convention(method) <T><U> (@guaranteed E<T>) -> @out U {
302+
public func something2<U>() -> U where T: Copyable {
303+
fatalError()
304+
}
305+
306+
// DEMANGLED: test.E.something2<A where A1: ~Swift.Copyable>() -> A1
307+
// CHECK: sil [ossa] @$s4test1EV10something2qd__yRi_d__lF : $@convention(method) <T><U where U : ~Copyable> (@guaranteed E<T>) -> @out U {
308+
public func something2<U: ~Copyable>() -> U where T: Copyable {
309+
fatalError()
310+
}
311+
300312
// DEMANGLED: variable initialization expression of test.E.property : Swift.Int
301313
// CHECK: sil [transparent] [ossa] @$s4test1EV8propertySivpfi : $@convention(thin) <T where T : ~Copyable> () -> Int {
302314

test/api-digester/Outputs/stability-stdlib-source-x86_64.swift.expected

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -314,32 +314,34 @@ TypeAlias UnsafePointer.Stride has generic signature change from <Pointee> to <P
314314
Func FixedWidthInteger.&*(_:_:) has been added as a protocol requirement
315315
Accessor UnsafeBufferPointer.debugDescription.Get() has generic signature change from <Element> to <Element where Element : ~Copyable>
316316
Accessor UnsafeMutableBufferPointer.debugDescription.Get() has generic signature change from <Element> to <Element where Element : ~Copyable>
317-
Func ManagedBuffer.withUnsafeMutablePointerToElements(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, R : ~Copyable>
317+
Func ManagedBuffer.withUnsafeMutablePointerToElements(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, Element : ~Copyable, R : ~Copyable>
318318
Func ManagedBuffer.withUnsafeMutablePointerToElements(_:) is now without @rethrows
319-
Func ManagedBuffer.withUnsafeMutablePointerToHeader(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, R : ~Copyable>
319+
Func ManagedBuffer.withUnsafeMutablePointerToHeader(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, Element : ~Copyable, R : ~Copyable>
320320
Func ManagedBuffer.withUnsafeMutablePointerToHeader(_:) is now without @rethrows
321-
Func ManagedBuffer.withUnsafeMutablePointers(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, R : ~Copyable>
321+
Func ManagedBuffer.withUnsafeMutablePointers(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, Element : ~Copyable, R : ~Copyable>
322322
Func ManagedBuffer.withUnsafeMutablePointers(_:) is now without @rethrows
323-
Func ManagedBufferPointer.withUnsafeMutablePointerToElements(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, R : ~Copyable>
323+
Func ManagedBufferPointer.withUnsafeMutablePointerToElements(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, Element : ~Copyable, R : ~Copyable>
324324
Func ManagedBufferPointer.withUnsafeMutablePointerToElements(_:) is now without @rethrows
325-
Func ManagedBufferPointer.withUnsafeMutablePointerToHeader(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, R : ~Copyable>
325+
Func ManagedBufferPointer.withUnsafeMutablePointerToHeader(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, Element : ~Copyable, R : ~Copyable>
326326
Func ManagedBufferPointer.withUnsafeMutablePointerToHeader(_:) is now without @rethrows
327-
Func ManagedBufferPointer.withUnsafeMutablePointers(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, R : ~Copyable>
327+
Func ManagedBufferPointer.withUnsafeMutablePointers(_:) has generic signature change from <Header, Element, R> to <Header, Element, E, R where E : Swift.Error, Element : ~Copyable, R : ~Copyable>
328328
Func ManagedBufferPointer.withUnsafeMutablePointers(_:) is now without @rethrows
329329
Func Optional.flatMap(_:) has generic signature change from <Wrapped, U> to <Wrapped, E, U where E : Swift.Error, U : ~Copyable>
330330
Func Optional.flatMap(_:) is now without @rethrows
331331
Func Optional.map(_:) has generic signature change from <Wrapped, U> to <Wrapped, E, U where E : Swift.Error, U : ~Copyable>
332332
Func Optional.map(_:) is now without @rethrows
333333
Func Result.flatMap(_:) has generic signature change from <Success, Failure, NewSuccess where Failure : Swift.Error> to <Success, Failure, NewSuccess where Failure : Swift.Error, NewSuccess : ~Copyable>
334+
Func Result.flatMapError(_:) has generic signature change from <Success, Failure, NewFailure where Failure : Swift.Error, NewFailure : Swift.Error> to <Success, Failure, NewFailure where Failure : Swift.Error, NewFailure : Swift.Error, Success : ~Copyable>
334335
Func Result.flatMapError(_:) has self access kind changing from NonMutating to Consuming
335336
Func Result.map(_:) has generic signature change from <Success, Failure, NewSuccess where Failure : Swift.Error> to <Success, Failure, NewSuccess where Failure : Swift.Error, NewSuccess : ~Copyable>
336-
Func UnsafeBufferPointer.withMemoryRebound(to:_:) has generic signature change from <Element, T, Result> to <Element, T, E, Result where E : Swift.Error, T : ~Copyable, Result : ~Copyable>
337+
Func Result.mapError(_:) has generic signature change from <Success, Failure, NewFailure where Failure : Swift.Error, NewFailure : Swift.Error> to <Success, Failure, NewFailure where Failure : Swift.Error, NewFailure : Swift.Error, Success : ~Copyable>
338+
Func UnsafeBufferPointer.withMemoryRebound(to:_:) has generic signature change from <Element, T, Result> to <Element, T, E, Result where E : Swift.Error, Element : ~Copyable, T : ~Copyable, Result : ~Copyable>
337339
Func UnsafeBufferPointer.withMemoryRebound(to:_:) is now without @rethrows
338-
Func UnsafeMutableBufferPointer.withMemoryRebound(to:_:) has generic signature change from <Element, T, Result> to <Element, T, E, Result where E : Swift.Error, T : ~Copyable, Result : ~Copyable>
340+
Func UnsafeMutableBufferPointer.withMemoryRebound(to:_:) has generic signature change from <Element, T, Result> to <Element, T, E, Result where E : Swift.Error, Element : ~Copyable, T : ~Copyable, Result : ~Copyable>
339341
Func UnsafeMutableBufferPointer.withMemoryRebound(to:_:) is now without @rethrows
340-
Func UnsafeMutablePointer.withMemoryRebound(to:capacity:_:) has generic signature change from <Pointee, T, Result> to <Pointee, T, E, Result where E : Swift.Error, T : ~Copyable, Result : ~Copyable>
342+
Func UnsafeMutablePointer.withMemoryRebound(to:capacity:_:) has generic signature change from <Pointee, T, Result> to <Pointee, T, E, Result where E : Swift.Error, Pointee : ~Copyable, T : ~Copyable, Result : ~Copyable>
341343
Func UnsafeMutablePointer.withMemoryRebound(to:capacity:_:) is now without @rethrows
342-
Func UnsafePointer.withMemoryRebound(to:capacity:_:) has generic signature change from <Pointee, T, Result> to <Pointee, T, E, Result where E : Swift.Error, T : ~Copyable, Result : ~Copyable>
344+
Func UnsafePointer.withMemoryRebound(to:capacity:_:) has generic signature change from <Pointee, T, Result> to <Pointee, T, E, Result where E : Swift.Error, Pointee : ~Copyable, T : ~Copyable, Result : ~Copyable>
343345
Func UnsafePointer.withMemoryRebound(to:capacity:_:) is now without @rethrows
344346
Func withExtendedLifetime(_:_:) has generic signature change from <T, Result> to <T, E, Result where E : Swift.Error, T : ~Copyable, Result : ~Copyable>
345347
Func withExtendedLifetime(_:_:) is now without @rethrows

0 commit comments

Comments
 (0)