Skip to content

Commit d958c0e

Browse files
committed
[AST] Introduce Expr::isAlwaysLeftFolded
Use this to query for `try`-like expressions when it comes to binary operator folding.
1 parent bf2d01e commit d958c0e

File tree

3 files changed

+49
-19
lines changed

3 files changed

+49
-19
lines changed

include/swift/AST/Expr.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,22 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
456456
return const_cast<Expr *>(this)->getValueProvidingExpr();
457457
}
458458

459+
/// Checks whether this expression is always hoisted above a binary operator
460+
/// when it appears on the left-hand side, e.g 'try x + y' becomes
461+
/// 'try (x + y)'. If so, returns the sub-expression, \c nullptr otherwise.
462+
///
463+
/// Note that such expressions may not appear on the right-hand side of a
464+
/// binary operator, except for assignment and ternaries.
465+
Expr *getAlwaysLeftFoldedSubExpr() const;
466+
467+
/// Checks whether this expression is always hoisted above a binary operator
468+
/// when it appears on the left-hand side, e.g 'try x + y' becomes
469+
/// 'try (x + y)'.
470+
///
471+
/// Note that such expressions may not appear on the right-hand side of a
472+
/// binary operator, except for assignment and ternaries.
473+
bool isAlwaysLeftFolded() const { return bool(getAlwaysLeftFoldedSubExpr()); }
474+
459475
/// Find the original expression value, looking through various
460476
/// implicit conversions.
461477
const Expr *findOriginalValue() const;

lib/AST/Expr.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3017,6 +3017,17 @@ FrontendStatsTracer::getTraceFormatter<const Expr *>() {
30173017
return &TF;
30183018
}
30193019

3020+
Expr *Expr::getAlwaysLeftFoldedSubExpr() const {
3021+
if (auto *ATE = dyn_cast<AnyTryExpr>(this))
3022+
return ATE->getSubExpr();
3023+
if (auto *AE = dyn_cast<AwaitExpr>(this))
3024+
return AE->getSubExpr();
3025+
if (auto *UE = dyn_cast<UnsafeExpr>(this))
3026+
return UE->getSubExpr();
3027+
3028+
return nullptr;
3029+
}
3030+
30203031
const Expr *Expr::findOriginalValue() const {
30213032
auto *expr = this;
30223033
do {

lib/Sema/TypeCheckExpr.cpp

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -198,25 +198,28 @@ static Expr *makeBinOp(ASTContext &Ctx, Expr *Op, Expr *LHS, Expr *RHS,
198198

199199
// If the left-hand-side is a 'try', 'await', or 'unsafe', hoist it up
200200
// turning "(try x) + y" into try (x + y).
201-
if (auto *tryEval = dyn_cast<AnyTryExpr>(LHS)) {
202-
auto sub = makeBinOp(Ctx, Op, tryEval->getSubExpr(), RHS,
203-
opPrecedence, isEndOfSequence);
204-
tryEval->setSubExpr(sub);
205-
return tryEval;
206-
}
207-
208-
if (auto *await = dyn_cast<AwaitExpr>(LHS)) {
209-
auto sub = makeBinOp(Ctx, Op, await->getSubExpr(), RHS,
210-
opPrecedence, isEndOfSequence);
211-
await->setSubExpr(sub);
212-
return await;
213-
}
201+
if (LHS->isAlwaysLeftFolded()) {
202+
if (auto *tryEval = dyn_cast<AnyTryExpr>(LHS)) {
203+
auto sub = makeBinOp(Ctx, Op, tryEval->getSubExpr(), RHS, opPrecedence,
204+
isEndOfSequence);
205+
tryEval->setSubExpr(sub);
206+
return tryEval;
207+
}
214208

215-
if (auto *unsafe = dyn_cast<UnsafeExpr>(LHS)) {
216-
auto sub = makeBinOp(Ctx, Op, unsafe->getSubExpr(), RHS,
217-
opPrecedence, isEndOfSequence);
218-
unsafe->setSubExpr(sub);
219-
return unsafe;
209+
if (auto *await = dyn_cast<AwaitExpr>(LHS)) {
210+
auto sub = makeBinOp(Ctx, Op, await->getSubExpr(), RHS, opPrecedence,
211+
isEndOfSequence);
212+
await->setSubExpr(sub);
213+
return await;
214+
}
215+
216+
if (auto *unsafe = dyn_cast<UnsafeExpr>(LHS)) {
217+
auto sub = makeBinOp(Ctx, Op, unsafe->getSubExpr(), RHS, opPrecedence,
218+
isEndOfSequence);
219+
unsafe->setSubExpr(sub);
220+
return unsafe;
221+
}
222+
llvm_unreachable("Unhandled left-folded case!");
220223
}
221224

222225
// If the right operand is a try, await, or unsafe, it's an error unless
@@ -235,7 +238,7 @@ static Expr *makeBinOp(ASTContext &Ctx, Expr *Op, Expr *LHS, Expr *RHS,
235238
// x ? try foo() : try bar() $#! 1
236239
// assuming $#! is some crazy operator with lower precedence
237240
// than the conditional operator.
238-
if (isa<AnyTryExpr>(RHS) || isa<AwaitExpr>(RHS) || isa<UnsafeExpr>(RHS)) {
241+
if (RHS->isAlwaysLeftFolded()) {
239242
// If you change this, also change TRY_KIND_SELECT in diagnostics.
240243
enum class TryKindForDiagnostics : unsigned {
241244
Try,

0 commit comments

Comments
 (0)