Skip to content

Commit 86ca682

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 lower them appropriately. rdar://94320481
1 parent 2eda219 commit 86ca682

File tree

7 files changed

+159
-6
lines changed

7 files changed

+159
-6
lines changed

include/swift/AST/Types.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5313,8 +5313,8 @@ class ParameterizedProtocolType final : public TypeBase,
53135313
public:
53145314
/// Retrieve an instance of a protocol composition type with the
53155315
/// given set of members.
5316-
static Type get(const ASTContext &C, ProtocolType *base,
5317-
ArrayRef<Type> args);
5316+
static ParameterizedProtocolType *get(const ASTContext &C, ProtocolType *base,
5317+
ArrayRef<Type> args);
53185318

53195319
ProtocolType *getBaseType() const {
53205320
return Base;
@@ -5354,6 +5354,13 @@ class ParameterizedProtocolType final : public TypeBase,
53545354
RecursiveTypeProperties properties);
53555355
};
53565356
BEGIN_CAN_TYPE_WRAPPER(ParameterizedProtocolType, Type)
5357+
static CanParameterizedProtocolType get(const ASTContext &C,
5358+
ProtocolType *base,
5359+
ArrayRef<Type> args) {
5360+
return CanParameterizedProtocolType(
5361+
ParameterizedProtocolType::get(C, base, args));
5362+
}
5363+
53575364
CanProtocolType getBaseType() const {
53585365
return CanProtocolType(getPointer()->getBaseType());
53595366
}
@@ -5420,6 +5427,7 @@ class ExistentialType final : public TypeBase {
54205427
}
54215428
};
54225429
BEGIN_CAN_TYPE_WRAPPER(ExistentialType, Type)
5430+
static CanExistentialType get(CanType constraint);
54235431
PROXY_CAN_TYPE_SIMPLE_GETTER(getConstraintType)
54245432
END_CAN_TYPE_WRAPPER(ExistentialType, Type)
54255433

include/swift/SIL/AbstractionPattern.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,10 @@ class AbstractionPattern {
13611361
/// it.
13621362
AbstractionPattern getReferenceStorageReferentType() const;
13631363

1364+
/// Give that the value being abstracted is an existential, return the
1365+
/// underlying constraint type.
1366+
AbstractionPattern getExistentialConstraintType() const;
1367+
13641368
/// Given that the value being abstracted is a function type, return the
13651369
/// abstraction pattern for the derivative function.
13661370
///

lib/AST/ASTContext.cpp

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

3339-
Type ParameterizedProtocolType::get(const ASTContext &C,
3340-
ProtocolType *baseTy,
3341-
ArrayRef<Type> args) {
3339+
ParameterizedProtocolType *ParameterizedProtocolType::get(const ASTContext &C,
3340+
ProtocolType *baseTy,
3341+
ArrayRef<Type> args) {
33423342
assert(args.size() > 0);
33433343

33443344
bool isCanonical = baseTy->isCanonical();

lib/AST/Type.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1631,7 +1631,7 @@ CanType TypeBase::computeCanonicalType() {
16311631
for (Type t : PPT->getArgs())
16321632
CanArgs.push_back(t->getCanonicalType());
16331633
auto &C = Base->getASTContext();
1634-
Result = ParameterizedProtocolType::get(C, Base, CanArgs).getPointer();
1634+
Result = ParameterizedProtocolType::get(C, Base, CanArgs);
16351635
break;
16361636
}
16371637
case TypeKind::Existential: {
@@ -3844,6 +3844,15 @@ operator()(CanType maybeOpaqueType, Type replacementType,
38443844
return substRef;
38453845
}
38463846

3847+
CanExistentialType CanExistentialType::get(CanType constraint) {
3848+
assert(!(constraint->isAny() || constraint->isAnyObject()) &&
3849+
"Any(Object) may not apppear as canonical constraint type");
3850+
assert(!constraint->is<ExistentialMetatypeType>() &&
3851+
"Existential metatype may not apppear as canonical constraint type");
3852+
return CanExistentialType(
3853+
ExistentialType::get(constraint)->castTo<ExistentialType>());
3854+
}
3855+
38473856
CanPrimaryArchetypeType
38483857
PrimaryArchetypeType::getNew(const ASTContext &Ctx,
38493858
GenericEnvironment *GenericEnv,

lib/SIL/IR/AbstractionPattern.cpp

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

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

1757+
CanType visitExistentialType(ExistentialType *exist,
1758+
AbstractionPattern pattern) {
1759+
if (auto gp = handleTypeParameterInAbstractionPattern(pattern, exist))
1760+
return gp;
1761+
1762+
// Avoid walking into the constraint type if we can help it.
1763+
if (!exist->hasTypeParameter() && !exist->hasArchetype() &&
1764+
!exist->hasOpaqueArchetype()) {
1765+
return CanType(exist);
1766+
}
1767+
1768+
return CanExistentialType::get(visit(
1769+
exist->getConstraintType(), pattern.getExistentialConstraintType()));
1770+
}
1771+
1772+
CanType visitParameterizedProtocolType(ParameterizedProtocolType *ppt,
1773+
AbstractionPattern pattern) {
1774+
if (auto gp = handleTypeParameterInAbstractionPattern(pattern, ppt))
1775+
return gp;
1776+
1777+
// Recurse into the arguments of the parameterized protocol.
1778+
SmallVector<Type, 4> substArgs;
1779+
auto origPPT = pattern.getAs<ParameterizedProtocolType>();
1780+
for (unsigned i = 0; i < ppt->getArgs().size(); ++i) {
1781+
auto argTy = ppt->getArgs()[i];
1782+
auto origArgTy = AbstractionPattern(pattern.getGenericSignatureOrNull(),
1783+
origPPT.getArgs()[i]);
1784+
auto substEltTy = visit(argTy, origArgTy);
1785+
substArgs.push_back(substEltTy);
1786+
}
1787+
1788+
return CanType(ParameterizedProtocolType::get(
1789+
TC.Context, ppt->getBaseType(), substArgs));
1790+
}
1791+
17081792
CanType visitTupleType(TupleType *tuple, AbstractionPattern pattern) {
17091793
if (auto gp = handleTypeParameterInAbstractionPattern(pattern, tuple))
17101794
return gp;

lib/SIL/IR/TypeLowering.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2265,6 +2265,44 @@ TypeConverter::computeLoweredRValueType(TypeExpansionContext forExpansion,
22652265
MetatypeRepresentation::Thick);
22662266
}
22672267

2268+
CanType visitExistentialType(CanExistentialType substExistType) {
2269+
// Try to avoid walking into the constraint type if we can help it
2270+
if (!substExistType->hasTypeParameter() &&
2271+
!substExistType->hasArchetype() &&
2272+
!substExistType->hasOpaqueArchetype()) {
2273+
return substExistType;
2274+
}
2275+
2276+
return CanExistentialType::get(visit(substExistType.getConstraintType()));
2277+
}
2278+
2279+
CanType
2280+
visitParameterizedProtocolType(CanParameterizedProtocolType substPPT) {
2281+
bool changed = false;
2282+
SmallVector<Type, 4> loweredSubstArgs;
2283+
loweredSubstArgs.reserve(substPPT.getArgs().size());
2284+
2285+
auto origConstraint = origType.getExistentialConstraintType();
2286+
auto origPPT = origConstraint.getAs<ParameterizedProtocolType>();
2287+
for (auto i : indices(substPPT.getArgs())) {
2288+
auto origArgTy = AbstractionPattern(
2289+
origConstraint.getGenericSignatureOrNull(), origPPT.getArgs()[i]);
2290+
auto substArgType = substPPT.getArgs()[i];
2291+
2292+
CanType loweredSubstEltType =
2293+
TC.getLoweredRValueType(forExpansion, origArgTy, substArgType);
2294+
changed = changed || substArgType != loweredSubstEltType;
2295+
2296+
loweredSubstArgs.push_back(loweredSubstEltType);
2297+
}
2298+
2299+
if (!changed)
2300+
return substPPT;
2301+
2302+
return CanParameterizedProtocolType::get(
2303+
TC.Context, substPPT->getBaseType(), loweredSubstArgs);
2304+
}
2305+
22682306
CanType visitPackType(CanPackType substPackType) {
22692307
llvm_unreachable("");
22702308
}

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)