Skip to content

Commit 63d0130

Browse files
committed
Devirtualize: Extend SE-0309 bail-out logic to variadic function parameters and Self-rooted type parameters
1 parent fb1aa8b commit 63d0130

File tree

2 files changed

+71
-42
lines changed

2 files changed

+71
-42
lines changed

lib/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,9 +1094,10 @@ static bool canDevirtualizeWitnessMethod(ApplySite applySite) {
10941094
return false;
10951095
}
10961096

1097-
// FIXME: devirtualizeWitnessMethod below does not support cases with
1098-
// covariant 'Self' nested inside a collection type,
1099-
// like '[Self]' or '[* : Self]'.
1097+
// FIXME: devirtualizeWitnessMethod does not support cases with covariant
1098+
// 'Self'-rooted type parameters nested inside a collection type, like
1099+
// '[Self]' or '[* : Self.A]', because it doesn't know how to deal with
1100+
// associated collection upcasts.
11001101
const Type interfaceTy = wmi->getMember()
11011102
.getDecl()
11021103
->getInterfaceType()
@@ -1107,35 +1108,35 @@ static bool canDevirtualizeWitnessMethod(ApplySite applySite) {
11071108
if (!interfaceTy->hasTypeParameter())
11081109
return true;
11091110

1110-
class HasSelfNestedInsideCollection final : public TypeWalker {
1111-
unsigned CollectionDepth;
1111+
auto *const selfGP = wmi->getLookupProtocol()->getProtocolSelfType();
1112+
auto isSelfRootedTypeParameter = [selfGP](Type T) -> bool {
1113+
if (!T->hasTypeParameter())
1114+
return false;
11121115

1113-
public:
1114-
Action walkToTypePre(Type T) override {
1115-
if (!T->hasTypeParameter())
1116-
return Action::SkipChildren;
1116+
if (T->isTypeParameter()) {
1117+
return T->getRootGenericParam()->isEqual(selfGP);
1118+
}
11171119

1118-
if (auto *GP = T->getAs<GenericTypeParamType>()) {
1119-
// Only 'Self' will have zero depth in the type of a requirement.
1120-
if (GP->getDepth() == 0 && CollectionDepth)
1121-
return Action::Stop;
1122-
}
1120+
return false;
1121+
};
11231122

1124-
if (T->isArray() || T->isDictionary())
1125-
++CollectionDepth;
1123+
return !interfaceTy.findIf([&](Type T) -> bool {
1124+
if (!T->hasTypeParameter())
1125+
return false;
11261126

1127-
return Action::Continue;
1127+
if (T->isArray() || T->isDictionary()) {
1128+
return T.findIf(isSelfRootedTypeParameter);
11281129
}
11291130

1130-
Action walkToTypePost(Type T) override {
1131-
if (T->isArray() || T->isDictionary())
1132-
--CollectionDepth;
1133-
1134-
return Action::Continue;
1131+
if (auto *FT = T->getAs<FunctionType>()) {
1132+
for (const auto &Param : FT->getParams()) {
1133+
if (Param.isVariadic() && T.findIf(isSelfRootedTypeParameter))
1134+
return true;
1135+
}
11351136
}
1136-
};
11371137

1138-
return !interfaceTy.walk(HasSelfNestedInsideCollection());
1138+
return false;
1139+
});
11391140
}
11401141

11411142
/// In the cases where we can statically determine the function that

test/SILOptimizer/devirt_protocol_method_invocations.swift

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -290,28 +290,56 @@ public func testReabstracted(f: Optional<()->()>) {
290290
}
291291

292292

293-
// Test that we don't devirtualize calls to protocol requirements with covariant `Self` nested
294-
// inside a collection type – the devirtualizer does not support handling these yet.
295-
protocol CovariantSelfInsideCollection {
296-
func array() -> Array<Self>
297-
func dictionary() -> Dictionary<String, Self>
298-
func mixed(_: (Array<(Dictionary<String, String>, Self)>) -> Void)
293+
// Test that we don't devirtualize calls to protocol requirements with
294+
// covariant `Self`-rooted type parameters nested inside a collection type;
295+
// the devirtualizer doesn't know how to handle these yet.
296+
protocol CovariantSelfInCollection {
297+
associatedtype Assoc
298+
299+
func self1() -> Array<Self>
300+
func self2() -> Dictionary<String, Self>
301+
func self3(_: (Self...) -> Void)
302+
func self4(_: (Array<(Dictionary<String, String>, Self)>) -> Void)
303+
304+
func assoc1() -> Array<Assoc>
305+
func assoc2() -> Dictionary<String, Assoc>
306+
func assoc3(_: (Assoc...) -> Void)
307+
func assoc4(_: (Array<(Dictionary<String, String>, Assoc)>) -> Void)
308+
}
309+
struct CovariantSelfInCollectionImpl: CovariantSelfInCollection {
310+
typealias Assoc = Bool
311+
312+
func self1() -> Array<Self> { [self] }
313+
func self2() -> Dictionary<String, Self> { [#file : self] }
314+
func self3(_: (Self...) -> Void) {}
315+
func self4(_: (Array<(Dictionary<String, String>, Self)>) -> Void) {}
316+
317+
func assoc1() -> Array<Assoc> { [true] }
318+
func assoc2() -> Dictionary<String, Assoc> { [#file : true] }
319+
func assoc3(_: (Assoc...) -> Void) {}
320+
func assoc4(_: (Array<(Dictionary<String, String>, Assoc)>) -> Void) {}
299321
}
300322
// CHECK-LABEL: sil @$s34devirt_protocol_method_invocations12testNoDevirtyyF
301323
//
302-
// CHECK: witness_method $S, #CovariantSelfInsideCollection.array
303-
// CHECK: witness_method $S, #CovariantSelfInsideCollection.dictionary
304-
// CHECK: witness_method $S, #CovariantSelfInsideCollection.mixed
324+
// CHECK: witness_method $CovariantSelfInCollectionImpl, #CovariantSelfInCollection.self1
325+
// CHECK: witness_method $CovariantSelfInCollectionImpl, #CovariantSelfInCollection.self2
326+
// CHECK: witness_method $CovariantSelfInCollectionImpl, #CovariantSelfInCollection.self3
327+
// CHECK: witness_method $CovariantSelfInCollectionImpl, #CovariantSelfInCollection.self4
328+
// CHECK: witness_method $CovariantSelfInCollectionImpl, #CovariantSelfInCollection.assoc1
329+
// CHECK: witness_method $CovariantSelfInCollectionImpl, #CovariantSelfInCollection.assoc2
330+
// CHECK: witness_method $CovariantSelfInCollectionImpl, #CovariantSelfInCollection.assoc3
331+
// CHECK: witness_method $CovariantSelfInCollectionImpl, #CovariantSelfInCollection.assoc4
305332
// CHECK: end sil function '$s34devirt_protocol_method_invocations12testNoDevirtyyF'
306333
public func testNoDevirt() {
307-
struct S: CovariantSelfInsideCollection {
308-
func array() -> Array<Self> { fatalError() }
309-
func dictionary() -> Dictionary<String, Self> { fatalError() }
310-
func mixed(_: (Array<(Dictionary<String, String>, Self)>) -> Void) {}
311-
}
334+
let p: any CovariantSelfInCollection = CovariantSelfInCollectionImpl()
335+
336+
_ = p.self1()
337+
_ = p.self2()
338+
p.self3 { _ in }
339+
p.self4 { _ in }
312340

313-
let p: CovariantSelfInsideCollection = S()
314-
_ = p.array()
315-
_ = p.dictionary()
316-
p.mixed { _ in }
341+
_ = p.assoc1()
342+
_ = p.assoc2()
343+
p.assoc3 { _ in }
344+
p.assoc4 { _ in }
317345
}

0 commit comments

Comments
 (0)