@@ -994,6 +994,48 @@ struct ConcreteArgumentCopy {
994994 }
995995};
996996
997+ SILValue SILCombiner::canCastArg (FullApplySite Apply,
998+ const OpenedArchetypeInfo &OAI,
999+ const ConcreteExistentialInfo &CEI,
1000+ unsigned ArgIdx) {
1001+ if (!CEI.ConcreteValue || CEI.ConcreteType ->isOpenedExistential () ||
1002+ !CEI.ConcreteValue ->getType ().isAddress ())
1003+ return SILValue ();
1004+
1005+ // Don't specialize apply instructions that return the callee's Arg type,
1006+ // because this optimization does not know how to substitute types in the
1007+ // users of this apply. In the function type substitution below, all
1008+ // references to OpenedArchetype will be substituted. So walk to type to
1009+ // find all possible references, such as returning Optional<Arg>.
1010+ if (Apply.getType ().getASTType ().findIf (
1011+ [&OAI](Type t) -> bool { return t->isEqual (OAI.OpenedArchetype ); })) {
1012+ return SILValue ();
1013+ }
1014+ // Bail out if any other arguments or indirect result that refer to the
1015+ // OpenedArchetype. The following optimization substitutes all occurrences
1016+ // of OpenedArchetype in the function signature, but will only rewrite the
1017+ // Arg operand.
1018+ //
1019+ // Note that the language does not allow Self to occur in contravariant
1020+ // position. However, SIL does allow this and it can happen as a result of
1021+ // upstream transformations. Since this is bail-out logic, it must handle
1022+ // all verifiable SIL.
1023+
1024+ // This bailout check is also needed for non-Self arguments [including Self].
1025+ unsigned NumApplyArgs = Apply.getNumArguments ();
1026+ for (unsigned Idx = 0 ; Idx < NumApplyArgs; ++Idx) {
1027+ if (Idx == ArgIdx)
1028+ continue ;
1029+ if (Apply.getArgument (Idx)->getType ().getASTType ().findIf (
1030+ [&OAI](Type t) -> bool {
1031+ return t->isEqual (OAI.OpenedArchetype );
1032+ })) {
1033+ return SILValue ();
1034+ }
1035+ }
1036+ return Builder.createUncheckedAddrCast (
1037+ Apply.getLoc (), Apply.getArgument (ArgIdx), CEI.ConcreteValue ->getType ());
1038+ }
9971039// / Rewrite the given method apply instruction in terms of the provided conrete
9981040// / type information.
9991041// /
@@ -1049,6 +1091,32 @@ SILInstruction *SILCombiner::createApplyWithConcreteType(
10491091
10501092 // Check for Arg's concrete type propagation legality.
10511093 if (!canReplaceArg (Apply, OAI, CEI, ArgIdx)) {
1094+
1095+ // As on last fall-back try to cast the argument.
1096+ if (auto cast = canCastArg (Apply, OAI, CEI, ArgIdx)) {
1097+ NewArgs.push_back (cast);
1098+ // Form a new set of substitutions where the argument is
1099+ // replaced with a concrete type.
1100+ NewCallSubs = NewCallSubs.subst (
1101+ [&](SubstitutableType *type) -> Type {
1102+ if (type == OAI.OpenedArchetype )
1103+ return CEI.ConcreteType ;
1104+ return type;
1105+ },
1106+ [&](CanType origTy, Type substTy,
1107+ ProtocolDecl *proto) -> ProtocolConformanceRef {
1108+ if (origTy->isEqual (OAI.OpenedArchetype )) {
1109+ assert (substTy->isEqual (CEI.ConcreteType ));
1110+ // Do a conformance lookup on this witness requirement using the
1111+ // existential's conformances. The witness requirement may be a
1112+ // base type of the existential's requirements.
1113+ return CEI.lookupExistentialConformance (proto);
1114+ }
1115+ return ProtocolConformanceRef (proto);
1116+ });
1117+ continue ;
1118+ }
1119+ // Otherwise, use the original argument.
10521120 NewArgs.push_back (Apply.getArgument (ArgIdx));
10531121 continue ;
10541122 }
0 commit comments