Skip to content

Commit 339e40f

Browse files
committed
Fixed an assert caused when a TupleExpr that didn't have a valid SourceRange had a valid SourceLoc for the first element but not for the last
1 parent d9fe1d0 commit 339e40f

File tree

3 files changed

+68
-12
lines changed

3 files changed

+68
-12
lines changed

include/swift/AST/Expr.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,8 +2055,7 @@ class TupleExpr final : public Expr,
20552055
SourceLoc getLParenLoc() const { return LParenLoc; }
20562056
SourceLoc getRParenLoc() const { return RParenLoc; }
20572057

2058-
SourceLoc getStartLoc() const;
2059-
SourceLoc getEndLoc() const;
2058+
SourceRange getSourceRange() const;
20602059

20612060
/// \brief Whether this expression has a trailing closure as its argument.
20622061
bool hasTrailingClosure() const { return TupleExprBits.HasTrailingClosure; }

lib/AST/Expr.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,18 +1314,32 @@ SequenceExpr *SequenceExpr::create(ASTContext &ctx, ArrayRef<Expr*> elements) {
13141314
return ::new(Buffer) SequenceExpr(elements);
13151315
}
13161316

1317-
SourceLoc TupleExpr::getStartLoc() const {
1318-
if (LParenLoc.isValid()) return LParenLoc;
1319-
if (getNumElements() == 0) return SourceLoc();
1320-
return getElement(0)->getStartLoc();
1321-
}
1322-
1323-
SourceLoc TupleExpr::getEndLoc() const {
1317+
SourceRange TupleExpr::getSourceRange() const {
1318+
SourceLoc start = SourceLoc();
1319+
SourceLoc end = SourceLoc();
1320+
if (LParenLoc.isValid()) {
1321+
start = LParenLoc;
1322+
} else if (getNumElements() == 0) {
1323+
return { SourceLoc(), SourceLoc() };
1324+
} else {
1325+
start = getElement(0)->getStartLoc();
1326+
}
1327+
13241328
if (hasTrailingClosure() || RParenLoc.isInvalid()) {
1325-
if (getNumElements() == 0) return SourceLoc();
1326-
return getElements().back()->getEndLoc();
1329+
if (getNumElements() == 0) {
1330+
return { SourceLoc(), SourceLoc() };
1331+
} else {
1332+
end = getElements().back()->getEndLoc();
1333+
}
1334+
} else {
1335+
end = RParenLoc;
1336+
}
1337+
1338+
if (start.isValid() && end.isValid()) {
1339+
return { start, end };
1340+
} else {
1341+
return { SourceLoc(), SourceLoc() };
13271342
}
1328-
return RParenLoc;
13291343
}
13301344

13311345
TupleExpr::TupleExpr(SourceLoc LParenLoc, ArrayRef<Expr *> SubExprs,

unittests/AST/SourceLocTests.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,46 @@ TEST(SourceLoc, AssignExpr) {
100100
EXPECT_EQ(SourceLoc(), invalidAll->getEndLoc());
101101
EXPECT_EQ(SourceRange(), invalidAll->getSourceRange());
102102
}
103+
104+
TEST(SourceLoc, TupleExpr) {
105+
TestContext C;
106+
107+
// In a TupleExpr, if the parens are both invalid, then you can only have a
108+
// valid range iff both the first element and last element have valid ranges.
109+
// Source ranges also have the property:
110+
// Start.isValid() == End.isValid()
111+
// For example, given the buffer "one", of the form:
112+
// (tuple_expr
113+
// (declref_expr range=[test.swift:1:0 - line:1:2] ...)
114+
// (declref_expr range=invalid ...))
115+
// the range of this TupleExpr is SourceLoc() (invalid).
116+
// v invalid v invalid
117+
// ( one, two )
118+
// valid ^ invalid ^
119+
// COL: xxxxxx012xxxxxxxxxxxxxxxxx
120+
// but the SourceRange of 'one' is 1:0 - 1:2.
121+
122+
// 012
123+
auto bufferID = C.Ctx.SourceMgr.addMemBufferCopy("one");
124+
SourceLoc start = C.Ctx.SourceMgr.getLocForBufferStart(bufferID);
125+
126+
auto one = new (C.Ctx) UnresolvedDeclRefExpr(
127+
C.Ctx.getIdentifier("one"),
128+
DeclRefKind::Ordinary,
129+
DeclNameLoc(start));
130+
131+
auto two = new (C.Ctx) UnresolvedDeclRefExpr(
132+
C.Ctx.getIdentifier("two"),
133+
DeclRefKind::Ordinary,
134+
DeclNameLoc());
135+
136+
// the tuple from the example
137+
SmallVector<Expr *, 2> SubExprs({ one, two });
138+
SmallVector<Identifier, 2> SubExprNames(2, Identifier());
139+
auto exampleTuple = TupleExpr::createImplicit(C.Ctx, SubExprs, SubExprNames);
140+
141+
EXPECT_EQ(start, one->getStartLoc());
142+
EXPECT_EQ(SourceLoc(), exampleTuple->getStartLoc());
143+
EXPECT_EQ(SourceLoc(), exampleTuple->getEndLoc());
144+
EXPECT_EQ(SourceRange(), exampleTuple->getSourceRange());
145+
}

0 commit comments

Comments
 (0)