@@ -753,70 +753,69 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI,
753
753
// / Derive a concrete type of self and conformance from the init_existential
754
754
// / instruction.
755
755
static Optional<std::tuple<ProtocolConformanceRef, CanType, SILValue, SILValue>>
756
- getConformanceAndConcreteType (FullApplySite AI,
756
+ getConformanceAndConcreteType (ASTContext &Ctx,
757
+ FullApplySite AI,
757
758
SILInstruction *InitExistential,
758
759
ProtocolDecl *Protocol,
759
760
ArrayRef<ProtocolConformanceRef> &Conformances) {
760
761
// Try to derive the concrete type of self from the found init_existential.
761
762
CanType ConcreteType;
763
+ // The existential type result of the found init_existential.
764
+ CanType ExistentialType;
762
765
SILValue ConcreteTypeDef;
763
766
SILValue NewSelf;
764
767
768
+ // FIXME: Factor this out. All we really need here is the ExistentialSig
769
+ // below, which should be stored directly in the SILInstruction.
765
770
if (auto IE = dyn_cast<InitExistentialAddrInst>(InitExistential)) {
766
771
Conformances = IE->getConformances ();
767
772
ConcreteType = IE->getFormalConcreteType ();
768
773
NewSelf = IE;
774
+ ExistentialType = IE->getOperand ()->getType ().getSwiftRValueType ();
769
775
} else if (auto IER = dyn_cast<InitExistentialRefInst>(InitExistential)) {
770
776
Conformances = IER->getConformances ();
771
777
ConcreteType = IER->getFormalConcreteType ();
772
778
NewSelf = IER->getOperand ();
779
+ ExistentialType = IER->getType ().getSwiftRValueType ();
773
780
} else if (auto IEM = dyn_cast<InitExistentialMetatypeInst>(InitExistential)){
774
781
Conformances = IEM->getConformances ();
775
782
NewSelf = IEM->getOperand ();
776
783
ConcreteType = NewSelf->getType ().getSwiftRValueType ();
777
-
778
- auto ExType = IEM->getType ().getSwiftRValueType ();
779
- while (auto ExMetatype = dyn_cast<ExistentialMetatypeType>(ExType)) {
780
- ExType = ExMetatype.getInstanceType ();
784
+ ExistentialType = IEM->getType ().getSwiftRValueType ();
785
+ while (auto InstanceType = dyn_cast<ExistentialMetatypeType>(ExistentialType)) {
786
+ ExistentialType = InstanceType.getInstanceType ();
781
787
ConcreteType = cast<MetatypeType>(ConcreteType).getInstanceType ();
782
788
}
783
789
} else {
784
790
return None;
785
791
}
786
792
793
+ // Construct a substitution map from the existential type's generic
794
+ // parameter to the concrete type.
795
+ auto ExistentialSig = Ctx.getExistentialSignature (ExistentialType,
796
+ AI.getModule ().getSwiftModule ());
797
+
798
+ Substitution ConcreteSub (ConcreteType, Conformances);
799
+ auto SubMap = ExistentialSig->getSubstitutionMap ({&ConcreteSub, 1 });
800
+
801
+ // If the requirement is in a base protocol that is refined by the
802
+ // conforming protocol, fish out the exact conformance for the base
803
+ // protocol using the substitution map.
804
+ auto ExactConformance = SubMap.lookupConformance (
805
+ CanType (ExistentialSig->getGenericParams ()[0 ]),
806
+ Protocol);
807
+
808
+ // If the concrete type is another existential, we're "forwarding" an
809
+ // opened existential type, so we must keep track of the original
810
+ // defining instruction.
787
811
if (ConcreteType->isOpenedExistential ()) {
788
812
assert (!InitExistential->getTypeDependentOperands ().empty () &&
789
813
" init_existential is supposed to have a typedef operand" );
790
814
ConcreteTypeDef = InitExistential->getTypeDependentOperands ()[0 ].get ();
791
815
}
792
816
793
- // Find the conformance for the protocol we're interested in.
794
- for (auto Conformance : Conformances) {
795
- auto Requirement = Conformance.getRequirement ();
796
- if (Requirement == Protocol) {
797
- return std::make_tuple (Conformance, ConcreteType, ConcreteTypeDef,
798
- NewSelf);
799
- }
800
- // If Requirement != Protocol, then the abstract conformance cannot be
801
- // used as is and we need to create a proper conformance.
802
- // FIXME: We can handle only direct inheritance at the moment due to some
803
- // limitations of the init_existential_* instructions representation.
804
- // Once these instructions start using generic signatures instead of
805
- // conformances lists, it should be fairly easy to support the indirect
806
- // inheritance here by something like:
807
- // Substitution Sub(ConcreteType, Conformances);
808
- // IE->getGenericSignature()
809
- // ->getSubstitutionMap({Sub}).lookupConformance(GP00, Protocol);
810
- auto InheritedProtocols = Requirement->getInheritedProtocols ();
811
- if (std::find (InheritedProtocols.begin (), InheritedProtocols.end (),
812
- Protocol) == InheritedProtocols.end ())
813
- return None;
814
- // Requirement is directly inherited from Protocol.
815
- return std::make_tuple (Conformance.getInherited (Protocol), ConcreteType,
816
- ConcreteTypeDef, NewSelf);
817
- }
818
-
819
- llvm_unreachable (" couldn't find matching conformance in substitution?" );
817
+ return std::make_tuple (*ExactConformance, ConcreteType,
818
+ ConcreteTypeDef, NewSelf);
820
819
}
821
820
822
821
// / Propagate information about a concrete type from init_existential_addr
@@ -829,6 +828,8 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI,
829
828
ProtocolDecl *Protocol,
830
829
llvm::function_ref<void (CanType , ProtocolConformanceRef)> Propagate) {
831
830
831
+ ASTContext &Ctx = Builder.getASTContext ();
832
+
832
833
// Get the self argument.
833
834
SILValue Self;
834
835
if (auto *Apply = dyn_cast<ApplyInst>(AI)) {
@@ -854,8 +855,8 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI,
854
855
// the found init_existential.
855
856
ArrayRef<ProtocolConformanceRef> Conformances;
856
857
auto ConformanceAndConcreteType =
857
- getConformanceAndConcreteType (AI, InitExistential,
858
- Protocol, Conformances);
858
+ getConformanceAndConcreteType (Ctx, AI, InitExistential,
859
+ Protocol, Conformances);
859
860
if (!ConformanceAndConcreteType)
860
861
return nullptr ;
861
862
0 commit comments