Skip to content

Commit 90c96d8

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 (cherry picked from commit 545844c)
1 parent 4de861a commit 90c96d8

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
@@ -973,7 +973,6 @@ class PrintAST : public ASTVisitor<PrintAST> {
973973
SwapSelfAndDependentMemberType = 8,
974974
PrintInherited = 16,
975975
PrintInverseRequirements = 32,
976-
IncludeOuterInverses = 64,
977976
};
978977

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

16851685
void PrintAST::printGenericSignature(GenericSignature genericSig,
16861686
unsigned flags) {
1687+
ASSERT(!((flags & InnermostOnly) && (flags & PrintInverseRequirements))
1688+
&& "InnermostOnly + PrintInverseRequirements is not handled");
1689+
16871690
printGenericSignature(genericSig, flags,
16881691
// print everything
1689-
[&](const Requirement &) { return true; });
1692+
[&](const Requirement &) { return true; },
1693+
AllInverses());
16901694
}
16911695

16921696
// Erase any requirements involving invertible protocols.
@@ -1704,16 +1708,35 @@ static void eraseInvertibleProtocolConformances(
17041708
});
17051709
}
17061710

1711+
InversesAtDepth::InversesAtDepth(GenericContext *level) {
1712+
includedDepth = std::nullopt;
1713+
// Does this generic context have its own generic parameters?
1714+
if (auto *list = level->getGenericParams()) {
1715+
includedDepth = list->getParams().back()->getDepth(); // use this depth.
1716+
}
1717+
}
1718+
bool InversesAtDepth::operator()(const InverseRequirement &inverse) const {
1719+
if (includedDepth) {
1720+
auto d = inverse.subject->castTo<GenericTypeParamType>()->getDepth();
1721+
return d == includedDepth.value();
1722+
}
1723+
return false;
1724+
}
1725+
17071726
void PrintAST::printGenericSignature(
17081727
GenericSignature genericSig,
17091728
unsigned flags,
1710-
llvm::function_ref<bool(const Requirement &)> filter) {
1729+
llvm::function_ref<bool(const Requirement &)> filter,
1730+
InverseFilter inverseFilter) {
17111731

17121732
SmallVector<Requirement, 2> requirements;
17131733
SmallVector<InverseRequirement, 2> inverses;
17141734

17151735
if (flags & PrintInverseRequirements) {
17161736
genericSig->getRequirementsWithInverses(requirements, inverses);
1737+
llvm::erase_if(inverses, [&](InverseRequirement inverse) -> bool {
1738+
return !inverseFilter(inverse);
1739+
});
17171740
} else {
17181741
requirements.append(genericSig.getRequirements().begin(),
17191742
genericSig.getRequirements().end());
@@ -1722,17 +1745,6 @@ void PrintAST::printGenericSignature(
17221745
eraseInvertibleProtocolConformances(requirements);
17231746
}
17241747

1725-
// Unless `IncludeOuterInverses` is enabled, limit inverses to the
1726-
// innermost generic parameters.
1727-
if (!(flags & IncludeOuterInverses) && !inverses.empty()) {
1728-
auto innerParams = genericSig.getInnermostGenericParams();
1729-
SmallPtrSet<TypeBase *, 4> innerParamSet(innerParams.begin(),
1730-
innerParams.end());
1731-
llvm::erase_if(inverses, [&](InverseRequirement inverse) -> bool {
1732-
return !innerParamSet.contains(inverse.subject.getPointer());
1733-
});
1734-
}
1735-
17361748
if (flags & InnermostOnly) {
17371749
auto genericParams = genericSig.getInnermostGenericParams();
17381750

@@ -2769,8 +2781,9 @@ void PrintAST::printDeclGenericRequirements(GenericContext *decl) {
27692781
// In many cases, inverses should not be printed for outer generic parameters.
27702782
// Exceptions to that include extensions, as it's valid to write an inverse
27712783
// on the generic parameters they get from the extended nominal.
2772-
if (isa<ExtensionDecl>(decl))
2773-
flags |= IncludeOuterInverses;
2784+
InverseFilter inverseFilter = AllInverses();
2785+
if (!isa<ExtensionDecl>(decl))
2786+
inverseFilter = InversesAtDepth(decl);
27742787

27752788
Printer.printStructurePre(PrintStructureKind::DeclGenericParameterClause);
27762789
printGenericSignature(genericSig,
@@ -2779,7 +2792,8 @@ void PrintAST::printDeclGenericRequirements(GenericContext *decl) {
27792792
if (parentSig)
27802793
return !parentSig->isRequirementSatisfied(req);
27812794
return true;
2782-
});
2795+
},
2796+
inverseFilter);
27832797
Printer.printStructurePost(PrintStructureKind::DeclGenericParameterClause);
27842798
}
27852799

@@ -3037,24 +3051,22 @@ void PrintAST::printExtension(ExtensionDecl *decl) {
30373051
assert(baseGenericSig &&
30383052
"an extension can't be generic if the base type isn't");
30393053

3040-
auto genSigFlags = defaultGenericRequirementFlags()
3041-
| IncludeOuterInverses;
3054+
auto genSigFlags = defaultGenericRequirementFlags();
30423055

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

30523063
printGenericSignature(genericSig,
30533064
genSigFlags,
30543065
[baseGenericSig](const Requirement &req) -> bool {
30553066
// Only include constraints that are not satisfied by the base type.
30563067
return !baseGenericSig->isRequirementSatisfied(req);
3057-
});
3068+
},
3069+
AllInverses());
30583070
}
30593071
}
30603072
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)