Skip to content

Commit 0c67ce6

Browse files
authored
Merge pull request #59544 from CodaFi/abstract-art
2 parents 9d791b5 + ce4afc7 commit 0c67ce6

File tree

7 files changed

+165
-6
lines changed

7 files changed

+165
-6
lines changed

include/swift/AST/Types.h

+10-2
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,13 @@ class ParameterizedProtocolType final : public TypeBase,
54075407
RecursiveTypeProperties properties);
54085408
};
54095409
BEGIN_CAN_TYPE_WRAPPER(ParameterizedProtocolType, Type)
5410+
static CanParameterizedProtocolType get(const ASTContext &C,
5411+
ProtocolType *base,
5412+
ArrayRef<Type> args) {
5413+
return CanParameterizedProtocolType(
5414+
ParameterizedProtocolType::get(C, base, args));
5415+
}
5416+
54105417
CanProtocolType getBaseType() const {
54115418
return CanProtocolType(getPointer()->getBaseType());
54125419
}
@@ -5473,6 +5480,7 @@ class ExistentialType final : public TypeBase {
54735480
}
54745481
};
54755482
BEGIN_CAN_TYPE_WRAPPER(ExistentialType, Type)
5483+
static CanExistentialType get(CanType constraint);
54765484
PROXY_CAN_TYPE_SIMPLE_GETTER(getConstraintType)
54775485
END_CAN_TYPE_WRAPPER(ExistentialType, Type)
54785486

include/swift/SIL/AbstractionPattern.h

+4
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

+3-3
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

+10-1
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: {
@@ -3854,6 +3854,15 @@ operator()(CanType maybeOpaqueType, Type replacementType,
38543854
return substRef;
38553855
}
38563856

3857+
CanExistentialType CanExistentialType::get(CanType constraint) {
3858+
assert(!(constraint->isAny() || constraint->isAnyObject()) &&
3859+
"Any(Object) may not apppear as canonical constraint type");
3860+
assert(!constraint->is<ExistentialMetatypeType>() &&
3861+
"Existential metatype may not apppear as canonical constraint type");
3862+
return CanExistentialType(
3863+
ExistentialType::get(constraint)->castTo<ExistentialType>());
3864+
}
3865+
38573866
CanPrimaryArchetypeType
38583867
PrimaryArchetypeType::getNew(const ASTContext &Ctx,
38593868
GenericEnvironment *GenericEnv,

lib/SIL/IR/AbstractionPattern.cpp

+87
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,44 @@ 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+
if (!origPPT)
1759+
return CanType(ppt);
1760+
1761+
for (unsigned i = 0; i < ppt->getArgs().size(); ++i) {
1762+
auto argTy = ppt->getArgs()[i];
1763+
auto origArgTy = AbstractionPattern(pattern.getGenericSignatureOrNull(),
1764+
origPPT.getArgs()[i]);
1765+
auto substEltTy = visit(argTy, origArgTy);
1766+
substArgs.push_back(substEltTy);
1767+
}
1768+
1769+
return CanType(ParameterizedProtocolType::get(
1770+
TC.Context, ppt->getBaseType(), substArgs));
1771+
}
1772+
16861773
CanType visitTupleType(TupleType *tuple, AbstractionPattern pattern) {
16871774
if (auto gp = handleTypeParameterInAbstractionPattern(pattern, tuple))
16881775
return gp;

lib/SIL/IR/TypeLowering.cpp

+41
Original file line numberDiff line numberDiff line change
@@ -2500,6 +2500,47 @@ 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+
if (!origPPT)
2523+
return substPPT;
2524+
2525+
for (auto i : indices(substPPT.getArgs())) {
2526+
auto origArgTy = AbstractionPattern(
2527+
origConstraint.getGenericSignatureOrNull(), origPPT.getArgs()[i]);
2528+
auto substArgType = substPPT.getArgs()[i];
2529+
2530+
CanType loweredSubstEltType =
2531+
TC.getLoweredRValueType(forExpansion, origArgTy, substArgType);
2532+
changed = changed || substArgType != loweredSubstEltType;
2533+
2534+
loweredSubstArgs.push_back(loweredSubstEltType);
2535+
}
2536+
2537+
if (!changed)
2538+
return substPPT;
2539+
2540+
return CanParameterizedProtocolType::get(
2541+
TC.Context, substPPT->getBaseType(), loweredSubstArgs);
2542+
}
2543+
25032544
CanType visitPackType(CanPackType substPackType) {
25042545
llvm_unreachable("");
25052546
}

test/SILGen/parameterized_existentials.swift

+10
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)