Skip to content

Commit 52d613e

Browse files
committed
Sema: Fix existential member access type erasure around metatypes
The only case a singleton metatype transforms into an existential metatype is when the instance type transforms into an existential from a non-existential.
1 parent eb40cc5 commit 52d613e

File tree

1 file changed

+41
-29
lines changed

1 file changed

+41
-29
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,19 +2208,25 @@ static bool isMainDispatchQueueMember(ConstraintLocator *locator) {
22082208
return true;
22092209
}
22102210

2211-
/// Type-erase occurrences of covariant 'Self'-rooted type parameters to their
2212-
/// most specific upper bounds throughout the given type, using \p baseTy as
2213-
/// the existential base object type.
2211+
/// Transforms `refTy` as follows.
22142212
///
2215-
/// \note If a 'Self'-rooted type parameter is bound to a concrete type, this
2216-
/// routine will recurse into the concrete type.
2217-
static Type typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
2218-
TypePosition outermostPosition,
2219-
GenericSignature existentialSig,
2220-
llvm::function_ref<bool(Type)> containsFn,
2221-
llvm::function_ref<bool(Type)> predicateFn,
2222-
llvm::function_ref<Type(Type)> projectionFn,
2223-
bool force, unsigned metatypeDepth = 0) {
2213+
/// For each occurrence of a type **type** that satisfies `predicateFn` in
2214+
/// covariant position:
2215+
/// 1. **type** is projected to a type parameter using `projectionFn`.
2216+
/// 2. If the type parameter is not bound to a concrete type, it is type-erased
2217+
/// to the most specific upper bounds using `existentialSig` and substituted
2218+
/// for **type**. Otherwise, the concrete type is transformed recursively.
2219+
/// The result is substituted for **type** unless it is an identity
2220+
/// transform.
2221+
///
2222+
/// `baseTy` is used as a ready substitution for the `Self` generic parameter.
2223+
///
2224+
/// @param force If `true`, proceeds regardless of a type's variance position.
2225+
static Type typeEraseExistentialSelfReferences(
2226+
Type refTy, Type baseTy, TypePosition outermostPosition,
2227+
GenericSignature existentialSig, llvm::function_ref<bool(Type)> containsFn,
2228+
llvm::function_ref<bool(Type)> predicateFn,
2229+
llvm::function_ref<Type(Type)> projectionFn, bool force) {
22242230
assert(baseTy->isExistentialType());
22252231
if (!containsFn(refTy))
22262232
return refTy;
@@ -2234,15 +2240,28 @@ static Type typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
22342240

22352241
if (t->is<MetatypeType>()) {
22362242
const auto instanceTy = t->getMetatypeInstanceType();
2237-
const auto erasedTy = typeEraseExistentialSelfReferences(
2243+
auto erasedTy = typeEraseExistentialSelfReferences(
22382244
instanceTy, baseTy, currPos, existentialSig, containsFn,
2239-
predicateFn, projectionFn, force, metatypeDepth + 1);
2240-
2245+
predicateFn, projectionFn, force);
22412246
if (instanceTy.getPointer() == erasedTy.getPointer()) {
22422247
return Type(t);
22432248
}
22442249

2245-
return Type(ExistentialMetatypeType::get(erasedTy));
2250+
// - If the output instance type is an existential, but the input is
2251+
// not, wrap the output in an existential metatype.
2252+
//
2253+
// X.Type → X → any Y → any Y.Type
2254+
//
2255+
// - Otherwise, both are existential or the output instance type is
2256+
// not existential; wrap the output in a singleton metatype.
2257+
if (erasedTy->isAnyExistentialType() &&
2258+
!erasedTy->isConstraintType() &&
2259+
!(instanceTy->isAnyExistentialType() &&
2260+
!instanceTy->isConstraintType())) {
2261+
return Type(ExistentialMetatypeType::get(erasedTy));
2262+
}
2263+
2264+
return Type(MetatypeType::get(erasedTy));
22462265
}
22472266

22482267
// Opaque types whose substitutions involve this type parameter are
@@ -2252,8 +2271,7 @@ static Type typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
22522271
opaque->getSubstitutions().getReplacementTypes()) {
22532272
auto erasedReplacementType = typeEraseExistentialSelfReferences(
22542273
replacementType, baseTy, TypePosition::Covariant,
2255-
existentialSig, containsFn, predicateFn, projectionFn, force,
2256-
metatypeDepth);
2274+
existentialSig, containsFn, predicateFn, projectionFn, force);
22572275
if (erasedReplacementType.getPointer() !=
22582276
replacementType.getPointer())
22592277
return opaque->getExistentialType();
@@ -2266,7 +2284,7 @@ static Type typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
22662284
for (auto argType : parameterized->getArgs()) {
22672285
auto erasedArgType = typeEraseExistentialSelfReferences(
22682286
argType, baseTy, TypePosition::Covariant, existentialSig,
2269-
containsFn, predicateFn, projectionFn, force, metatypeDepth);
2287+
containsFn, predicateFn, projectionFn, force);
22702288
if (erasedArgType.getPointer() != argType.getPointer())
22712289
return parameterized->getBaseType();
22722290
}
@@ -2278,7 +2296,7 @@ static Type typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
22782296
typeEraseExistentialSelfReferences(
22792297
objTy, baseTy, currPos,
22802298
existentialSig, containsFn, predicateFn, projectionFn,
2281-
force, metatypeDepth);
2299+
force);
22822300
22832301
if (erasedTy.getPointer() == objTy.getPointer())
22842302
return Type(lvalue);
@@ -2296,6 +2314,8 @@ static Type typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
22962314
if (!paramTy)
22972315
return Type(t);
22982316

2317+
assert(paramTy->isTypeParameter());
2318+
22992319
// This can happen with invalid code.
23002320
if (!existentialSig->isValidTypeParameter(paramTy)) {
23012321
return Type(t);
@@ -2307,11 +2327,8 @@ static Type typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
23072327
concreteTy, baseTy, currPos, existentialSig,
23082328
[](Type t) { return t->hasTypeParameter(); },
23092329
[](Type t) { return t->isTypeParameter(); },
2310-
[](Type t) { return t; }, force, metatypeDepth);
2330+
[](Type t) { return t; }, force);
23112331
if (erasedTy.getPointer() == concreteTy.getPointer()) {
2312-
// Don't return the concrete type if we haven't type-erased
2313-
// anything inside it, or else we might inadvertently transform a
2314-
// normal metatype into an existential one.
23152332
return Type(t);
23162333
}
23172334

@@ -2339,11 +2356,6 @@ static Type typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
23392356
erasedTy = existentialSig->getExistentialType(paramTy);
23402357
}
23412358

2342-
if (metatypeDepth) {
2343-
if (const auto existential = erasedTy->getAs<ExistentialType>())
2344-
return existential->getConstraintType();
2345-
}
2346-
23472359
return erasedTy;
23482360
});
23492361
}

0 commit comments

Comments
 (0)