Skip to content

Commit 5d59985

Browse files
authored
Merge pull request swiftlang#71748 from kavon/ncgenerics-test-fixes-kavon-v18
ASTPrinter: fix nested inverse printing (v18)
2 parents f03ddf7 + 70878a6 commit 5d59985

File tree

5 files changed

+185
-4
lines changed

5 files changed

+185
-4
lines changed

lib/AST/ASTPrinter.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ class PrintAST : public ASTVisitor<PrintAST> {
963963
SwapSelfAndDependentMemberType = 8,
964964
PrintInherited = 16,
965965
PrintInverseRequirements = 32,
966+
IncludeOuterInverses = 64,
966967
};
967968

968969
void printInheritedFromRequirementSignature(ProtocolDecl *proto,
@@ -1668,6 +1669,17 @@ void PrintAST::printGenericSignature(
16681669
genericSig.getRequirements().end());
16691670
}
16701671

1672+
// Unless `IncludeOuterInverses` is enabled, limit inverses to the
1673+
// innermost generic parameters.
1674+
if (!(flags & IncludeOuterInverses) && !inverses.empty()) {
1675+
auto innerParams = genericSig.getInnermostGenericParams();
1676+
SmallPtrSet<TypeBase *, 4> innerParamSet(innerParams.begin(),
1677+
innerParams.end());
1678+
llvm::erase_if(inverses, [&](InverseRequirement inverse) -> bool {
1679+
return !innerParamSet.contains(inverse.subject.getPointer());
1680+
});
1681+
}
1682+
16711683
if (flags & InnermostOnly) {
16721684
auto genericParams = genericSig.getInnermostGenericParams();
16731685

@@ -2696,9 +2708,17 @@ void PrintAST::printDeclGenericRequirements(GenericContext *decl) {
26962708
if (parentSig && parentSig->isEqual(genericSig))
26972709
return;
26982710

2711+
unsigned flags = PrintRequirements | PrintInverseRequirements;
2712+
2713+
// In many cases, inverses should not be printed for outer generic parameters.
2714+
// Exceptions to that include extensions, as it's valid to write an inverse
2715+
// on the generic parameters they get from the extended nominal.
2716+
if (isa<ExtensionDecl>(decl))
2717+
flags |= IncludeOuterInverses;
2718+
26992719
Printer.printStructurePre(PrintStructureKind::DeclGenericParameterClause);
27002720
printGenericSignature(genericSig,
2701-
PrintRequirements | PrintInverseRequirements,
2721+
flags,
27022722
[parentSig](const Requirement &req) {
27032723
if (parentSig)
27042724
return !parentSig->isRequirementSatisfied(req);
@@ -2852,10 +2872,13 @@ void PrintAST::printSynthesizedExtension(Type ExtendedType,
28522872
void PrintAST::printSynthesizedExtensionImpl(Type ExtendedType,
28532873
ExtensionDecl *ExtDecl) {
28542874
auto printRequirementsFrom = [&](ExtensionDecl *ED, bool &IsFirst) {
2875+
SmallVector<Requirement, 2> requirements;
2876+
SmallVector<InverseRequirement, 2> inverses;
28552877
auto Sig = ED->getGenericSignature();
2878+
Sig->getRequirementsWithInverses(requirements, inverses);
28562879
printSingleDepthOfGenericSignature(Sig.getGenericParams(),
2857-
Sig.getRequirements(),
2858-
/*inverses=*/{},
2880+
requirements,
2881+
inverses,
28592882
IsFirst,
28602883
PrintRequirements | PrintInverseRequirements,
28612884
[](const Requirement &Req){
@@ -2956,7 +2979,9 @@ void PrintAST::printExtension(ExtensionDecl *decl) {
29562979
assert(baseGenericSig &&
29572980
"an extension can't be generic if the base type isn't");
29582981
printGenericSignature(genericSig,
2959-
PrintRequirements | PrintInverseRequirements,
2982+
PrintRequirements
2983+
| PrintInverseRequirements
2984+
| IncludeOuterInverses,
29602985
[baseGenericSig](const Requirement &req) -> bool {
29612986
// Only include constraints that are not satisfied by the base type.
29622987
return !baseGenericSig->isRequirementSatisfied(req);
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// RUN: %target-swift-frontend \
2+
// RUN: -enable-experimental-feature NoncopyableGenerics \
3+
// RUN: -enable-experimental-feature NonescapableTypes \
4+
// RUN: -verify -typecheck %s -debug-generic-signatures \
5+
// RUN: -debug-inverse-requirements 2>&1 | %FileCheck %s --implicit-check-not "error:"
6+
7+
// CHECK-LABEL: .Outer@
8+
// CHECK: Generic signature: <A where A : Escapable>
9+
10+
// CHECK-LABEL: .Outer.innerFn@
11+
// CHECK: Generic signature: <A, B where A : Escapable, B : Escapable>
12+
13+
// CHECK-LABEL: .Outer.InnerStruct@
14+
// CHECK: Generic signature: <A, C where A : Escapable, C : Escapable>
15+
16+
// CHECK-LABEL: .Outer.InnerStruct.g@
17+
// CHECK: Generic signature: <A, C, D where A : Escapable, C : Escapable, D : Escapable>
18+
19+
// CHECK-LABEL: .Outer.InnerStruct.init()@
20+
// CHECK: Generic signature: <A, C where A : Escapable, C : Escapable>
21+
22+
// CHECK: (normal_conformance type="Outer<A>.InnerStruct<C>" protocol="Escapable")
23+
24+
// CHECK-LABEL: .Outer.InnerVariation1@
25+
// CHECK: Generic signature: <A, D where A : Escapable, D : Escapable>
26+
27+
// CHECK-LABEL: .Outer.InnerVariation2@
28+
// CHECK: Generic signature: <A, D where A : Escapable, D : Copyable>
29+
30+
// CHECK-LABEL: ExtensionDecl {{.*}} base=Outer.InnerStruct
31+
// CHECK: Generic signature: <A, C where A : Copyable, A : Escapable, C : Copyable, C : Escapable>
32+
33+
// CHECK-LABEL: .InnerStruct extension.hello@
34+
// CHECK: Generic signature: <A, C, T where A : Copyable, A : Escapable, C : Copyable, C : Escapable, T : Copyable>
35+
36+
// CHECK-LABEL: .Freestanding@
37+
// CHECK: Generic signature: <T>
38+
39+
// CHECK-LABEL: ExtensionDecl {{.*}} base=Outer
40+
// CHECK: Generic signature: <A where A : Copyable, A : Escapable>
41+
42+
// CHECK-LABEL: ExtensionDecl {{.*}} base=Outer.InnerVariation1
43+
// CHECK: Generic signature: <A, D where A : Escapable, D : Copyable, D : Escapable>
44+
45+
// CHECK-LABEL: ExtensionDecl {{.*}} base=Outer.InnerVariation2
46+
// CHECK: Generic signature: <A, D where A : Escapable, D : Copyable>
47+
48+
// CHECK-LABEL: ExtensionDecl line=0 base=Outer<A>.InnerStruct<C>
49+
// CHECK-NEXT: (normal_conformance type="Outer<A>.InnerStruct<C>" protocol="Copyable"
50+
// CHECK-NEXT: (requirement "A" conforms_to "Copyable")
51+
// CHECK-NEXT: (requirement "C" conforms_to "Copyable"))
52+
53+
// CHECK-LABEL: ExtensionDecl line=0 base=Outer<A>.InnerVariation1<D>
54+
// CHECK-NEXT: (normal_conformance type="Outer<A>.InnerVariation1<D>" protocol="Copyable"
55+
// CHECK-NEXT: (requirement "A" conforms_to "Copyable")
56+
// CHECK-NEXT: (requirement "D" conforms_to "Copyable"))
57+
58+
// CHECK-LABEL: ExtensionDecl line=0 base=Outer<A>.InnerVariation2<D>
59+
// CHECK-NEXT: (normal_conformance type="Outer<A>.InnerVariation2<D>" protocol="Escapable"
60+
// CHECK-NEXT: (requirement "D" conforms_to "Escapable"))
61+
62+
// CHECK-LABEL: ExtensionDecl line=0 base=Outer<A>
63+
// CHECK-NEXT: (normal_conformance type="Outer<A>" protocol="Copyable"
64+
// CHECK-NEXT: (requirement "A" conforms_to "Copyable"))
65+
66+
// CHECK-LABEL: ExtensionDecl line=0 base=Freestanding<T>
67+
// CHECK-NEXT: (normal_conformance type="Freestanding<T>" protocol="Copyable"
68+
// CHECK-NEXT: (requirement "T" conforms_to "Copyable"))
69+
70+
// CHECK-LABEL: ExtensionDecl line=0 base=Freestanding<T>
71+
// CHECK-NEXT: (normal_conformance type="Freestanding<T>" protocol="Escapable"
72+
// CHECK-NEXT: (requirement "T" conforms_to "Escapable"))
73+
74+
public struct Outer<A: ~Copyable> {
75+
public func innerFn<B: ~Copyable>(_ b: borrowing B) {}
76+
public struct InnerStruct<C: ~Copyable> {
77+
public func g<D>(_ d: borrowing D) where D: ~Copyable {}
78+
}
79+
public struct InnerVariation1<D: ~Copyable>: ~Escapable {}
80+
public struct InnerVariation2<D: ~Escapable>: ~Copyable {}
81+
}
82+
83+
extension Outer.InnerStruct {
84+
public func hello<T: ~Escapable>(_ t: T) {}
85+
}
86+
87+
public struct Freestanding<T: ~Copyable> where T: ~Escapable {}
88+
89+
extension Outer {}
90+
extension Outer.InnerVariation1 where A: ~Copyable {}
91+
extension Outer.InnerVariation2 where D: ~Escapable, A: ~Copyable {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-typecheck-verify-swift \
2+
// RUN: -enable-experimental-feature NoncopyableGenerics \
3+
// RUN: -enable-experimental-feature NonescapableTypes
4+
5+
struct Turtle<T> {}
6+
extension Turtle where T: ~Copyable {} // expected-error {{'T' required to be 'Copyable' but is marked with '~Copyable'}}
7+
8+
struct Rabbit<T> where T: ~Copyable {}
9+
extension Rabbit where T: ~Escapable {} // expected-error {{'T' required to be 'Escapable' but is marked with '~Escapable'}}
10+
11+
protocol P {}
12+
extension P where Self: ~Escapable {} // expected-error {{'Self' required to be 'Escapable' but is marked with '~Escapable'}}
13+
14+
protocol HasAssoc {
15+
associatedtype A
16+
}
17+
extension HasAssoc where Self.A: ~Copyable {}
18+
// expected-error@-1 {{cannot add inverse constraint 'Self.A: ~Copyable' on generic parameter 'Self.A' defined in outer scope}}
19+
// expected-error@-2 {{'Self.A' required to be 'Copyable' but is marked with '~Copyable'}}
20+
21+
class Box<T: ~Copyable> {}
22+
extension Box where T: ~Copyable {}

test/ModuleInterface/Inputs/NoncopyableGenerics_Misc.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,19 @@ public func noInversesEND() {}
8080
public func checkAnyInv1<Result>(_ t: borrowing Result) where Result: Any & ~Copyable {}
8181
public func checkAnyInv2<Result: Any>(_ t: borrowing Result) where Result: ~Copyable & ~Escapable {}
8282
public func checkAnyObject<Result>(_ t: Result) where Result: AnyObject {}
83+
84+
// coverage for rdar://123281976
85+
public struct Outer<A: ~Copyable> {
86+
public func innerFn<B: ~Copyable>(_ b: borrowing B) {}
87+
public struct InnerStruct<C: ~Copyable> {
88+
public func g<D>(_ d: borrowing D) where D: ~Copyable {}
89+
}
90+
public struct InnerVariation1<D: ~Copyable>: ~Escapable {}
91+
public struct InnerVariation2<D: ~Escapable>: ~Copyable {}
92+
}
93+
94+
extension Outer.InnerStruct {
95+
public func hello<T: ~Escapable>(_ t: T) {}
96+
}
97+
98+
public struct Freestanding<T: ~Copyable> where T: ~Escapable {}

test/ModuleInterface/noncopyable_generics.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,39 @@ import NoncopyableGenerics_Misc
104104
// CHECK-MISC: public func checkAnyInv2<Result>(_ t: borrowing Result) where Result : ~Copyable, Result : ~Escapable
105105
// CHECK-MISC: public func checkAnyObject<Result>(_ t: Result) where Result : AnyObject
106106

107+
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
108+
// CHECK-MISC-NEXT: public struct Outer<A> where A : ~Copyable {
109+
// CHECK-MISC-NEXT: public func innerFn<B>(_ b: borrowing B) where B : ~Copyable
110+
// CHECK-MISC: public struct InnerStruct<C> where C : ~Copyable {
111+
// CHECK-MISC-NEXT: public func g<D>(_ d: borrowing D) where D : ~Copyable
112+
// CHECK-MISC: public struct InnerVariation1<D> : ~Escapable where D : ~Copyable
113+
// CHECK-MISC: public struct InnerVariation2<D> : ~Copyable where D : ~Escapable
114+
115+
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
116+
// CHECK-MISC-NEXT: extension {{.*}}.Outer.InnerStruct {
117+
// CHECK-MISC-NEXT: public func hello<T>(_ t: T) where T : ~Escapable
118+
119+
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
120+
// CHECK-MISC-NEXT: public struct Freestanding<T> where T : ~Copyable, T : ~Escapable {
121+
107122
///////////////////////////////////////////////////////////////////////
108123
// Synthesized conditional conformances are next
109124

110125
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
111126
// CHECK-MISC-NEXT: extension {{.*}}.Hello : Swift.Copyable where T : ~Escapable {
112127

128+
// FIXME: (rdar://123293620) inner struct extensions are not feature-guarded correctly
129+
// CHECK-MISC: extension {{.*}}.Outer.InnerStruct : Swift.Copyable {
130+
// CHECK-MISC: extension {{.*}}.Outer.InnerVariation1 : Swift.Copyable {
131+
// CHECK-MISC: extension {{.*}}.Outer.InnerVariation2 : Swift.Escapable where A : ~Copyable {
132+
// CHECK-MISC: extension {{.*}}.Outer : Swift.Copyable {
133+
134+
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
135+
// CHECK-MISC-NEXT: extension {{.*}}.Freestanding : Swift.Copyable where T : ~Escapable {
136+
137+
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
138+
// CHECK-MISC-NEXT: extension {{.*}}.Freestanding : Swift.Escapable where T : ~Copyable {
139+
113140
////////////////////////////////////////////////////////////////////////
114141
// At the end, ensure there are no synthesized Copyable extensions
115142

0 commit comments

Comments
 (0)