@@ -1318,6 +1318,18 @@ class OpenTypeSequenceElements {
1318
1318
};
1319
1319
}
1320
1320
1321
+ namespace {
1322
+ /// Flags that should be applied to the existential argument type after
1323
+ /// opening.
1324
+ enum class OpenedExistentialAdjustmentFlags {
1325
+ /// The argument should be made inout after opening.
1326
+ InOut = 0x01,
1327
+ };
1328
+
1329
+ using OpenedExistentialAdjustments =
1330
+ OptionSet<OpenedExistentialAdjustmentFlags>;
1331
+ }
1332
+
1321
1333
/// Determine whether we should open up the existential argument to the
1322
1334
/// given parameters.
1323
1335
///
@@ -1330,9 +1342,11 @@ class OpenTypeSequenceElements {
1330
1342
///
1331
1343
/// \returns If the argument type is existential and opening it can bind a
1332
1344
/// generic parameter in the callee, returns the type variable (from the
1333
- /// opened parameter type) and the existential type that needs to be opened
1334
- /// (from the argument type).
1335
- static Optional<std::pair<TypeVariableType *, Type>>
1345
+ /// opened parameter type) the existential type that needs to be opened
1346
+ /// (from the argument type), and the adjustements that need to be applied to
1347
+ /// the existential type after it is opened.
1348
+ static Optional<
1349
+ std::tuple<TypeVariableType *, Type, OpenedExistentialAdjustments>>
1336
1350
shouldOpenExistentialCallArgument(
1337
1351
ValueDecl *callee, unsigned paramIdx, Type paramTy, Type argTy) {
1338
1352
if (!callee)
@@ -1368,6 +1382,14 @@ shouldOpenExistentialCallArgument(
1368
1382
if (!paramTy->hasTypeVariable())
1369
1383
return None;
1370
1384
1385
+ OpenedExistentialAdjustments adjustments;
1386
+
1387
+ // If the argument is inout, strip it off and we can add it back.
1388
+ if (auto inOutArg = argTy->getAs<InOutType>()) {
1389
+ argTy = inOutArg->getObjectType();
1390
+ adjustments |= OpenedExistentialAdjustmentFlags::InOut;
1391
+ }
1392
+
1371
1393
// The argument type needs to be an existential type or metatype thereof.
1372
1394
if (!argTy->isAnyExistentialType())
1373
1395
return None;
@@ -1380,14 +1402,19 @@ shouldOpenExistentialCallArgument(
1380
1402
if (param->isVariadic() && !param->getVarargBaseTy()->hasTypeSequence())
1381
1403
return None;
1382
1404
1405
+ // Look through an inout type on the formal type of the parameter.
1406
+ auto formalParamTy = param->getInterfaceType()->getInOutObjectType();
1407
+
1383
1408
// If the argument is of an existential metatype, look through the
1384
1409
// metatype on the parameter.
1385
- auto formalParamTy = param->getInterfaceType();
1386
1410
if (argTy->is<AnyMetatypeType>()) {
1387
1411
formalParamTy = formalParamTy->getMetatypeInstanceType();
1388
1412
paramTy = paramTy->getMetatypeInstanceType();
1389
1413
}
1390
1414
1415
+ // Look through an inout type on the parameter.
1416
+ paramTy = paramTy->getInOutObjectType();
1417
+
1391
1418
// The parameter type must be a type variable.
1392
1419
auto paramTypeVar = paramTy->getAs<TypeVariableType>();
1393
1420
if (!paramTypeVar)
@@ -1418,7 +1445,7 @@ shouldOpenExistentialCallArgument(
1418
1445
referenceInfo.assocTypeRef > TypePosition::Covariant)
1419
1446
return None;
1420
1447
1421
- return std::make_pair (paramTypeVar, argTy);
1448
+ return std::make_tuple (paramTypeVar, argTy, adjustments );
1422
1449
}
1423
1450
1424
1451
// Match the argument of a call to the parameter.
@@ -1657,12 +1684,20 @@ static ConstraintSystem::TypeMatchResult matchCallArguments(
1657
1684
// consider opening the existential type.
1658
1685
if (auto existentialArg = shouldOpenExistentialCallArgument(
1659
1686
callee, paramIdx, paramTy, argTy)) {
1660
- assert(existentialArg->second->isEqual(argTy));
1687
+ // My kingdom for a decent "if let" in C++.
1688
+ TypeVariableType *openedTypeVar;
1689
+ Type existentialType;
1690
+ OpenedExistentialAdjustments adjustments;
1691
+ std::tie(openedTypeVar, existentialType, adjustments) = *existentialArg;
1692
+
1661
1693
OpenedArchetypeType *opened;
1662
1694
std::tie(argTy, opened) = cs.openExistentialType(
1663
- argTy, cs.getConstraintLocator(loc));
1695
+ existentialType, cs.getConstraintLocator(loc));
1696
+
1697
+ if (adjustments.contains(OpenedExistentialAdjustmentFlags::InOut))
1698
+ argTy = InOutType::get(argTy);
1664
1699
1665
- openedExistentials.push_back({existentialArg->first , opened});
1700
+ openedExistentials.push_back({openedTypeVar , opened});
1666
1701
}
1667
1702
1668
1703
auto argLabel = argument.getLabel();
0 commit comments