@@ -1432,12 +1432,13 @@ namespace {
14321432/// \param argTy The type of the argument.
14331433///
14341434/// \returns If the argument type is existential and opening it can bind a
1435- /// generic parameter in the callee, returns the type variable (from the
1436- /// opened parameter type) the existential type that needs to be opened
1437- /// (from the argument type), and the adjustements that need to be applied to
1438- /// the existential type after it is opened.
1435+ /// generic parameter in the callee, returns the generic parameter, type
1436+ /// variable (from the opened parameter type) the existential type that needs
1437+ /// to be opened (from the argument type), and the adjustements that need to be
1438+ /// applied to the existential type after it is opened.
14391439static Optional<
1440- std::tuple<TypeVariableType *, Type, OpenedExistentialAdjustments>>
1440+ std::tuple<GenericTypeParamType *, TypeVariableType *, Type,
1441+ OpenedExistentialAdjustments>>
14411442shouldOpenExistentialCallArgument(
14421443 ValueDecl *callee, unsigned paramIdx, Type paramTy, Type argTy,
14431444 Expr *argExpr, ConstraintSystem &cs) {
@@ -1551,7 +1552,7 @@ shouldOpenExistentialCallArgument(
15511552 referenceInfo.assocTypeRef > TypePosition::Covariant)
15521553 return None;
15531554
1554- return std::make_tuple(paramTypeVar, argTy, adjustments);
1555+ return std::make_tuple(genericParam, paramTypeVar, argTy, adjustments);
15551556}
15561557
15571558// Match the argument of a call to the parameter.
@@ -1831,15 +1832,29 @@ static ConstraintSystem::TypeMatchResult matchCallArguments(
18311832 cs, cs.getConstraintLocator(loc)));
18321833 }
18331834
1835+ // Type-erase any opened existentials from subsequent parameter types
1836+ // unless the argument itself is a generic function, which could handle
1837+ // the opened existentials.
1838+ if (!openedExistentials.empty() && paramTy->hasTypeVariable() &&
1839+ !cs.isArgumentGenericFunction(argTy, argExpr)) {
1840+ for (const auto &opened : openedExistentials) {
1841+ paramTy = typeEraseOpenedExistentialReference(
1842+ paramTy, opened.second->getExistentialType(), opened.first,
1843+ /*FIXME*/cs.DC, TypePosition::Contravariant);
1844+ }
1845+ }
1846+
18341847 // If the argument is an existential type and the parameter is generic,
18351848 // consider opening the existential type.
18361849 if (auto existentialArg = shouldOpenExistentialCallArgument(
18371850 callee, paramIdx, paramTy, argTy, argExpr, cs)) {
18381851 // My kingdom for a decent "if let" in C++.
1852+ GenericTypeParamType *openedGenericParam;
18391853 TypeVariableType *openedTypeVar;
18401854 Type existentialType;
18411855 OpenedExistentialAdjustments adjustments;
1842- std::tie(openedTypeVar, existentialType, adjustments) = *existentialArg;
1856+ std::tie(openedGenericParam, openedTypeVar, existentialType,
1857+ adjustments) = *existentialArg;
18431858
18441859 OpenedArchetypeType *opened;
18451860 std::tie(argTy, opened) = cs.openExistentialType(
@@ -11327,7 +11342,8 @@ ConstraintSystem::simplifyApplicableFnConstraint(
1132711342 if (result2->hasTypeVariable() && !openedExistentials.empty()) {
1132811343 for (const auto &opened : openedExistentials) {
1132911344 result2 = typeEraseOpenedExistentialReference(
11330- result2, opened.second->getExistentialType(), opened.first, DC);
11345+ result2, opened.second->getExistentialType(), opened.first, DC,
11346+ TypePosition::Covariant);
1133111347 }
1133211348 }
1133311349
0 commit comments