Skip to content

Commit 3fb3fa3

Browse files
committed
Recurse Into Existential Types With Generic Structure
Before the introduction of parameterized existential types, there was no generic structure under these types. Now that there is, we'll need to recurse into them to pick up any latent generic types and re-abstract them appropriately. rdar://94320481
1 parent a38fc3d commit 3fb3fa3

File tree

7 files changed

+153
-6
lines changed

7 files changed

+153
-6
lines changed

include/swift/AST/Types.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5366,8 +5366,8 @@ class ParameterizedProtocolType final : public TypeBase,
53665366
public:
53675367
/// Retrieve an instance of a protocol composition type with the
53685368
/// given set of members.
5369-
static Type get(const ASTContext &C, ProtocolType *base,
5370-
ArrayRef<Type> args);
5369+
static ParameterizedProtocolType *get(const ASTContext &C, ProtocolType *base,
5370+
ArrayRef<Type> args);
53715371

53725372
ProtocolType *getBaseType() const {
53735373
return Base;
@@ -5407,6 +5407,12 @@ class ParameterizedProtocolType final : public TypeBase,
54075407
RecursiveTypeProperties properties);
54085408
};
54095409
BEGIN_CAN_TYPE_WRAPPER(ParameterizedProtocolType, Type)
5410+
static CanParameterizedProtocolType get(const ASTContext &C, ProtocolType *base,
5411+
ArrayRef<Type> args) {
5412+
return CanParameterizedProtocolType(
5413+
ParameterizedProtocolType::get(C, base, args));
5414+
}
5415+
54105416
CanProtocolType getBaseType() const {
54115417
return CanProtocolType(getPointer()->getBaseType());
54125418
}
@@ -5473,6 +5479,11 @@ class ExistentialType final : public TypeBase {
54735479
}
54745480
};
54755481
BEGIN_CAN_TYPE_WRAPPER(ExistentialType, Type)
5482+
static CanExistentialType get(CanType constraint) {
5483+
return CanExistentialType(
5484+
ExistentialType::get(constraint, /*forceExistential*/ true)
5485+
->castTo<ExistentialType>());
5486+
}
54765487
PROXY_CAN_TYPE_SIMPLE_GETTER(getConstraintType)
54775488
END_CAN_TYPE_WRAPPER(ExistentialType, Type)
54785489

include/swift/SIL/AbstractionPattern.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,6 +1287,10 @@ class AbstractionPattern {
12871287
/// it.
12881288
AbstractionPattern getReferenceStorageReferentType() const;
12891289

1290+
/// Give that the value being abstracted is an existential, return the
1291+
/// underlying constraint type.
1292+
AbstractionPattern getExistentialConstraintType() const;
1293+
12901294
/// Given that the value being abstracted is a function type, return the
12911295
/// abstraction pattern for the derivative function.
12921296
///

lib/AST/ASTContext.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3327,9 +3327,9 @@ ProtocolCompositionType::build(const ASTContext &C, ArrayRef<Type> Members,
33273327
return compTy;
33283328
}
33293329

3330-
Type ParameterizedProtocolType::get(const ASTContext &C,
3331-
ProtocolType *baseTy,
3332-
ArrayRef<Type> args) {
3330+
ParameterizedProtocolType *ParameterizedProtocolType::get(const ASTContext &C,
3331+
ProtocolType *baseTy,
3332+
ArrayRef<Type> args) {
33333333
assert(args.size() > 0);
33343334

33353335
bool isCanonical = baseTy->isCanonical();

lib/AST/Type.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1641,7 +1641,7 @@ CanType TypeBase::computeCanonicalType() {
16411641
for (Type t : PPT->getArgs())
16421642
CanArgs.push_back(t->getCanonicalType());
16431643
auto &C = Base->getASTContext();
1644-
Result = ParameterizedProtocolType::get(C, Base, CanArgs).getPointer();
1644+
Result = ParameterizedProtocolType::get(C, Base, CanArgs);
16451645
break;
16461646
}
16471647
case TypeKind::Existential: {

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,55 @@ AbstractionPattern AbstractionPattern::getReferenceStorageReferentType() const {
943943
llvm_unreachable("bad kind");
944944
}
945945

946+
static CanType getExistentialConstraintType(CanType type) {
947+
assert(type.isExistentialType());
948+
if (auto *ET = type->getAs<ExistentialType>()) {
949+
return CanType(ET->getConstraintType());
950+
}
951+
return type;
952+
}
953+
954+
AbstractionPattern AbstractionPattern::getExistentialConstraintType() const {
955+
switch (getKind()) {
956+
case Kind::Invalid:
957+
llvm_unreachable("querying invalid abstraction pattern!");
958+
case Kind::ObjCMethodType:
959+
case Kind::CurriedObjCMethodType:
960+
case Kind::PartialCurriedObjCMethodType:
961+
case Kind::CFunctionAsMethodType:
962+
case Kind::CurriedCFunctionAsMethodType:
963+
case Kind::PartialCurriedCFunctionAsMethodType:
964+
case Kind::CXXMethodType:
965+
case Kind::CurriedCXXMethodType:
966+
case Kind::PartialCurriedCXXMethodType:
967+
case Kind::Tuple:
968+
case Kind::OpaqueFunction:
969+
case Kind::OpaqueDerivativeFunction:
970+
case Kind::ObjCCompletionHandlerArgumentsType:
971+
llvm_unreachable("pattern for function or tuple cannot be for optional");
972+
973+
case Kind::Opaque:
974+
return *this;
975+
976+
case Kind::Type:
977+
if (isTypeParameterOrOpaqueArchetype())
978+
return AbstractionPattern::getOpaque();
979+
return AbstractionPattern(getGenericSignature(),
980+
::getExistentialConstraintType(getType()));
981+
982+
case Kind::Discard:
983+
return AbstractionPattern::getDiscard(
984+
getGenericSignature(), ::getExistentialConstraintType(getType()));
985+
986+
case Kind::ClangType:
987+
// This is not reflected in clang types.
988+
return AbstractionPattern(getGenericSignature(),
989+
::getExistentialConstraintType(getType()),
990+
getClangType());
991+
}
992+
llvm_unreachable("bad kind");
993+
}
994+
946995
void AbstractionPattern::dump() const {
947996
print(llvm::errs());
948997
llvm::errs() << "\n";
@@ -1683,6 +1732,41 @@ class SubstFunctionTypePatternVisitor
16831732
llvm_unreachable("Unimplemented!");
16841733
}
16851734

1735+
CanType visitExistentialType(ExistentialType *exist,
1736+
AbstractionPattern pattern) {
1737+
if (auto gp = handleTypeParameterInAbstractionPattern(pattern, exist))
1738+
return gp;
1739+
1740+
// Avoid walking into the constraint type if we can help it.
1741+
if (!exist->hasTypeParameter() && !exist->hasArchetype() &&
1742+
!exist->hasOpaqueArchetype()) {
1743+
return CanType(exist);
1744+
}
1745+
1746+
return CanExistentialType::get(visit(
1747+
exist->getConstraintType(), pattern.getExistentialConstraintType()));
1748+
}
1749+
1750+
CanType visitParameterizedProtocolType(ParameterizedProtocolType *ppt,
1751+
AbstractionPattern pattern) {
1752+
if (auto gp = handleTypeParameterInAbstractionPattern(pattern, ppt))
1753+
return gp;
1754+
1755+
// Recurse into the arguments of the parameterized protocol.
1756+
SmallVector<Type, 4> substArgs;
1757+
auto origPPT = pattern.getAs<ParameterizedProtocolType>();
1758+
for (unsigned i = 0; i < ppt->getArgs().size(); ++i) {
1759+
auto argTy = ppt->getArgs()[i];
1760+
auto origArgTy = AbstractionPattern(pattern.getGenericSignatureOrNull(),
1761+
origPPT.getArgs()[i]);
1762+
auto substEltTy = visit(argTy, origArgTy);
1763+
substArgs.push_back(substEltTy);
1764+
}
1765+
1766+
return CanType(ParameterizedProtocolType::get(
1767+
TC.Context, ppt->getBaseType(), substArgs));
1768+
}
1769+
16861770
CanType visitTupleType(TupleType *tuple, AbstractionPattern pattern) {
16871771
if (auto gp = handleTypeParameterInAbstractionPattern(pattern, tuple))
16881772
return gp;

lib/SIL/IR/TypeLowering.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,6 +2500,44 @@ TypeConverter::computeLoweredRValueType(TypeExpansionContext forExpansion,
25002500
MetatypeRepresentation::Thick);
25012501
}
25022502

2503+
CanType visitExistentialType(CanExistentialType substExistType) {
2504+
// Try to avoid walking into the constraint type if we can help it
2505+
if (!substExistType->hasTypeParameter() &&
2506+
!substExistType->hasArchetype() &&
2507+
!substExistType->hasOpaqueArchetype()) {
2508+
return substExistType;
2509+
}
2510+
2511+
return CanExistentialType::get(visit(substExistType.getConstraintType()));
2512+
}
2513+
2514+
CanType
2515+
visitParameterizedProtocolType(CanParameterizedProtocolType substPPT) {
2516+
bool changed = false;
2517+
SmallVector<Type, 4> loweredSubstArgs;
2518+
loweredSubstArgs.reserve(substPPT.getArgs().size());
2519+
2520+
auto origConstraint = origType.getExistentialConstraintType();
2521+
auto origPPT = origConstraint.getAs<ParameterizedProtocolType>();
2522+
for (auto i : indices(substPPT.getArgs())) {
2523+
auto origArgTy = AbstractionPattern(
2524+
origConstraint.getGenericSignatureOrNull(), origPPT.getArgs()[i]);
2525+
auto substArgType = substPPT.getArgs()[i];
2526+
2527+
CanType loweredSubstEltType =
2528+
TC.getLoweredRValueType(forExpansion, origArgTy, substArgType);
2529+
changed = changed || substArgType != loweredSubstEltType;
2530+
2531+
loweredSubstArgs.push_back(loweredSubstEltType);
2532+
}
2533+
2534+
if (!changed)
2535+
return substPPT;
2536+
2537+
return CanParameterizedProtocolType::get(
2538+
TC.Context, substPPT->getBaseType(), loweredSubstArgs);
2539+
}
2540+
25032541
CanType visitPackType(CanPackType substPackType) {
25042542
llvm_unreachable("");
25052543
}

test/SILGen/parameterized_existentials.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ struct S: Q {
2222
typealias Z = Float
2323
}
2424

25+
struct R<T, U, V> {
26+
var force: () -> any P<T, U, V>
27+
// CHECK-LABEL: sil hidden [ossa] @$s13parameterized1RV5forceACyxq_q0_GAA1P_pyxq_q0_XPyc_tcfC : $@convention(method) <T, U, V> (@owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> () -> @out P<τ_0_0, τ_0_1, τ_0_2> for <T, U, V>, @thin R<T, U, V>.Type) -> @owned R<T, U, V> {
28+
}
29+
2530
// CHECK-LABEL: sil hidden [ossa] @$s13parameterized6upcastyAA1P_pAA1SVF : $@convention(thin) (S) -> @out P {
2631
func upcast(_ x: S) -> any P {
2732
// CHECK: bb0([[RESULT_PARAM:%.*]] : $*P, [[CONCRETE_VAL:%.*]] : $S):
@@ -88,3 +93,8 @@ func upcastResult() {
8893

8994
reuse({ () -> any Q<Int, String, Float> in S() })
9095
}
96+
97+
// CHECK-LABEL: sil hidden [ossa] @$s13parameterized5forceAA1P_pyxq_q0_XPyr1_lF : $@convention(thin) <T, U, V> () -> @out P<T, U, V> {
98+
func force<T, U, V>() -> any P<T, U, V> {
99+
return R(force: { force() }).force()
100+
}

0 commit comments

Comments
 (0)