Skip to content

Commit b5965f2

Browse files
authored
Merge pull request #5571 from DougGregor/devirtualize-default-generic-witness
[Devirtualizer] Handle default witnesses for generic requirements.
2 parents 983293c + 1b9946b commit b5965f2

File tree

2 files changed

+67
-20
lines changed

2 files changed

+67
-20
lines changed

lib/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,7 @@ static void getWitnessMethodSubstitutions(
791791
GenericSignature *requirementSig,
792792
GenericSignature *witnessThunkSig,
793793
ArrayRef<Substitution> origSubs,
794+
bool isDefaultWitness,
794795
SmallVectorImpl<Substitution> &newSubs) {
795796

796797
if (witnessThunkSig == nullptr)
@@ -806,19 +807,28 @@ static void getWitnessMethodSubstitutions(
806807
SubstitutionMap subMap;
807808

808809
// Take apart substitutions from the conforming type.
809-
//
810-
// If `Self` maps to a bound generic type, this gives us the
811-
// substitutions for the concrete type's generic parameters.
812-
auto witnessSubs = getSubstitutionsForProtocolConformance(conformanceRef);
813-
810+
ArrayRef<Substitution> witnessSubs;
811+
auto *rootConformance = conformance->getRootNormalConformance();
812+
auto *witnessSig = rootConformance->getGenericSignature();
814813
unsigned depth = 0;
815-
if (!witnessSubs.empty()) {
816-
auto *rootConformance = conformance->getRootNormalConformance();
817-
depth = rootConformance->getGenericSignature()->getGenericParams().back()
818-
->getDepth() + 1;
819-
auto *witnessSig = rootConformance->getGenericSignature();
814+
if (isDefaultWitness) {
815+
// For default witnesses, we substitute all of Self.
816+
auto gp = witnessThunkSig->getGenericParams().front()->getCanonicalType();
817+
subMap.addSubstitution(gp, origSubs.front().getReplacement());
818+
subMap.addConformances(gp, origSubs.front().getConformances());
819+
820+
// For default witnesses, innermost generic parameters are always at
821+
// depth 1.
822+
depth = 1;
823+
} else {
824+
// If `Self` maps to a bound generic type, this gives us the
825+
// substitutions for the concrete type's generic parameters.
826+
witnessSubs = getSubstitutionsForProtocolConformance(conformanceRef);
820827

821-
witnessSig->getSubstitutionMap(witnessSubs, subMap);
828+
if (!witnessSubs.empty()) {
829+
witnessSig->getSubstitutionMap(witnessSubs, subMap);
830+
depth = witnessSig->getGenericParams().back()->getDepth() + 1;
831+
}
822832
}
823833

824834
// Next, take apart caller-side substitutions.
@@ -890,17 +900,15 @@ static void getWitnessMethodSubstitutions(ApplySite AI, SILFunction *F,
890900

891901
ArrayRef<Substitution> origSubs = AI.getSubstitutions();
892902

893-
if (F->getLoweredFunctionType()->getRepresentation()
894-
== SILFunctionTypeRepresentation::WitnessMethod &&
895-
F->getLoweredFunctionType()->getDefaultWitnessMethodProtocol(
896-
*Module.getSwiftModule())) {
897-
// Default witness thunks use the generic signature of the requirement.
898-
NewSubs.append(origSubs.begin(), origSubs.end());
899-
return;
900-
}
903+
bool isDefaultWitness =
904+
F->getLoweredFunctionType()->getRepresentation()
905+
== SILFunctionTypeRepresentation::WitnessMethod &&
906+
F->getLoweredFunctionType()->getDefaultWitnessMethodProtocol(
907+
*Module.getSwiftModule())
908+
== CRef.getRequirement();
901909

902910
getWitnessMethodSubstitutions(Module, CRef, requirementSig, witnessThunkSig,
903-
origSubs, NewSubs);
911+
origSubs, isDefaultWitness, NewSubs);
904912
}
905913

906914
/// Check if an upcast is legal.

test/SILOptimizer/devirt_default_witness_method.sil

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import Builtin
55
import Swift
66
import SwiftShims
77

8+
public protocol P { }
9+
public protocol Q : P { }
10+
extension Int : P, Q { }
11+
812
public protocol ResilientProtocol {
913
func defaultA()
1014
}
@@ -35,6 +39,28 @@ sil_witness_table <T> ConformingGenericStruct<T> : ResilientProtocol module prot
3539
method #ResilientProtocol.defaultA!1: @defaultA
3640
}
3741

42+
public protocol ResilientProtocolWithGeneric {
43+
func defaultB<T: Q>(_: T)
44+
}
45+
46+
sil @defaultB : $@convention(witness_method) <Self where Self : ResilientProtocolWithGeneric><T where T : P> (@in T, @in_guaranteed Self) -> () {
47+
bb0(%0 : $*T, %1 : $*Self):
48+
%result = tuple ()
49+
return %result : $()
50+
}
51+
52+
sil_default_witness_table ResilientProtocolWithGeneric {
53+
method #ResilientProtocolWithGeneric.defaultB!1: @defaultB
54+
}
55+
56+
extension ConformingGenericStruct : ResilientProtocolWithGeneric {
57+
func defaultB<T>(_: T)
58+
}
59+
60+
sil_witness_table <T> ConformingGenericStruct<T> : ResilientProtocolWithGeneric module protocol_resilience {
61+
method #ResilientProtocolWithGeneric.defaultB!1: @defaultB
62+
}
63+
3864
// CHECK-LABEL: sil hidden @test_devirt_of_default_witness_method : $@convention(thin) (@in_guaranteed ConformingStruct) -> ()
3965
// CHECK: bb0(%0 : $*ConformingStruct):
4066
// CHECK: [[FN:%.*]] = function_ref @defaultA : $@convention(witness_method) <τ_0_0 where τ_0_0 : ResilientProtocol> (@in_guaranteed τ_0_0) -> ()
@@ -60,3 +86,16 @@ bb0(%0 : $*ConformingGenericStruct<Int>):
6086
%result = apply %fn<ConformingGenericStruct<Int>>(%0) : $@convention(witness_method) <T where T : ResilientProtocol> (@in_guaranteed T) -> ()
6187
return %result : $()
6288
}
89+
90+
// CHECK-LABEL: test_devirt_of_inner_generic_default_witness_method
91+
// CHECK: bb0(%0 : $*ConformingGenericStruct<Int>, %1 : $*Int):
92+
// CHECK: [[FN:%[0-9]+]] = function_ref @defaultB : $@convention(witness_method) <τ_0_0 where τ_0_0 : ResilientProtocolWithGeneric><τ_1_0 where τ_1_0 : P> (@in τ_1_0, @in_guaranteed τ_0_0) -> ()
93+
// CHECK: [[RESULT:%[0-9]+]] = apply [[FN]]<ConformingGenericStruct<Int>, Int>(%1, %0) : $@convention(witness_method) <τ_0_0 where τ_0_0 : ResilientProtocolWithGeneric><τ_1_0 where τ_1_0 : P> (@in τ_1_0, @in_guaranteed τ_0_0) -> ()
94+
// CHECK: return [[RESULT]] : $()
95+
// CHECK: }
96+
sil hidden @test_devirt_of_inner_generic_default_witness_method : $@convention(thin) (@in_guaranteed ConformingGenericStruct<Int>, @in Int) -> () {
97+
bb0(%0 : $*ConformingGenericStruct<Int>, %1 : $*Int):
98+
%fn = witness_method $ConformingGenericStruct<Int>, #ResilientProtocolWithGeneric.defaultB!1 : $@convention(witness_method) <T where T : ResilientProtocolWithGeneric><U where U : Q> (@in U, @in_guaranteed T) -> ()
99+
%result = apply %fn<ConformingGenericStruct<Int>, Int>(%1, %0) : $@convention(witness_method) <T where T : ResilientProtocolWithGeneric><U where U : Q> (@in U, @in_guaranteed T) -> ()
100+
return %result : $()
101+
}

0 commit comments

Comments
 (0)