Skip to content

Commit 0a4c029

Browse files
committed
[AST] Introduce UnreachableExpr
This models the conversion from an uninhabited value to any type, and allows us to get rid of a couple of places where we'd attempt to drop the return statement instead.
1 parent 9b64990 commit 0a4c029

File tree

12 files changed

+66
-43
lines changed

12 files changed

+66
-43
lines changed

include/swift/AST/Expr.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3591,6 +3591,22 @@ class ArchetypeToSuperExpr : public ImplicitConversionExpr {
35913591
}
35923592
};
35933593

3594+
/// An expression that models an implicit conversion from an uninhabited value
3595+
/// to any type. It cannot be evaluated.
3596+
class UnreachableExpr : public ImplicitConversionExpr {
3597+
UnreachableExpr(Expr *subExpr, Type ty)
3598+
: ImplicitConversionExpr(ExprKind::Unreachable, subExpr, ty) {}
3599+
3600+
public:
3601+
static UnreachableExpr *create(ASTContext &ctx, Expr *subExpr, Type ty) {
3602+
return new (ctx) UnreachableExpr(subExpr, ty);
3603+
}
3604+
3605+
static bool classof(const Expr *E) {
3606+
return E->getKind() == ExprKind::Unreachable;
3607+
}
3608+
};
3609+
35943610
/// The builtin unary '&' operator, which converts the
35953611
/// given lvalue into an 'inout' argument value.
35963612
class InOutExpr : public Expr {

include/swift/AST/ExprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ ABSTRACT_EXPR(ImplicitConversion, Expr)
183183
EXPR(ForeignObjectConversion, ImplicitConversionExpr)
184184
EXPR(UnevaluatedInstance, ImplicitConversionExpr)
185185
EXPR(UnderlyingToOpaque, ImplicitConversionExpr)
186+
EXPR(Unreachable, ImplicitConversionExpr)
186187
EXPR(DifferentiableFunction, ImplicitConversionExpr)
187188
EXPR(LinearFunction, ImplicitConversionExpr)
188189
EXPR(DifferentiableFunctionExtractOriginal, ImplicitConversionExpr)

lib/AST/ASTDumper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2653,6 +2653,11 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
26532653
printRec(E->getSubExpr());
26542654
printFoot();
26552655
}
2656+
void visitUnreachableExpr(UnreachableExpr *E, StringRef label) {
2657+
printCommon(E, "unreachable", label);
2658+
printRec(E->getSubExpr());
2659+
printFoot();
2660+
}
26562661
void visitDifferentiableFunctionExpr(DifferentiableFunctionExpr *E, StringRef label) {
26572662
printCommon(E, "differentiable_function", label);
26582663
printRec(E->getSubExpr());

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5965,6 +5965,10 @@ void PrintAST::visitPropertyWrapperValuePlaceholderExpr(swift::PropertyWrapperVa
59655965
void PrintAST::visitDifferentiableFunctionExtractOriginalExpr(swift::DifferentiableFunctionExtractOriginalExpr *expr) {
59665966
}
59675967

5968+
void PrintAST::visitUnreachableExpr(UnreachableExpr *E) {
5969+
visit(E->getSubExpr());
5970+
}
5971+
59685972
void PrintAST::visitMacroExpansionExpr(MacroExpansionExpr *expr) {
59695973
}
59705974

lib/AST/ASTVerifier.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,6 +1784,14 @@ class Verifier : public ASTWalker {
17841784
verifyCheckedBase(E);
17851785
}
17861786

1787+
void verifyChecked(UnreachableExpr *E) {
1788+
if (!E->getSubExpr()->getType()->isStructurallyUninhabited()) {
1789+
Out << "UnreachableExpr must have an uninhabited sub-expression: ";
1790+
E->getSubExpr()->dump(Out);
1791+
abort();
1792+
}
1793+
}
1794+
17871795
void verifyChecked(TupleElementExpr *E) {
17881796
PrettyStackTraceExpr debugStack(Ctx, "verifying TupleElementExpr", E);
17891797

lib/AST/Expr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const {
455455
PASS_THROUGH_REFERENCE(BridgeFromObjC, getSubExpr);
456456
PASS_THROUGH_REFERENCE(ConditionalBridgeFromObjC, getSubExpr);
457457
PASS_THROUGH_REFERENCE(UnderlyingToOpaque, getSubExpr);
458+
PASS_THROUGH_REFERENCE(Unreachable, getSubExpr);
458459
NO_REFERENCE(Coerce);
459460
NO_REFERENCE(ForcedCheckedCast);
460461
NO_REFERENCE(ConditionalCheckedCast);
@@ -820,6 +821,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const {
820821
case ExprKind::BridgeFromObjC:
821822
case ExprKind::BridgeToObjC:
822823
case ExprKind::UnderlyingToOpaque:
824+
case ExprKind::Unreachable:
823825
// Implicit conversion nodes have no syntax of their own; defer to the
824826
// subexpression.
825827
return cast<ImplicitConversionExpr>(this)->getSubExpr()
@@ -1000,6 +1002,7 @@ bool Expr::isValidParentOfTypeExpr(Expr *typeExpr) const {
10001002
case ExprKind::ForeignObjectConversion:
10011003
case ExprKind::UnevaluatedInstance:
10021004
case ExprKind::UnderlyingToOpaque:
1005+
case ExprKind::Unreachable:
10031006
case ExprKind::DifferentiableFunction:
10041007
case ExprKind::LinearFunction:
10051008
case ExprKind::DifferentiableFunctionExtractOriginal:

lib/SILGen/SILGenExpr.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ namespace {
499499
RValue visitIsExpr(IsExpr *E, SGFContext C);
500500
RValue visitCoerceExpr(CoerceExpr *E, SGFContext C);
501501
RValue visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E, SGFContext C);
502+
RValue visitUnreachableExpr(UnreachableExpr *E, SGFContext C);
502503
RValue visitTupleExpr(TupleExpr *E, SGFContext C);
503504
RValue visitMemberRefExpr(MemberRefExpr *E, SGFContext C);
504505
RValue visitDynamicMemberRefExpr(DynamicMemberRefExpr *E, SGFContext C);
@@ -2395,6 +2396,22 @@ RValue RValueEmitter::visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E,
23952396
return RValue(SGF, E, cast);
23962397
}
23972398

2399+
RValue RValueEmitter::visitUnreachableExpr(UnreachableExpr *E, SGFContext C) {
2400+
// Emit the expression, followed by an unreachable. To produce a value of
2401+
// arbitrary type, we emit a temporary allocation, with the use of the
2402+
// allocation in the unreachable block. The SILOptimizer will eliminate both
2403+
// the unreachable block and unused allocation.
2404+
SGF.emitIgnoredExpr(E->getSubExpr());
2405+
2406+
auto &lowering = SGF.getTypeLowering(E->getType());
2407+
auto resultAddr = SGF.emitTemporaryAllocation(E, lowering.getLoweredType());
2408+
2409+
SGF.B.createUnreachable(E);
2410+
SGF.B.emitBlock(SGF.createBasicBlock());
2411+
2412+
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr));
2413+
}
2414+
23982415
VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
23992416
CanType baseTy, CanType arrayTy,
24002417
unsigned numElements) {

lib/SILGen/SILGenStmt.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -840,15 +840,6 @@ void StmtEmitter::visitYieldStmt(YieldStmt *S) {
840840
void StmtEmitter::visitThenStmt(ThenStmt *S) {
841841
auto *E = S->getResult();
842842

843-
// If we have an uninhabited type, we may not be able to use it for
844-
// initialization, since we allow the conversion of Never to any other type.
845-
// Instead, emit an ignored expression with an unreachable.
846-
if (E->getType()->isUninhabited()) {
847-
SGF.emitIgnoredExpr(E);
848-
SGF.B.createUnreachable(E);
849-
return;
850-
}
851-
852843
// Retrieve the initialization for the parent SingleValueStmtExpr. If we don't
853844
// have an init, we don't care about the result, emit an ignored expr. This is
854845
// the case if e.g the result is being converted to Void.

lib/Sema/CSApply.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7491,6 +7491,10 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
74917491
break;
74927492
}
74937493

7494+
// Uninhabited types can be coerced to any other type via an UnreachableExpr.
7495+
if (fromType->isUninhabited())
7496+
return cs.cacheType(UnreachableExpr::create(ctx, expr, toType));
7497+
74947498
// "Catch all" coercions.
74957499
auto desugaredToType = toType->getDesugaredType();
74967500
switch (desugaredToType->getKind()) {
@@ -9574,8 +9578,7 @@ ExprWalker::rewriteTarget(SyntacticElementTarget target) {
95749578
if (target.isOptionalSomePatternInit())
95759579
return false;
95769580

9577-
if (solution.getResolvedType(resultExpr)->isUninhabited() ||
9578-
solution.simplifyType(convertType)->isVoid()) {
9581+
if (solution.simplifyType(convertType)->isVoid()) {
95799582
auto contextPurpose = cs.getContextualTypePurpose(target.getAsExpr());
95809583
if (contextPurpose == CTP_ImpliedReturnStmt ||
95819584
contextPurpose == CTP_SingleValueStmtBranch) {

lib/Sema/CSSyntacticElement.cpp

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,23 +2139,18 @@ class SyntacticElementSolutionApplication
21392139

21402140
enum {
21412141
convertToResult,
2142-
coerceToVoid,
2143-
coerceFromNever,
2142+
coerceToVoid
21442143
} mode;
21452144

21462145
auto resultExprType =
21472146
solution.simplifyType(solution.getType(resultExpr))->getRValueType();
21482147
// A closure with a non-void return expression can coerce to a closure
21492148
// that returns Void.
2149+
// TODO: We probably ought to introduce an implicit conversion expr to Void
2150+
// and eliminate this case.
21502151
if (resultType->isVoid() && !resultExprType->isVoid()) {
21512152
mode = coerceToVoid;
21522153

2153-
// A single-expression closure with a Never expression type
2154-
// coerces to any other function type.
2155-
} else if (context.isSingleExpressionClosure(cs) &&
2156-
resultExprType->isUninhabited()) {
2157-
mode = coerceFromNever;
2158-
21592154
// Normal rule is to coerce to the return expression to the closure type.
21602155
} else {
21612156
mode = convertToResult;
@@ -2206,12 +2201,6 @@ class SyntacticElementSolutionApplication
22062201
elements, returnStmt->getEndLoc(),
22072202
/*implicit*/ true);
22082203
}
2209-
2210-
case coerceFromNever:
2211-
// Replace the return statement with its expression, so that the
2212-
// expression is evaluated directly. This only works because coercion
2213-
// from never is limited to single-expression closures.
2214-
return resultExpr;
22152204
}
22162205

22172206
return returnStmt;

0 commit comments

Comments
 (0)