Skip to content

Commit 2bfd9ee

Browse files
committed
Sema: Optional-promote tuple patterns during solution application
1 parent 400fdb8 commit 2bfd9ee

File tree

1 file changed

+59
-19
lines changed

1 file changed

+59
-19
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,24 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
12051205
case PatternKind::Tuple: {
12061206
TuplePattern *TP = cast<TuplePattern>(P);
12071207

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+
12081226
TupleType *tupleTy = type->getAs<TupleType>();
12091227

12101228
// Sometimes a paren is just a paren. If the tuple pattern has a single
@@ -1277,6 +1295,21 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
12771295
P->setType(type);
12781296
}
12791297

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+
12801313
return P;
12811314
}
12821315

@@ -1561,10 +1594,12 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
15611594
}
15621595
}
15631596

1597+
Type elementType;
1598+
Pattern *sub = EEP->getSubPattern();
1599+
15641600
// If there is a subpattern, push the enum element type down onto it.
15651601
auto argType = elt->getArgumentInterfaceType();
1566-
if (EEP->hasSubPattern()) {
1567-
Pattern *sub = EEP->getSubPattern();
1602+
if (sub) {
15681603
if (!elt->hasAssociatedValues()) {
15691604
diags.diagnose(EEP->getLoc(),
15701605
diag::enum_element_pattern_assoc_values_mismatch,
@@ -1574,33 +1609,21 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
15741609
.fixItRemove(sub->getSourceRange());
15751610
return nullptr;
15761611
}
1577-
1578-
Type elementType;
1612+
15791613
if (argType)
15801614
elementType = enumTy->getTypeOfMember(elt->getModuleContext(),
15811615
elt, argType);
15821616
else
15831617
elementType = TupleType::getEmpty(Context);
1584-
auto newSubOptions = subOptions;
1585-
newSubOptions.setContext(TypeResolverContext::EnumPatternPayload);
1586-
newSubOptions |= TypeResolutionFlags::FromNonInferredPattern;
15871618

15881619
::repairTupleOrAssociatedValuePatternIfApplicable(
15891620
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);
15981621
} else if (argType) {
15991622
// Else if the element pattern has no sub-pattern but the element type has
16001623
// associated values, expand it to be semantically equivalent to an
16011624
// element pattern of wildcards.
1602-
Type elementType = enumTy->getTypeOfMember(elt->getModuleContext(),
1603-
elt, argType);
1625+
elementType =
1626+
enumTy->getTypeOfMember(elt->getModuleContext(), elt, argType);
16041627
SmallVector<TuplePatternElt, 8> elements;
16051628
if (auto *TTy = dyn_cast<TupleType>(elementType.getPointer())) {
16061629
for (auto &elt : TTy->getElements()) {
@@ -1617,17 +1640,34 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
16171640
elements.push_back(TuplePatternElt(Identifier(), SourceLoc(),
16181641
subPattern));
16191642
}
1620-
Pattern *sub = TuplePattern::createSimple(Context, SourceLoc(),
1621-
elements, SourceLoc());
1643+
sub = TuplePattern::createSimple(Context, SourceLoc(), elements,
1644+
SourceLoc());
16221645
sub->setImplicit();
1646+
}
1647+
1648+
if (sub) {
16231649
auto newSubOptions = subOptions;
16241650
newSubOptions.setContext(TypeResolverContext::EnumPatternPayload);
16251651
newSubOptions |= TypeResolutionFlags::FromNonInferredPattern;
1652+
16261653
sub = coercePatternToType(
16271654
pattern.forSubPattern(sub, /*retainTopLevel=*/false), elementType,
16281655
newSubOptions);
16291656
if (!sub)
16301657
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+
16311671
EEP->setSubPattern(sub);
16321672
}
16331673

0 commit comments

Comments
 (0)