Skip to content

Commit f4bea5f

Browse files
authored
Merge pull request swiftlang#77203 from hamishknight/wrapping-paper-sema
[Sema] Avoid relying on ParenType in a couple of places
2 parents 98c538a + b9646da commit f4bea5f

File tree

4 files changed

+114
-102
lines changed

4 files changed

+114
-102
lines changed

include/swift/AST/Decl.h

+4
Original file line numberDiff line numberDiff line change
@@ -8547,6 +8547,10 @@ class EnumElementDecl : public DeclContext, public ValueDecl {
85478547
/// associated values, or null if there are no associated values.
85488548
Type getPayloadInterfaceType() const;
85498549

8550+
/// Retrieve the parameters of the implicit case constructor for the enum
8551+
/// element.
8552+
ArrayRef<AnyFunctionType::Param> getCaseConstructorParams() const;
8553+
85508554
void setParameterList(ParameterList *params);
85518555
ParameterList *getParameterList() const { return Params; }
85528556

lib/AST/Decl.cpp

+17-7
Original file line numberDiff line numberDiff line change
@@ -10733,22 +10733,32 @@ SourceRange EnumElementDecl::getSourceRange() const {
1073310733
return {getStartLoc(), getNameLoc()};
1073410734
}
1073510735

10736-
Type EnumElementDecl::getPayloadInterfaceType() const {
10736+
ArrayRef<AnyFunctionType::Param>
10737+
EnumElementDecl::getCaseConstructorParams() const {
1073710738
if (!hasAssociatedValues())
10738-
return nullptr;
10739+
return {};
1073910740

1074010741
auto interfaceType = getInterfaceType();
10741-
if (interfaceType->is<ErrorType>()) {
10742-
return interfaceType;
10743-
}
10742+
if (interfaceType->is<ErrorType>())
10743+
return {};
1074410744

1074510745
auto funcTy = interfaceType->castTo<AnyFunctionType>();
10746-
funcTy = funcTy->getResult()->castTo<FunctionType>();
10746+
return funcTy->getResult()->castTo<FunctionType>()->getParams();
10747+
}
10748+
10749+
Type EnumElementDecl::getPayloadInterfaceType() const {
10750+
if (!hasAssociatedValues())
10751+
return Type();
10752+
10753+
auto interfaceType = getInterfaceType();
10754+
if (interfaceType->is<ErrorType>())
10755+
return interfaceType;
1074710756

1074810757
// The payload type of an enum is an imploded tuple of the internal arguments
1074910758
// of the case constructor. As such, compose a tuple type with the parameter
1075010759
// flags dropped.
10751-
return AnyFunctionType::composeTuple(getASTContext(), funcTy->getParams(),
10760+
return AnyFunctionType::composeTuple(getASTContext(),
10761+
getCaseConstructorParams(),
1075210762
ParameterFlagHandling::IgnoreNonEmpty);
1075310763
}
1075410764

lib/Sema/TypeCheckPattern.cpp

+62-54
Original file line numberDiff line numberDiff line change
@@ -942,64 +942,72 @@ void repairTupleOrAssociatedValuePatternIfApplicable(
942942
Type enumPayloadType,
943943
const EnumElementDecl *enumCase) {
944944
auto &DE = Ctx.Diags;
945-
bool addDeclNote = false;
946-
if (auto *tupleType = dyn_cast<TupleType>(enumPayloadType.getPointer())) {
947-
if (tupleType->getNumElements() >= 2
948-
&& enumElementInnerPat->getKind() == PatternKind::Paren) {
949-
auto *semantic = enumElementInnerPat->getSemanticsProvidingPattern();
950-
if (auto *tuplePattern = dyn_cast<TuplePattern>(semantic)) {
951-
if (tuplePattern->getNumElements() >= 2) {
952-
auto diag = DE.diagnose(tuplePattern->getLoc(),
953-
diag::converting_tuple_into_several_associated_values,
954-
enumCase->getNameStr(), tupleType->getNumElements());
955-
auto subPattern =
956-
dyn_cast<ParenPattern>(enumElementInnerPat)->getSubPattern();
957-
958-
// We might also have code like
959-
//
960-
// enum Upair { case upair(Int, Int) }
961-
// func f(u: Upair) { switch u { case .upair(let (x, y)): () } }
962-
//
963-
// This needs a more complex rearrangement to fix the code. So only
964-
// apply the fix-it if we have a tuple immediately inside.
965-
if (subPattern->getKind() == PatternKind::Tuple) {
966-
auto leadingParen = SourceRange(enumElementInnerPat->getStartLoc());
967-
auto trailingParen = SourceRange(enumElementInnerPat->getEndLoc());
968-
diag.fixItRemove(leadingParen)
969-
.fixItRemove(trailingParen);
970-
}
971-
972-
addDeclNote = true;
973-
enumElementInnerPat = semantic;
974-
}
975-
} else {
976-
DE.diagnose(enumElementInnerPat->getLoc(),
977-
diag::found_one_pattern_for_several_associated_values,
978-
enumCase->getNameStr(),
979-
tupleType->getNumElements());
980-
addDeclNote = true;
981-
}
982-
}
983-
} else if (auto *tupleType = enumPayloadType->getAs<TupleType>()) {
984-
if (tupleType->getNumElements() >= 2) {
985-
if (auto *tuplePattern = dyn_cast<TuplePattern>(enumElementInnerPat)) {
986-
DE.diagnose(enumElementInnerPat->getLoc(),
987-
diag::converting_several_associated_values_into_tuple,
988-
enumCase->getNameStr(),
989-
tupleType->getNumElements())
990-
.fixItInsert(enumElementInnerPat->getStartLoc(), "(")
991-
.fixItInsertAfter(enumElementInnerPat->getEndLoc(), ")");
992-
addDeclNote = true;
993-
enumElementInnerPat =
994-
new (Ctx) ParenPattern(enumElementInnerPat->getStartLoc(),
995-
enumElementInnerPat,
996-
enumElementInnerPat->getEndLoc());
945+
auto addDeclNote = [&]() {
946+
DE.diagnose(enumCase->getStartLoc(), diag::decl_declared_here, enumCase);
947+
};
948+
auto payloadParams = enumCase->getCaseConstructorParams();
949+
950+
// First check to see whether we need to untuple a pattern.
951+
if (payloadParams.size() >= 2) {
952+
if (enumElementInnerPat->getKind() != PatternKind::Paren)
953+
return;
954+
955+
auto *semantic = enumElementInnerPat->getSemanticsProvidingPattern();
956+
if (auto *tuplePattern = dyn_cast<TuplePattern>(semantic)) {
957+
if (tuplePattern->getNumElements() < 2)
958+
return;
959+
960+
auto diag =
961+
DE.diagnose(tuplePattern->getLoc(),
962+
diag::converting_tuple_into_several_associated_values,
963+
enumCase->getNameStr(), payloadParams.size());
964+
auto subPattern =
965+
dyn_cast<ParenPattern>(enumElementInnerPat)->getSubPattern();
966+
967+
// We might also have code like
968+
//
969+
// enum Upair { case upair(Int, Int) }
970+
// func f(u: Upair) { switch u { case .upair(let (x, y)): () } }
971+
//
972+
// This needs a more complex rearrangement to fix the code. So only
973+
// apply the fix-it if we have a tuple immediately inside.
974+
if (subPattern->getKind() == PatternKind::Tuple) {
975+
auto leadingParen = SourceRange(enumElementInnerPat->getStartLoc());
976+
auto trailingParen = SourceRange(enumElementInnerPat->getEndLoc());
977+
diag.fixItRemove(leadingParen).fixItRemove(trailingParen);
997978
}
979+
diag.flush();
980+
addDeclNote();
981+
enumElementInnerPat = semantic;
982+
} else {
983+
DE.diagnose(enumElementInnerPat->getLoc(),
984+
diag::found_one_pattern_for_several_associated_values,
985+
enumCase->getNameStr(), payloadParams.size());
986+
addDeclNote();
998987
}
988+
return;
999989
}
1000990

1001-
if (addDeclNote)
1002-
DE.diagnose(enumCase->getStartLoc(), diag::decl_declared_here, enumCase);
991+
// Then check to see whether we need to tuple a pattern.
992+
if (payloadParams.size() == 1 && !payloadParams[0].hasLabel()) {
993+
auto *tupleType = enumPayloadType->getAs<TupleType>();
994+
if (!tupleType || tupleType->getNumElements() < 2)
995+
return;
996+
997+
auto *tuplePattern = dyn_cast<TuplePattern>(enumElementInnerPat);
998+
if (!tuplePattern)
999+
return;
1000+
1001+
DE.diagnose(enumElementInnerPat->getLoc(),
1002+
diag::converting_several_associated_values_into_tuple,
1003+
enumCase->getNameStr(), tupleType->getNumElements())
1004+
.fixItInsert(enumElementInnerPat->getStartLoc(), "(")
1005+
.fixItInsertAfter(enumElementInnerPat->getEndLoc(), ")");
1006+
addDeclNote();
1007+
enumElementInnerPat = new (Ctx)
1008+
ParenPattern(enumElementInnerPat->getStartLoc(), enumElementInnerPat,
1009+
enumElementInnerPat->getEndLoc());
1010+
}
10031011
}
10041012

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

lib/Sema/TypeCheckSwitchStmt.cpp

+31-41
Original file line numberDiff line numberDiff line change
@@ -785,28 +785,11 @@ namespace {
785785
}
786786
}
787787

788-
/// Use this if you're doing getAs<TupleType> on a Type (and it succeeds)
789-
/// to compute the spaces for it. Handy for disambiguating fields
790-
/// that are tuples from associated values.
791-
///
792-
/// .e((a: X, b: X)) -> ((a: X, b: X))
793-
/// vs .f(a: X, b: X) -> (a: X, b: X)
794-
static void getTupleTypeSpaces(Type &outerType,
795-
TupleType *tty,
788+
/// Splat a tuple type into a set of element type spaces.
789+
static void getTupleTypeSpaces(TupleType *tty,
796790
SmallVectorImpl<Space> &spaces) {
797-
ArrayRef<TupleTypeElt> ttyElts = tty->getElements();
798-
if (isa<ParenType>(outerType.getPointer())) {
799-
// We had an actual tuple!
800-
SmallVector<Space, 4> innerSpaces;
801-
for (auto &elt: ttyElts)
802-
innerSpaces.push_back(Space::forType(elt.getType(), elt.getName()));
803-
spaces.push_back(
804-
Space::forConstructor(tty, Identifier(), innerSpaces));
805-
} else {
806-
// We're looking at the fields of a constructor here.
807-
for (auto &elt: ttyElts)
808-
spaces.push_back(Space::forType(elt.getType(), elt.getName()));
809-
}
791+
for (auto &elt : tty->getElements())
792+
spaces.push_back(Space::forType(elt.getType(), elt.getName()));
810793
};
811794

812795
// Decompose a type into its component spaces, ignoring any enum
@@ -843,19 +826,29 @@ namespace {
843826
return Space();
844827
}
845828

846-
// .e(a: X, b: X) -> (a: X, b: X)
847-
// .f((a: X, b: X)) -> ((a: X, b: X)
848829
SmallVector<Space, 4> constElemSpaces;
849-
if (auto payloadTy = eed->getPayloadInterfaceType()) {
850-
auto eedTy = tp->getCanonicalType()->getTypeOfMember(
851-
eed, payloadTy);
852-
if (auto *TTy = eedTy->getAs<TupleType>()) {
853-
Space::getTupleTypeSpaces(eedTy, TTy, constElemSpaces);
854-
} else if (auto *TTy =
855-
dyn_cast<ParenType>(eedTy.getPointer())) {
856-
constElemSpaces.push_back(
857-
Space::forType(TTy->getUnderlyingType(), Identifier()));
830+
auto params = eed->getCaseConstructorParams();
831+
auto isParenLike = params.size() == 1 && !params[0].hasLabel();
832+
833+
// .e(a: X, b: X) -> (a: X, b: X)
834+
// .f((a: X, b: X)) -> ((a: X, b: X))
835+
for (auto &param : params) {
836+
auto payloadTy = tp->getCanonicalType()->getTypeOfMember(
837+
eed, param.getParameterType());
838+
// A single tuple payload gets splatted into a constructor
839+
// space of its constituent elements. This allows the
840+
// deprecated ability to match using a .x(a, b, c) pattern
841+
// instead of a .x((a, b, c)) pattern.
842+
auto *tupleTy = payloadTy->getAs<TupleType>();
843+
if (tupleTy && isParenLike) {
844+
SmallVector<Space, 4> innerSpaces;
845+
Space::getTupleTypeSpaces(tupleTy, innerSpaces);
846+
constElemSpaces.push_back(Space::forConstructor(
847+
tupleTy, Identifier(), innerSpaces));
848+
continue;
858849
}
850+
constElemSpaces.push_back(
851+
Space::forType(payloadTy, param.getLabel()));
859852
}
860853
return Space::forConstructor(tp, eed->getName(),
861854
constElemSpaces);
@@ -870,11 +863,8 @@ namespace {
870863
} else if (auto *TTy = tp->castTo<TupleType>()) {
871864
// Decompose each of the elements into its component type space.
872865
SmallVector<Space, 4> constElemSpaces;
873-
llvm::transform(TTy->getElements(),
874-
std::back_inserter(constElemSpaces),
875-
[&](TupleTypeElt elt) {
876-
return Space::forType(elt.getType(), elt.getName());
877-
});
866+
Space::getTupleTypeSpaces(TTy, constElemSpaces);
867+
878868
// Create an empty constructor head for the tuple space.
879869
arr.push_back(Space::forConstructor(tp, Identifier(),
880870
constElemSpaces));
@@ -1519,12 +1509,12 @@ namespace {
15191509
// matched by a single var pattern. Project it like the tuple it
15201510
// really is.
15211511
//
1522-
// FIXME: SE-0155 makes this case unreachable.
1512+
// FIXME: SE-0155 will eventually this case unreachable. For now it's
1513+
// permitted as a deprecated behavior.
15231514
if (SP->getKind() == PatternKind::Named
15241515
|| SP->getKind() == PatternKind::Any) {
1525-
Type outerType = SP->getType();
1526-
if (auto *TTy = outerType->getAs<TupleType>())
1527-
Space::getTupleTypeSpaces(outerType, TTy, conArgSpace);
1516+
if (auto *TTy = SP->getType()->getAs<TupleType>())
1517+
Space::getTupleTypeSpaces(TTy, conArgSpace);
15281518
else
15291519
conArgSpace.push_back(projectPattern(SP));
15301520
} else if (SP->getKind() == PatternKind::Tuple) {

0 commit comments

Comments
 (0)