Skip to content

Commit 0d10a45

Browse files
committed
[Sema] Refactor repairTupleOrAssociatedValuePatternIfApplicable
Avoid relying on the modeling of single unlabeled associated values as ParenType, instead check the case constructor parameters. Also refactor to early return in more cases.
1 parent 81b8b0c commit 0d10a45

File tree

1 file changed

+62
-54
lines changed

1 file changed

+62
-54
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -983,64 +983,72 @@ void repairTupleOrAssociatedValuePatternIfApplicable(
983983
Type enumPayloadType,
984984
const EnumElementDecl *enumCase) {
985985
auto &DE = Ctx.Diags;
986-
bool addDeclNote = false;
987-
if (auto *tupleType = dyn_cast<TupleType>(enumPayloadType.getPointer())) {
988-
if (tupleType->getNumElements() >= 2
989-
&& enumElementInnerPat->getKind() == PatternKind::Paren) {
990-
auto *semantic = enumElementInnerPat->getSemanticsProvidingPattern();
991-
if (auto *tuplePattern = dyn_cast<TuplePattern>(semantic)) {
992-
if (tuplePattern->getNumElements() >= 2) {
993-
auto diag = DE.diagnose(tuplePattern->getLoc(),
994-
diag::converting_tuple_into_several_associated_values,
995-
enumCase->getNameStr(), tupleType->getNumElements());
996-
auto subPattern =
997-
dyn_cast<ParenPattern>(enumElementInnerPat)->getSubPattern();
998-
999-
// We might also have code like
1000-
//
1001-
// enum Upair { case upair(Int, Int) }
1002-
// func f(u: Upair) { switch u { case .upair(let (x, y)): () } }
1003-
//
1004-
// This needs a more complex rearrangement to fix the code. So only
1005-
// apply the fix-it if we have a tuple immediately inside.
1006-
if (subPattern->getKind() == PatternKind::Tuple) {
1007-
auto leadingParen = SourceRange(enumElementInnerPat->getStartLoc());
1008-
auto trailingParen = SourceRange(enumElementInnerPat->getEndLoc());
1009-
diag.fixItRemove(leadingParen)
1010-
.fixItRemove(trailingParen);
1011-
}
1012-
1013-
addDeclNote = true;
1014-
enumElementInnerPat = semantic;
1015-
}
1016-
} else {
1017-
DE.diagnose(enumElementInnerPat->getLoc(),
1018-
diag::found_one_pattern_for_several_associated_values,
1019-
enumCase->getNameStr(),
1020-
tupleType->getNumElements());
1021-
addDeclNote = true;
1022-
}
1023-
}
1024-
} else if (auto *tupleType = enumPayloadType->getAs<TupleType>()) {
1025-
if (tupleType->getNumElements() >= 2) {
1026-
if (auto *tuplePattern = dyn_cast<TuplePattern>(enumElementInnerPat)) {
1027-
DE.diagnose(enumElementInnerPat->getLoc(),
1028-
diag::converting_several_associated_values_into_tuple,
1029-
enumCase->getNameStr(),
1030-
tupleType->getNumElements())
1031-
.fixItInsert(enumElementInnerPat->getStartLoc(), "(")
1032-
.fixItInsertAfter(enumElementInnerPat->getEndLoc(), ")");
1033-
addDeclNote = true;
1034-
enumElementInnerPat =
1035-
new (Ctx) ParenPattern(enumElementInnerPat->getStartLoc(),
1036-
enumElementInnerPat,
1037-
enumElementInnerPat->getEndLoc());
986+
auto addDeclNote = [&]() {
987+
DE.diagnose(enumCase->getStartLoc(), diag::decl_declared_here, enumCase);
988+
};
989+
auto payloadParams = enumCase->getCaseConstructorParams();
990+
991+
// First check to see whether we need to untuple a pattern.
992+
if (payloadParams.size() >= 2) {
993+
if (enumElementInnerPat->getKind() != PatternKind::Paren)
994+
return;
995+
996+
auto *semantic = enumElementInnerPat->getSemanticsProvidingPattern();
997+
if (auto *tuplePattern = dyn_cast<TuplePattern>(semantic)) {
998+
if (tuplePattern->getNumElements() < 2)
999+
return;
1000+
1001+
auto diag =
1002+
DE.diagnose(tuplePattern->getLoc(),
1003+
diag::converting_tuple_into_several_associated_values,
1004+
enumCase->getNameStr(), payloadParams.size());
1005+
auto subPattern =
1006+
dyn_cast<ParenPattern>(enumElementInnerPat)->getSubPattern();
1007+
1008+
// We might also have code like
1009+
//
1010+
// enum Upair { case upair(Int, Int) }
1011+
// func f(u: Upair) { switch u { case .upair(let (x, y)): () } }
1012+
//
1013+
// This needs a more complex rearrangement to fix the code. So only
1014+
// apply the fix-it if we have a tuple immediately inside.
1015+
if (subPattern->getKind() == PatternKind::Tuple) {
1016+
auto leadingParen = SourceRange(enumElementInnerPat->getStartLoc());
1017+
auto trailingParen = SourceRange(enumElementInnerPat->getEndLoc());
1018+
diag.fixItRemove(leadingParen).fixItRemove(trailingParen);
10381019
}
1020+
diag.flush();
1021+
addDeclNote();
1022+
enumElementInnerPat = semantic;
1023+
} else {
1024+
DE.diagnose(enumElementInnerPat->getLoc(),
1025+
diag::found_one_pattern_for_several_associated_values,
1026+
enumCase->getNameStr(), payloadParams.size());
1027+
addDeclNote();
10391028
}
1029+
return;
10401030
}
10411031

1042-
if (addDeclNote)
1043-
DE.diagnose(enumCase->getStartLoc(), diag::decl_declared_here, enumCase);
1032+
// Then check to see whether we need to tuple a pattern.
1033+
if (payloadParams.size() == 1 && !payloadParams[0].hasLabel()) {
1034+
auto *tupleType = enumPayloadType->getAs<TupleType>();
1035+
if (!tupleType || tupleType->getNumElements() < 2)
1036+
return;
1037+
1038+
auto *tuplePattern = dyn_cast<TuplePattern>(enumElementInnerPat);
1039+
if (!tuplePattern)
1040+
return;
1041+
1042+
DE.diagnose(enumElementInnerPat->getLoc(),
1043+
diag::converting_several_associated_values_into_tuple,
1044+
enumCase->getNameStr(), tupleType->getNumElements())
1045+
.fixItInsert(enumElementInnerPat->getStartLoc(), "(")
1046+
.fixItInsertAfter(enumElementInnerPat->getEndLoc(), ")");
1047+
addDeclNote();
1048+
enumElementInnerPat = new (Ctx)
1049+
ParenPattern(enumElementInnerPat->getStartLoc(), enumElementInnerPat,
1050+
enumElementInnerPat->getEndLoc());
1051+
}
10441052
}
10451053

10461054
NullablePtr<Pattern> TypeChecker::trySimplifyExprPattern(ExprPattern *EP,

0 commit comments

Comments
 (0)