mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Type-erase contravariant uses of opened existentials in subsequent parameters.
When we open an existential argument in a call to a generic function, type-erase contravariant uses of that opened existential in subsequent parameters. This primarily impacts closure parameters, where we want the closure to be provided with an existential parameter type rather than permit the parameter to have opened existential type. This prevents the opened existential type from being directly exposed in the type system. Note that we do not need to perform this erasure when the argument is a reference to a generic function, because there it is suitable to infer that the generic arguments are the opened archetypes. This subsumes the use case for `_openExistential`.
This commit is contained in:
@@ -1432,12 +1432,13 @@ namespace {
|
||||
/// \param argTy The type of the argument.
|
||||
///
|
||||
/// \returns If the argument type is existential and opening it can bind a
|
||||
/// generic parameter in the callee, returns the type variable (from the
|
||||
/// opened parameter type) the existential type that needs to be opened
|
||||
/// (from the argument type), and the adjustements that need to be applied to
|
||||
/// the existential type after it is opened.
|
||||
/// generic parameter in the callee, returns the generic parameter, type
|
||||
/// variable (from the opened parameter type) the existential type that needs
|
||||
/// to be opened (from the argument type), and the adjustements that need to be
|
||||
/// applied to the existential type after it is opened.
|
||||
static Optional<
|
||||
std::tuple<TypeVariableType *, Type, OpenedExistentialAdjustments>>
|
||||
std::tuple<GenericTypeParamType *, TypeVariableType *, Type,
|
||||
OpenedExistentialAdjustments>>
|
||||
shouldOpenExistentialCallArgument(
|
||||
ValueDecl *callee, unsigned paramIdx, Type paramTy, Type argTy,
|
||||
Expr *argExpr, ConstraintSystem &cs) {
|
||||
@@ -1551,7 +1552,7 @@ shouldOpenExistentialCallArgument(
|
||||
referenceInfo.assocTypeRef > TypePosition::Covariant)
|
||||
return None;
|
||||
|
||||
return std::make_tuple(paramTypeVar, argTy, adjustments);
|
||||
return std::make_tuple(genericParam, paramTypeVar, argTy, adjustments);
|
||||
}
|
||||
|
||||
// Match the argument of a call to the parameter.
|
||||
@@ -1831,15 +1832,29 @@ static ConstraintSystem::TypeMatchResult matchCallArguments(
|
||||
cs, cs.getConstraintLocator(loc)));
|
||||
}
|
||||
|
||||
// Type-erase any opened existentials from subsequent parameter types
|
||||
// unless the argument itself is a generic function, which could handle
|
||||
// the opened existentials.
|
||||
if (!openedExistentials.empty() && paramTy->hasTypeVariable() &&
|
||||
!cs.isArgumentGenericFunction(argTy, argExpr)) {
|
||||
for (const auto &opened : openedExistentials) {
|
||||
paramTy = typeEraseOpenedExistentialReference(
|
||||
paramTy, opened.second->getExistentialType(), opened.first,
|
||||
/*FIXME*/cs.DC, TypePosition::Contravariant);
|
||||
}
|
||||
}
|
||||
|
||||
// If the argument is an existential type and the parameter is generic,
|
||||
// consider opening the existential type.
|
||||
if (auto existentialArg = shouldOpenExistentialCallArgument(
|
||||
callee, paramIdx, paramTy, argTy, argExpr, cs)) {
|
||||
// My kingdom for a decent "if let" in C++.
|
||||
GenericTypeParamType *openedGenericParam;
|
||||
TypeVariableType *openedTypeVar;
|
||||
Type existentialType;
|
||||
OpenedExistentialAdjustments adjustments;
|
||||
std::tie(openedTypeVar, existentialType, adjustments) = *existentialArg;
|
||||
std::tie(openedGenericParam, openedTypeVar, existentialType,
|
||||
adjustments) = *existentialArg;
|
||||
|
||||
OpenedArchetypeType *opened;
|
||||
std::tie(argTy, opened) = cs.openExistentialType(
|
||||
@@ -11314,7 +11329,8 @@ ConstraintSystem::simplifyApplicableFnConstraint(
|
||||
if (result2->hasTypeVariable() && !openedExistentials.empty()) {
|
||||
for (const auto &opened : openedExistentials) {
|
||||
result2 = typeEraseOpenedExistentialReference(
|
||||
result2, opened.second->getExistentialType(), opened.first, DC);
|
||||
result2, opened.second->getExistentialType(), opened.first, DC,
|
||||
TypePosition::Covariant);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user