Skip to content

Commit 3c8921a

Browse files
committed
[Sema] Avoid relying on ParenType in space engine
Refactor `decomposeDisjuncts` to avoid relying on the modeling of single unlabeled associated values as ParenTypes.
1 parent 512e6b3 commit 3c8921a

File tree

3 files changed

+52
-48
lines changed

3 files changed

+52
-48
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
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

Lines changed: 17 additions & 7 deletions
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/TypeCheckSwitchStmt.cpp

Lines changed: 31 additions & 41 deletions
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)