@@ -712,7 +712,8 @@ DevirtualizationResult swift::tryDevirtualizeClassMethod(FullApplySite AI,
712
712
// ===----------------------------------------------------------------------===//
713
713
714
714
static SubstitutionMap
715
- getSubstitutionsForProtocolConformance (ProtocolConformanceRef CRef) {
715
+ getSubstitutionsForProtocolConformance (ModuleDecl *M,
716
+ ProtocolConformanceRef CRef) {
716
717
auto C = CRef.getConcrete ();
717
718
718
719
// Walk down to the base NormalProtocolConformance.
@@ -746,8 +747,7 @@ getSubstitutionsForProtocolConformance(ProtocolConformanceRef CRef) {
746
747
747
748
if (Subs.empty ()) {
748
749
auto *DC = NormalC->getDeclContext ();
749
- return NormalC->getType ()
750
- ->getContextSubstitutionMap (DC->getParentModule (), DC);
750
+ return NormalC->getType ()->getContextSubstitutionMap (M, DC);
751
751
}
752
752
753
753
return NormalC->getGenericSignature ()->getSubstitutionMap (Subs);
@@ -764,17 +764,50 @@ getSubstitutionsForProtocolConformance(ProtocolConformanceRef CRef) {
764
764
// / are written in terms of the requirement's generic signature need
765
765
// / to be remapped to substitutions suitable for the witness signature.
766
766
// /
767
+ // / Supported remappings are:
768
+ // /
769
+ // / - (Concrete witness thunk) Original substitutions:
770
+ // / [Self := ConcreteType, R0 := X0, R1 := X1, ...]
771
+ // / - Requirement generic signature:
772
+ // / <Self : P, R0, R1, ...>
773
+ // / - Witness thunk generic signature:
774
+ // / <W0, W1, ...>
775
+ // / - Remapped substitutions:
776
+ // / [W0 := X0, W1 := X1, ...]
777
+ // /
778
+ // / - (Class witness thunk) Original substitutions:
779
+ // / [Self := C<A0, A1>, T0 := X0, T1 := X1, ...]
780
+ // / - Requirement generic signature:
781
+ // / <Self : P, R0, R1, ...>
782
+ // / - Witness thunk generic signature:
783
+ // / <Self : C<B0, B1>, B0, B1, W0, W1, ...>
784
+ // / - Remapped substitutions:
785
+ // / [Self := C<B0, B1>, B0 := A0, B1 := A1, W0 := X0, W1 := X1]
786
+ // /
787
+ // / - (Default witness thunk) Original substitutions:
788
+ // / [Self := ConcreteType, R0 := X0, R1 := X1, ...]
789
+ // / - Requirement generic signature:
790
+ // / <Self : P, R0, R1, ...>
791
+ // / - Witness thunk generic signature:
792
+ // / <Self : P, W0, W1, ...>
793
+ // / - Remapped substitutions:
794
+ // / [Self := ConcreteType, W0 := X0, W1 := X1, ...]
795
+ // /
767
796
// / \param conformanceRef The (possibly-specialized) conformance
768
797
// / \param requirementSig The generic signature of the requirement
769
798
// / \param witnessThunkSig The generic signature of the witness method
770
799
// / \param origSubs The substitutions from the call instruction
800
+ // / \param isDefaultWitness True if this is a default witness method
801
+ // / \param classWitness The ClassDecl if this is a class witness method
771
802
static SubstitutionMap
772
803
getWitnessMethodSubstitutions (
804
+ ModuleDecl *mod,
773
805
ProtocolConformanceRef conformanceRef,
774
806
GenericSignature *requirementSig,
775
807
GenericSignature *witnessThunkSig,
776
808
SubstitutionList origSubs,
777
- bool isDefaultWitness) {
809
+ bool isDefaultWitness,
810
+ ClassDecl *classWitness) {
778
811
779
812
if (witnessThunkSig == nullptr )
780
813
return SubstitutionMap ();
@@ -789,7 +822,7 @@ getWitnessMethodSubstitutions(
789
822
790
823
// If `Self` maps to a bound generic type, this gives us the
791
824
// substitutions for the concrete type's generic parameters.
792
- auto baseSubMap = getSubstitutionsForProtocolConformance (conformanceRef);
825
+ auto baseSubMap = getSubstitutionsForProtocolConformance (mod, conformanceRef);
793
826
794
827
unsigned baseDepth = 0 ;
795
828
auto *rootConformance = conformance->getRootNormalConformance ();
@@ -798,6 +831,39 @@ getWitnessMethodSubstitutions(
798
831
799
832
auto origDepth = 1 ;
800
833
834
+ // If the witness has a class-constrained 'Self' generic parameter,
835
+ // we have to build a new substitution map that shifts all generic
836
+ // parameters down by one.
837
+ if (classWitness != nullptr ) {
838
+ baseDepth += 1 ;
839
+
840
+ auto &ctx = mod->getASTContext ();
841
+ auto *proto = conformance->getProtocol ();
842
+ auto selfType = proto->getSelfInterfaceType ();
843
+
844
+ auto witnessThunkToWitnessMap = witnessThunkSig->getSubstitutionMap (
845
+ [&](SubstitutableType *type) -> Type {
846
+ if (type->isEqual (selfType))
847
+ return classWitness->getSelfInterfaceType ();
848
+
849
+ auto *origParamTy = cast<GenericTypeParamType>(type);
850
+ auto *substParamTy = GenericTypeParamType::get (
851
+ origParamTy->getDepth () - 1 ,
852
+ origParamTy->getIndex (),
853
+ ctx);
854
+
855
+ return substParamTy;
856
+ },
857
+ [&](CanType origType, Type replacementType, ProtocolType *protoType)
858
+ -> Optional<ProtocolConformanceRef> {
859
+ assert (!origType->isEqual (selfType));
860
+
861
+ return ProtocolConformanceRef (protoType->getDecl ());
862
+ });
863
+
864
+ baseSubMap = witnessThunkToWitnessMap.subst (baseSubMap);
865
+ }
866
+
801
867
return SubstitutionMap::combineSubstitutionMaps (
802
868
baseSubMap,
803
869
origSubMap,
@@ -807,24 +873,40 @@ getWitnessMethodSubstitutions(
807
873
witnessThunkSig);
808
874
}
809
875
876
+ static ClassDecl *
877
+ getWitnessMethodClass (SILFunctionType *witnessFnTy, ModuleDecl &M) {
878
+ auto selfTy = witnessFnTy->getSelfInstanceType ();
879
+ auto genericSig = witnessFnTy->getGenericSignature ();
880
+ if (auto paramTy = dyn_cast<GenericTypeParamType>(selfTy)) {
881
+ auto superclass = genericSig->getSuperclassBound (paramTy, M);
882
+ if (superclass)
883
+ return superclass->getClassOrBoundGenericClass ();
884
+ }
885
+
886
+ return nullptr ;
887
+ }
888
+
810
889
static SubstitutionMap
811
890
getWitnessMethodSubstitutions (SILModule &Module, ApplySite AI, SILFunction *F,
812
891
ProtocolConformanceRef CRef) {
892
+ auto witnessFnTy = F->getLoweredFunctionType ();
893
+ assert (witnessFnTy->getRepresentation () ==
894
+ SILFunctionTypeRepresentation::WitnessMethod);
895
+
813
896
auto requirementSig = AI.getOrigCalleeType ()->getGenericSignature ();
814
- auto witnessThunkSig = F-> getLoweredFunctionType () ->getGenericSignature ();
897
+ auto witnessThunkSig = witnessFnTy ->getGenericSignature ();
815
898
816
899
SubstitutionList origSubs = AI.getSubstitutions ();
817
900
901
+ auto *mod = Module.getSwiftModule ();
818
902
bool isDefaultWitness =
819
- F->getLoweredFunctionType ()->getRepresentation ()
820
- == SILFunctionTypeRepresentation::WitnessMethod &&
821
- F->getLoweredFunctionType ()->getDefaultWitnessMethodProtocol (
822
- *Module.getSwiftModule ())
823
- == CRef.getRequirement ();
903
+ (witnessFnTy->getDefaultWitnessMethodProtocol (*mod)
904
+ == CRef.getRequirement ());
905
+ auto *classWitness = getWitnessMethodClass (witnessFnTy, *mod);
824
906
825
907
return getWitnessMethodSubstitutions (
826
- CRef, requirementSig, witnessThunkSig,
827
- origSubs, isDefaultWitness);
908
+ mod, CRef, requirementSig, witnessThunkSig,
909
+ origSubs, isDefaultWitness, classWitness );
828
910
}
829
911
830
912
// / Generate a new apply of a function_ref to replace an apply of a
0 commit comments