Skip to content

Commit 0e2f74a

Browse files
authored
[ParseableInterface] Skip extensions with non-public constraints (#20146)
There are still some issues to work out here, but this is more correct than it was before. rdar://problem/44662458
1 parent 244f8bb commit 0e2f74a

File tree

2 files changed

+165
-2
lines changed

2 files changed

+165
-2
lines changed

lib/AST/ASTPrinter.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,20 @@ static bool isPublicOrUsableFromInline(const ValueDecl *VD) {
7171
return scope.isPublic();
7272
}
7373

74+
static bool isPublicOrUsableFromInline(Type ty) {
75+
// Note the double negative here: we're looking for any referenced decls that
76+
// are *not* public-or-usableFromInline.
77+
return !ty.findIf([](Type typePart) -> bool {
78+
// FIXME: If we have an internal typealias for a non-internal type, we ought
79+
// to be able to print it by desugaring.
80+
if (auto *aliasTy = dyn_cast<NameAliasType>(typePart.getPointer()))
81+
return !isPublicOrUsableFromInline(aliasTy->getDecl());
82+
if (auto *nominal = typePart->getAnyNominal())
83+
return !isPublicOrUsableFromInline(nominal);
84+
return false;
85+
});
86+
}
87+
7488
static bool contributesToParentTypeStorage(const AbstractStorageDecl *ASD) {
7589
auto *DC = ASD->getDeclContext()->getAsDecl();
7690
if (!DC) return false;
@@ -118,8 +132,21 @@ PrintOptions PrintOptions::printParseableInterfaceFile() {
118132
if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
119133
if (!shouldPrint(ED->getExtendedNominal(), options))
120134
return false;
121-
// FIXME: We also need to check the generic signature for constraints
122-
// that we can't reference.
135+
for (const Requirement &req : ED->getGenericRequirements()) {
136+
if (!isPublicOrUsableFromInline(req.getFirstType()))
137+
return false;
138+
139+
switch (req.getKind()) {
140+
case RequirementKind::Conformance:
141+
case RequirementKind::Superclass:
142+
case RequirementKind::SameType:
143+
if (!isPublicOrUsableFromInline(req.getSecondType()))
144+
return false;
145+
break;
146+
case RequirementKind::Layout:
147+
break;
148+
}
149+
}
123150
}
124151

125152
// Skip typealiases that just redeclare generic parameters.

test/ParseableInterface/access-filter.swift

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,139 @@ enum InternalEnum_BAD {
149149
// CHECK-NEXT: case y(Int)
150150
case y(Int)
151151
} // CHECK-NEXT: {{^[}]$}}
152+
153+
// CHECK: public class PublicClass {{[{]$}}
154+
public class PublicClass {
155+
} // CHECK: {{^[}]$}}
156+
157+
class InternalClass_BAD {
158+
}
159+
160+
// CHECK: @usableFromInline
161+
// CHECK-NEXT: internal class UFIClass {{[{]$}}
162+
@usableFromInline class UFIClass {
163+
} // CHECK: {{^[}]$}}
164+
165+
// CHECK: public struct GenericStruct<T>
166+
public struct GenericStruct<T> {}
167+
168+
// CHECK: extension GenericStruct where T == main.PublicStruct {{[{]$}}
169+
extension GenericStruct where T == PublicStruct {
170+
// CHECK-NEXT: public func constrainedToPublicStruct(){{$}}
171+
public func constrainedToPublicStruct() {}
172+
} // CHECK-NEXT: {{^[}]$}}
173+
// CHECK: extension GenericStruct where T == main.UFIStruct {{[{]$}}
174+
extension GenericStruct where T == UFIStruct {
175+
// CHECK-NEXT: @usableFromInline{{$}}
176+
// CHECK-NEXT: internal func constrainedToUFIStruct(){{$}}
177+
@usableFromInline internal func constrainedToUFIStruct() {}
178+
} // CHECK-NEXT: {{^[}]$}}
179+
extension GenericStruct where T == InternalStruct_BAD {
180+
@usableFromInline internal func constrainedToInternalStruct_BAD() {}
181+
}
182+
183+
// CHECK: extension GenericStruct where T == main.PublicStruct {{[{]$}}
184+
extension GenericStruct where PublicStruct == T {
185+
// CHECK-NEXT: public func constrainedToPublicStruct2(){{$}}
186+
public func constrainedToPublicStruct2() {}
187+
} // CHECK-NEXT: {{^[}]$}}
188+
// CHECK: extension GenericStruct where T == main.UFIStruct {{[{]$}}
189+
extension GenericStruct where UFIStruct == T {
190+
// CHECK-NEXT: @usableFromInline{{$}}
191+
// CHECK-NEXT: internal func constrainedToUFIStruct2(){{$}}
192+
@usableFromInline internal func constrainedToUFIStruct2() {}
193+
} // CHECK-NEXT: {{^[}]$}}
194+
extension GenericStruct where InternalStruct_BAD == T {
195+
@usableFromInline internal func constrainedToInternalStruct2_BAD() {}
196+
}
197+
198+
// CHECK: extension GenericStruct where T : PublicProto {{[{]$}}
199+
extension GenericStruct where T: PublicProto {
200+
// CHECK-NEXT: public func constrainedToPublicProto(){{$}}
201+
public func constrainedToPublicProto() {}
202+
} // CHECK-NEXT: {{^[}]$}}
203+
// CHECK: extension GenericStruct where T : UFIProto {{[{]$}}
204+
extension GenericStruct where T: UFIProto {
205+
// CHECK-NEXT: @usableFromInline{{$}}
206+
// CHECK-NEXT: internal func constrainedToUFIProto(){{$}}
207+
@usableFromInline internal func constrainedToUFIProto() {}
208+
} // CHECK-NEXT: {{^[}]$}}
209+
extension GenericStruct where T: InternalProto_BAD {
210+
@usableFromInline internal func constrainedToInternalProto_BAD() {}
211+
}
212+
213+
// CHECK: extension GenericStruct where T : main.PublicClass {{[{]$}}
214+
extension GenericStruct where T: PublicClass {
215+
// CHECK-NEXT: public func constrainedToPublicClass(){{$}}
216+
public func constrainedToPublicClass() {}
217+
} // CHECK-NEXT: {{^[}]$}}
218+
// CHECK: extension GenericStruct where T : main.UFIClass {{[{]$}}
219+
extension GenericStruct where T: UFIClass {
220+
// CHECK-NEXT: @usableFromInline{{$}}
221+
// CHECK-NEXT: internal func constrainedToUFIClass(){{$}}
222+
@usableFromInline internal func constrainedToUFIClass() {}
223+
} // CHECK-NEXT: {{^[}]$}}
224+
extension GenericStruct where T: InternalClass_BAD {
225+
@usableFromInline internal func constrainedToInternalClass_BAD() {}
226+
}
227+
228+
// CHECK: extension GenericStruct where T : AnyObject {{[{]$}}
229+
extension GenericStruct where T: AnyObject {
230+
// CHECK-NEXT: public func constrainedToAnyObject(){{$}}
231+
public func constrainedToAnyObject() {}
232+
} // CHECK-NEXT: {{^[}]$}}
233+
234+
public struct PublicAliasBase {}
235+
internal struct ReallyInternalAliasBase_BAD {}
236+
237+
// CHECK: public typealias PublicAlias = PublicAliasBase
238+
public typealias PublicAlias = PublicAliasBase
239+
internal typealias InternalAlias_BAD = PublicAliasBase
240+
// CHECK: @usableFromInline
241+
// CHECK-NEXT: internal typealias UFIAlias = PublicAliasBase
242+
@usableFromInline internal typealias UFIAlias = PublicAliasBase
243+
244+
internal typealias ReallyInternalAlias_BAD = ReallyInternalAliasBase_BAD
245+
246+
// CHECK: extension GenericStruct where T == PublicAlias {{[{]$}}
247+
extension GenericStruct where T == PublicAlias {
248+
// CHECK-NEXT: public func constrainedToPublicAlias(){{$}}
249+
public func constrainedToPublicAlias() {}
250+
} // CHECK-NEXT: {{^[}]$}}
251+
// CHECK: extension GenericStruct where T == UFIAlias {{[{]$}}
252+
extension GenericStruct where T == UFIAlias {
253+
// CHECK-NEXT: @usableFromInline{{$}}
254+
// CHECK-NEXT: internal func constrainedToUFIAlias(){{$}}
255+
@usableFromInline internal func constrainedToUFIAlias() {}
256+
} // CHECK-NEXT: {{^[}]$}}
257+
extension GenericStruct where T == InternalAlias_BAD {
258+
// FIXME: We could print this one by desugaring; it is indeed public.
259+
@usableFromInline internal func constrainedToInternalAlias() {}
260+
}
261+
extension GenericStruct where T == ReallyInternalAlias_BAD {
262+
@usableFromInline internal func constrainedToPrivateAlias() {}
263+
}
264+
265+
extension GenericStruct {
266+
// For the next extension's test.
267+
public func requirement() {}
268+
}
269+
extension GenericStruct: PublicProto where T: InternalProto_BAD {
270+
@usableFromInline internal func conformance_BAD() {}
271+
}
272+
273+
274+
public struct MultiGenericStruct<First, Second> {}
275+
276+
// CHECK: extension MultiGenericStruct where First == main.PublicStruct, Second == main.PublicStruct {{[{]$}}
277+
extension MultiGenericStruct where First == PublicStruct, Second == PublicStruct {
278+
// CHECK-NEXT: public func publicPublic(){{$}}
279+
public func publicPublic() {}
280+
} // CHECK-NEXT: {{^[}]$}}
281+
282+
extension MultiGenericStruct where First == PublicStruct, Second == InternalStruct_BAD {
283+
@usableFromInline internal func publicInternal_BAD() {}
284+
}
285+
extension MultiGenericStruct where First == InternalStruct_BAD, Second == PublicStruct {
286+
@usableFromInline internal func internalPublic_BAD() {}
287+
}

0 commit comments

Comments
 (0)