@@ -1205,6 +1205,24 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
1205
1205
case PatternKind::Tuple: {
1206
1206
TuplePattern *TP = cast<TuplePattern>(P);
1207
1207
1208
+ // Allow optional promotion only for pattern matching, not pattern binding.
1209
+ const bool allowOptionalPromotion = !pattern.getPatternBindingDecl ();
1210
+
1211
+ // If optional promotion is allowed and the coercion type is optional,
1212
+ // pretend we are in the context of an enum case payload.
1213
+ if (allowOptionalPromotion && type->isOptional ()) {
1214
+ subOptions.setContext (TypeResolverContext::EnumPatternPayload);
1215
+ subOptions |= TypeResolutionFlags::FromNonInferredPattern;
1216
+ }
1217
+
1218
+ const auto origTy = type;
1219
+ if (allowOptionalPromotion) {
1220
+ // Strip the coercion type of optionality. If the coercion succeeds, we
1221
+ // will promote the resulting pattern to the original type by wrapping it
1222
+ // in 'OptionalSome' patterns.
1223
+ type = type->lookThroughAllOptionalTypes ();
1224
+ }
1225
+
1208
1226
TupleType *tupleTy = type->getAs <TupleType>();
1209
1227
1210
1228
// Sometimes a paren is just a paren. If the tuple pattern has a single
@@ -1277,6 +1295,21 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
1277
1295
P->setType (type);
1278
1296
}
1279
1297
1298
+ if (allowOptionalPromotion) {
1299
+ // If the original coercion type is optional, promote the resulting
1300
+ // pattern to match the optionality.
1301
+ if (auto wrappedTy = origTy->getOptionalObjectType ()) {
1302
+ do {
1303
+ auto *OSP =
1304
+ OptionalSomePattern::createImplicit (Context, P, P->getEndLoc ());
1305
+ OSP->setType (OptionalType::get (P->getType ()));
1306
+ OSP->setImplicit ();
1307
+ P = OSP;
1308
+ wrappedTy = wrappedTy->getOptionalObjectType ();
1309
+ } while (wrappedTy);
1310
+ }
1311
+ }
1312
+
1280
1313
return P;
1281
1314
}
1282
1315
@@ -1561,10 +1594,12 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
1561
1594
}
1562
1595
}
1563
1596
1597
+ Type elementType;
1598
+ Pattern *sub = EEP->getSubPattern ();
1599
+
1564
1600
// If there is a subpattern, push the enum element type down onto it.
1565
1601
auto argType = elt->getArgumentInterfaceType ();
1566
- if (EEP->hasSubPattern ()) {
1567
- Pattern *sub = EEP->getSubPattern ();
1602
+ if (sub) {
1568
1603
if (!elt->hasAssociatedValues ()) {
1569
1604
diags.diagnose (EEP->getLoc (),
1570
1605
diag::enum_element_pattern_assoc_values_mismatch,
@@ -1574,33 +1609,21 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
1574
1609
.fixItRemove (sub->getSourceRange ());
1575
1610
return nullptr ;
1576
1611
}
1577
-
1578
- Type elementType;
1612
+
1579
1613
if (argType)
1580
1614
elementType = enumTy->getTypeOfMember (elt->getModuleContext (),
1581
1615
elt, argType);
1582
1616
else
1583
1617
elementType = TupleType::getEmpty (Context);
1584
- auto newSubOptions = subOptions;
1585
- newSubOptions.setContext (TypeResolverContext::EnumPatternPayload);
1586
- newSubOptions |= TypeResolutionFlags::FromNonInferredPattern;
1587
1618
1588
1619
::repairTupleOrAssociatedValuePatternIfApplicable (
1589
1620
Context, sub, elementType, elt);
1590
-
1591
- sub = coercePatternToType (
1592
- pattern.forSubPattern (sub, /* retainTopLevel=*/ false ), elementType,
1593
- newSubOptions);
1594
- if (!sub)
1595
- return nullptr ;
1596
-
1597
- EEP->setSubPattern (sub);
1598
1621
} else if (argType) {
1599
1622
// Else if the element pattern has no sub-pattern but the element type has
1600
1623
// associated values, expand it to be semantically equivalent to an
1601
1624
// element pattern of wildcards.
1602
- Type elementType = enumTy-> getTypeOfMember (elt-> getModuleContext (),
1603
- elt, argType);
1625
+ elementType =
1626
+ enumTy-> getTypeOfMember (elt-> getModuleContext (), elt, argType);
1604
1627
SmallVector<TuplePatternElt, 8 > elements;
1605
1628
if (auto *TTy = dyn_cast<TupleType>(elementType.getPointer ())) {
1606
1629
for (auto &elt : TTy->getElements ()) {
@@ -1617,17 +1640,34 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
1617
1640
elements.push_back (TuplePatternElt (Identifier (), SourceLoc (),
1618
1641
subPattern));
1619
1642
}
1620
- Pattern * sub = TuplePattern::createSimple (Context, SourceLoc (),
1621
- elements, SourceLoc ());
1643
+ sub = TuplePattern::createSimple (Context, SourceLoc (), elements ,
1644
+ SourceLoc ());
1622
1645
sub->setImplicit ();
1646
+ }
1647
+
1648
+ if (sub) {
1623
1649
auto newSubOptions = subOptions;
1624
1650
newSubOptions.setContext (TypeResolverContext::EnumPatternPayload);
1625
1651
newSubOptions |= TypeResolutionFlags::FromNonInferredPattern;
1652
+
1626
1653
sub = coercePatternToType (
1627
1654
pattern.forSubPattern (sub, /* retainTopLevel=*/ false ), elementType,
1628
1655
newSubOptions);
1629
1656
if (!sub)
1630
1657
return nullptr ;
1658
+
1659
+ // If we are left with an optional pattern rather than a paren or tuple
1660
+ // pattern, then we must have optional-promoted a splatted tuple, e.g.
1661
+ // 'let .a(x, y)' → 'let .a((x, y)?)' for 'case a((X, Y)?)'.
1662
+ //
1663
+ // Wrap it in an implicit paren pattern to meet structural expectations
1664
+ // about the subpattern of an enum element pattern.
1665
+ if (isa<OptionalSomePattern>(sub)) {
1666
+ assert (sub->isImplicit ());
1667
+
1668
+ sub = ParenPattern::createImplicit (Context, sub);
1669
+ }
1670
+
1631
1671
EEP->setSubPattern (sub);
1632
1672
}
1633
1673
0 commit comments