Skip to content

Commit fb8a51b

Browse files
authored
Merge pull request #69376 from DougGregor/record-thrown-error-conversions-in-ast
[Typed throws] Record thrown error types and conversions in the AST
2 parents 8381f01 + 5ad39c8 commit fb8a51b

19 files changed

+334
-75
lines changed

include/swift/AST/Expr.h

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "swift/AST/FreestandingMacroExpansion.h"
2929
#include "swift/AST/FunctionRefKind.h"
3030
#include "swift/AST/ProtocolConformanceRef.h"
31+
#include "swift/AST/ThrownErrorDestination.h"
3132
#include "swift/AST/TypeAlignments.h"
3233
#include "swift/Basic/Debug.h"
3334
#include "swift/Basic/InlineBitfield.h"
@@ -324,9 +325,8 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
324325
NumCaptures : 32
325326
);
326327

327-
SWIFT_INLINE_BITFIELD(ApplyExpr, Expr, 1+1+1+1+1+1+1,
328+
SWIFT_INLINE_BITFIELD(ApplyExpr, Expr, 1+1+1+1+1,
328329
ThrowsIsSet : 1,
329-
Throws : 1,
330330
ImplicitlyAsync : 1,
331331
ImplicitlyThrows : 1,
332332
NoAsync : 1,
@@ -1180,6 +1180,11 @@ class DeclRefExpr : public Expr {
11801180
DeclNameLoc Loc;
11811181
ActorIsolation implicitActorHopTarget;
11821182

1183+
/// Destination information for a thrown error, which includes any
1184+
/// necessary conversions from the actual type thrown to the type that
1185+
/// is expected by the enclosing context.
1186+
ThrownErrorDestination ThrowDest;
1187+
11831188
public:
11841189
DeclRefExpr(ConcreteDeclRef D, DeclNameLoc Loc, bool Implicit,
11851190
AccessSemantics semantics = AccessSemantics::Ordinary,
@@ -1230,6 +1235,14 @@ class DeclRefExpr : public Expr {
12301235
return Bits.DeclRefExpr.IsImplicitlyThrows;
12311236
}
12321237

1238+
/// The error thrown from this access.
1239+
ThrownErrorDestination throws() const { return ThrowDest; }
1240+
1241+
void setThrows(ThrownErrorDestination throws) {
1242+
assert(!ThrowDest);
1243+
ThrowDest = throws;
1244+
}
1245+
12331246
/// Set whether this reference must account for a `throw` occurring for reasons
12341247
/// other than the function implementation itself throwing, e.g. an
12351248
/// `DistributedActorSystem` implementing a `distributed func` call throwing a
@@ -1562,6 +1575,11 @@ class LookupExpr : public Expr {
15621575
assert(Base);
15631576
}
15641577

1578+
/// Destination information for a thrown error, which includes any
1579+
/// necessary conversions from the actual type thrown to the type that
1580+
/// is expected by the enclosing context.
1581+
ThrownErrorDestination ThrowDest;
1582+
15651583
public:
15661584
/// Retrieve the base of the expression.
15671585
Expr *getBase() const { return Base; }
@@ -1603,6 +1621,14 @@ class LookupExpr : public Expr {
16031621
implicitActorHopTarget = target;
16041622
}
16051623

1624+
/// The error thrown from this access.
1625+
ThrownErrorDestination throws() const { return ThrowDest; }
1626+
1627+
void setThrows(ThrownErrorDestination throws) {
1628+
assert(!ThrowDest);
1629+
ThrowDest = throws;
1630+
}
1631+
16061632
/// Determine whether this reference needs may implicitly throw.
16071633
///
16081634
/// This is the case for non-throwing `distributed func` declarations,
@@ -4627,6 +4653,11 @@ class ApplyExpr : public Expr {
46274653
// isolations in this struct.
46284654
llvm::Optional<ApplyIsolationCrossing> IsolationCrossing;
46294655

4656+
/// Destination information for a thrown error, which includes any
4657+
/// necessary conversions from the actual type thrown to the type that
4658+
/// is expected by the enclosing context.
4659+
ThrownErrorDestination ThrowDest;
4660+
46304661
protected:
46314662
ApplyExpr(ExprKind kind, Expr *fn, ArgumentList *argList, bool implicit,
46324663
Type ty = Type())
@@ -4656,16 +4687,18 @@ class ApplyExpr : public Expr {
46564687
/// Does this application throw? This is only meaningful after
46574688
/// complete type-checking.
46584689
///
4659-
/// If true, the function expression must have a throwing function
4660-
/// type. The converse is not true because of 'rethrows' functions.
4661-
bool throws() const {
4690+
/// Returns the thrown error destination, which includes both the type
4691+
/// thrown from this application as well as the the context's error type,
4692+
/// which may be different.
4693+
ThrownErrorDestination throws() const {
46624694
assert(Bits.ApplyExpr.ThrowsIsSet);
4663-
return Bits.ApplyExpr.Throws;
4695+
return ThrowDest;
46644696
}
4665-
void setThrows(bool throws) {
4697+
4698+
void setThrows(ThrownErrorDestination throws) {
46664699
assert(!Bits.ApplyExpr.ThrowsIsSet);
46674700
Bits.ApplyExpr.ThrowsIsSet = true;
4668-
Bits.ApplyExpr.Throws = throws;
4701+
ThrowDest = throws;
46694702
}
46704703

46714704
/// Is this a 'rethrows' function that is known not to throw?

include/swift/AST/Stmt.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/AST/ConcreteDeclRef.h"
2525
#include "swift/AST/IfConfigClause.h"
2626
#include "swift/AST/TypeAlignments.h"
27+
#include "swift/AST/ThrownErrorDestination.h"
2728
#include "swift/Basic/Debug.h"
2829
#include "swift/Basic/NullablePtr.h"
2930
#include "llvm/ADT/None.h"
@@ -1383,6 +1384,7 @@ class DoCatchStmt final
13831384

13841385
SourceLoc DoLoc;
13851386
Stmt *Body;
1387+
ThrownErrorDestination RethrowDest;
13861388

13871389
DoCatchStmt(LabeledStmtInfo labelInfo, SourceLoc doLoc, Stmt *body,
13881390
ArrayRef<CaseStmt *> catches, llvm::Optional<bool> implicit)
@@ -1433,6 +1435,15 @@ class DoCatchStmt final
14331435
// rethrown.
14341436
Type getCaughtErrorType() const;
14351437

1438+
/// Retrieves the rethrown error and its conversion to the error type
1439+
/// expected by the enclosing context.
1440+
ThrownErrorDestination rethrows() const { return RethrowDest; }
1441+
1442+
void setRethrows(ThrownErrorDestination rethrows) {
1443+
assert(!RethrowDest);
1444+
RethrowDest = rethrows;
1445+
}
1446+
14361447
static bool classof(const Stmt *S) {
14371448
return S->getKind() == StmtKind::DoCatch;
14381449
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//===--- ThrownErrorDestination.h - Thrown error dest -----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the ThrownErrorDestination class.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_AST_THROWNERRORDESTINATION
18+
#define SWIFT_AST_THROWNERRORDESTINATION
19+
20+
#include "llvm/ADT/Optional.h"
21+
#include "llvm/ADT/PointerUnion.h"
22+
#include "swift/AST/Type.h"
23+
#include "swift/AST/TypeAlignments.h"
24+
25+
namespace swift {
26+
class Expr;
27+
class OpaqueValueExpr;
28+
29+
/// Describes an error thrown from a particular operation and its conversion
30+
/// to the error type expected by its context.
31+
class ThrownErrorDestination {
32+
struct Conversion {
33+
/// The opaque value, which is of the thrown error type.
34+
OpaqueValueExpr *thrownError;
35+
36+
/// The conversion from the opaque value type to the type needed by the
37+
/// context.
38+
Expr *conversion;
39+
};
40+
41+
llvm::PointerUnion<TypeBase *, Conversion *> storage;
42+
43+
ThrownErrorDestination(Type type) : storage(type.getPointer()) { }
44+
ThrownErrorDestination(Conversion *conversion) : storage(conversion) { }
45+
46+
public:
47+
/// Construct a non-throwing destination.
48+
ThrownErrorDestination() : storage(nullptr) { }
49+
50+
/// Construct a non-throwing destination.
51+
ThrownErrorDestination(std::nullptr_t) : storage(nullptr) { }
52+
53+
/// Whether there is a thrown error destination at all.
54+
explicit operator bool() const { return !storage.isNull(); }
55+
56+
/// A thrown error destination where the thrown type corresponds to the
57+
/// type caught (or rethrows) by the enclosing context.
58+
static ThrownErrorDestination forMatchingContextType(Type thrownError) {
59+
return ThrownErrorDestination(thrownError);
60+
}
61+
62+
/// A thrown error destination where the thrown error requires a conversion
63+
/// to the error type expected by its context.
64+
static ThrownErrorDestination forConversion(OpaqueValueExpr *thrownError,
65+
Expr *conversion);
66+
67+
/// Retrieve the type of error thrown from this function call.
68+
Type getThrownErrorType() const;
69+
70+
/// Retrieve the type of the error expected in this context.
71+
Type getContextErrorType() const;
72+
73+
/// Retrieve the conversion as a pair of (opaque thrown error value,
74+
/// conversion expression), when a conversion from the thrown error type
75+
/// to the context error type is required.
76+
llvm::Optional<std::pair<OpaqueValueExpr *, Expr *>> getConversion() const {
77+
if (auto conversion = storage.dyn_cast<Conversion *>()) {
78+
return std::make_pair(conversion->thrownError, conversion->conversion);
79+
}
80+
81+
return llvm::None;
82+
}
83+
};
84+
85+
} // end namespace swift
86+
87+
#endif // SWIFT_AST_THROWNERRORDESTINATION

lib/AST/ASTDumper.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,33 @@ namespace {
893893
printFieldQuotedRaw([&](raw_ostream &OS) { declRef.dump(OS); }, label,
894894
Color);
895895
}
896+
897+
void printThrowDest(ThrownErrorDestination throws, bool wantNothrow) {
898+
if (!throws) {
899+
if (wantNothrow)
900+
printFlag("nothrow", ExprModifierColor);
901+
902+
return;
903+
}
904+
905+
auto thrownError = throws.getThrownErrorType();
906+
auto contextError = throws.getContextErrorType();
907+
if (thrownError->isEqual(contextError)) {
908+
// No translation of the thrown error type is required, so ony print
909+
// the thrown error type.
910+
Type errorExistentialType =
911+
contextError->getASTContext().getErrorExistentialType();
912+
if (errorExistentialType && thrownError->isEqual(errorExistentialType))
913+
printFlag("throws", ExprModifierColor);
914+
else {
915+
printFlag("throws(" + thrownError.getString() + ")", ExprModifierColor);
916+
}
917+
return;
918+
}
919+
920+
printFlag("throws(" + thrownError.getString() + " to " +
921+
contextError.getString() + ")", ExprModifierColor);
922+
}
896923
};
897924

898925
class PrintPattern : public PatternVisitor<PrintPattern, void, StringRef>,
@@ -2021,6 +2048,7 @@ class PrintStmt : public StmtVisitor<PrintStmt, void, StringRef>,
20212048

20222049
void visitDoCatchStmt(DoCatchStmt *S, StringRef label) {
20232050
printCommon(S, "do_catch_stmt", label);
2051+
printThrowDest(S->rethrows(), /*wantNothrow=*/true);
20242052
printRec(S->getBody(), "body");
20252053
printRecRange(S->getCatches(), Ctx, "catch_stmts");
20262054
printFoot();
@@ -2208,6 +2236,7 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
22082236

22092237
void visitDeclRefExpr(DeclRefExpr *E, StringRef label) {
22102238
printCommon(E, "declref_expr", label);
2239+
printThrowDest(E->throws(), /*wantNothrow=*/false);
22112240

22122241
printDeclRefField(E->getDeclRef(), "decl");
22132242
if (E->getAccessSemantics() != AccessSemantics::Ordinary)
@@ -2279,6 +2308,7 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
22792308

22802309
void visitMemberRefExpr(MemberRefExpr *E, StringRef label) {
22812310
printCommon(E, "member_ref_expr", label);
2311+
printThrowDest(E->throws(), /*wantNothrow=*/false);
22822312

22832313
printDeclRefField(E->getMember(), "decl");
22842314
if (E->getAccessSemantics() != AccessSemantics::Ordinary)
@@ -2290,6 +2320,7 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
22902320
}
22912321
void visitDynamicMemberRefExpr(DynamicMemberRefExpr *E, StringRef label) {
22922322
printCommon(E, "dynamic_member_ref_expr", label);
2323+
printThrowDest(E->throws(), /*wantNothrow=*/false);
22932324

22942325
printDeclRefField(E->getMember(), "decl");
22952326

@@ -2389,6 +2420,7 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
23892420
}
23902421
void visitSubscriptExpr(SubscriptExpr *E, StringRef label) {
23912422
printCommon(E, "subscript_expr", label);
2423+
printThrowDest(E->throws(), /*wantNothrow=*/false);
23922424

23932425
if (E->getAccessSemantics() != AccessSemantics::Ordinary)
23942426
printFlag(getDumpString(E->getAccessSemantics()), AccessLevelColor);
@@ -2410,6 +2442,7 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
24102442
}
24112443
void visitDynamicSubscriptExpr(DynamicSubscriptExpr *E, StringRef label) {
24122444
printCommon(E, "dynamic_subscript_expr", label);
2445+
printThrowDest(E->throws(), /*wantNothrow=*/false);
24132446

24142447
printDeclRefField(E->getMember(), "decl");
24152448

@@ -2798,7 +2831,7 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
27982831
void printApplyExpr(ApplyExpr *E, const char *NodeName, StringRef label) {
27992832
printCommon(E, NodeName, label);
28002833
if (E->isThrowsSet()) {
2801-
printFlag(E->throws() ? "throws" : "nothrow", ExprModifierColor);
2834+
printThrowDest(E->throws(), /*wantNothrow=*/true);
28022835
}
28032836
printFieldQuotedRaw([&](raw_ostream &OS) {
28042837
auto isolationCrossing = E->getIsolationCrossing();

lib/AST/Expr.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,3 +2860,36 @@ Type Expr::findOriginalType() const {
28602860

28612861
return expr->getType()->getRValueType();
28622862
}
2863+
2864+
ThrownErrorDestination
2865+
ThrownErrorDestination::forConversion(OpaqueValueExpr *thrownError,
2866+
Expr *conversion) {
2867+
ASTContext &ctx = thrownError->getType()->getASTContext();
2868+
auto conversionStorage = ctx.Allocate<Conversion>();
2869+
conversionStorage->thrownError = thrownError;
2870+
conversionStorage->conversion = conversion;
2871+
2872+
return ThrownErrorDestination(conversionStorage);
2873+
}
2874+
2875+
Type ThrownErrorDestination::getThrownErrorType() const {
2876+
if (!*this)
2877+
return Type();
2878+
2879+
if (auto type = storage.dyn_cast<TypeBase *>())
2880+
return Type(type);
2881+
2882+
auto conversion = storage.get<Conversion *>();
2883+
return conversion->thrownError->getType();
2884+
}
2885+
2886+
Type ThrownErrorDestination::getContextErrorType() const {
2887+
if (!*this)
2888+
return Type();
2889+
2890+
if (auto type = storage.dyn_cast<TypeBase *>())
2891+
return Type(type);
2892+
2893+
auto conversion = storage.get<Conversion *>();
2894+
return conversion->conversion->getType();
2895+
}

0 commit comments

Comments
 (0)