[Constraint System] Fix covariant erasure for constrained existentials

Constrained existentials should be type erased to an upper bound that is dependent on other type parameters.
This commit is contained in:
Angela Laar
2023-03-30 14:55:47 -07:00
parent 61ea49c840
commit 5c818b3fd4
9 changed files with 223 additions and 22 deletions

View File

@@ -2054,9 +2054,9 @@ static bool isMainDispatchQueueMember(ConstraintLocator *locator) {
/// \note If a 'Self'-rooted type parameter is bound to a concrete type, this
/// routine will recurse into the concrete type.
static Type
typeEraseExistentialSelfReferences(
Type refTy, Type baseTy,
TypePosition outermostPosition) {
typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
TypePosition outermostPosition,
bool wantNonDependentBound = true) {
assert(baseTy->isExistentialType());
if (!refTy->hasTypeParameter()) {
return refTy;
@@ -2159,7 +2159,9 @@ typeEraseExistentialSelfReferences(
if (t->is<GenericTypeParamType>()) {
erasedTy = baseTy;
} else {
erasedTy = existentialSig->getNonDependentUpperBounds(t);
erasedTy = wantNonDependentBound
? existentialSig->getNonDependentUpperBounds(t)
: existentialSig->getDependentUpperBounds(t);
}
if (metatypeDepth) {
@@ -2170,13 +2172,12 @@ typeEraseExistentialSelfReferences(
return erasedTy;
});
};
return transformFn(refTy, outermostPosition);
}
Type constraints::typeEraseOpenedExistentialReference(
Type type, Type existentialBaseType, TypeVariableType *openedTypeVar,
TypePosition outermostPosition) {
TypePosition outermostPosition, bool wantNonDependentBound) {
Type selfGP = GenericTypeParamType::get(false, 0, 0, type->getASTContext());
// First, temporarily reconstitute the 'Self' generic parameter.
@@ -2193,8 +2194,8 @@ Type constraints::typeEraseOpenedExistentialReference(
});
// Then, type-erase occurrences of covariant 'Self'-rooted type parameters.
type = typeEraseExistentialSelfReferences(type, existentialBaseType,
outermostPosition);
type = typeEraseExistentialSelfReferences(
type, existentialBaseType, outermostPosition, wantNonDependentBound);
// Finally, swap the 'Self'-corresponding type variable back in.
return type.transformRec([&](TypeBase *t) -> Optional<Type> {
@@ -2299,16 +2300,25 @@ Type ConstraintSystem::getMemberReferenceTypeFromOpenedType(
const auto selfGP = cast<GenericTypeParamType>(
outerDC->getSelfInterfaceType()->getCanonicalType());
auto openedTypeVar = replacements.lookup(selfGP);
type = typeEraseOpenedExistentialReference(type, baseObjTy, openedTypeVar,
TypePosition::Covariant);
Type contextualTy;
if (auto *anchor = getAsExpr(simplifyLocatorToAnchor(locator))) {
contextualTy =
getContextualType(getParentExpr(anchor), /*forConstraint=*/false);
}
if (!hasFixFor(locator) &&
AddExplicitExistentialCoercion::isRequired(
*this, nonErasedResultTy,
[&](TypeVariableType *typeVar) {
return openedTypeVar == typeVar ? baseObjTy : Optional<Type>();
},
locator)) {
locator) &&
!contextualTy) {
recordFix(AddExplicitExistentialCoercion::create(
*this, getResultType(type), locator));
}