Skip to content

Commit 4ec627e

Browse files
authored
Merge pull request #69551 from DougGregor/thrown-error-try-opt-bang
Record the thrown error type for try? and try! in the AST
2 parents 05271d3 + c90c055 commit 4ec627e

File tree

6 files changed

+53
-6
lines changed

6 files changed

+53
-6
lines changed

include/swift/AST/Expr.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,6 +1918,7 @@ class TryExpr : public AnyTryExpr {
19181918
/// should dynamically assert if it does.
19191919
class ForceTryExpr final : public AnyTryExpr {
19201920
SourceLoc ExclaimLoc;
1921+
Type thrownError;
19211922

19221923
public:
19231924
ForceTryExpr(SourceLoc tryLoc, Expr *sub, SourceLoc exclaimLoc,
@@ -1927,6 +1928,15 @@ class ForceTryExpr final : public AnyTryExpr {
19271928

19281929
SourceLoc getExclaimLoc() const { return ExclaimLoc; }
19291930

1931+
/// Retrieve the type of the error thrown from the subexpression.
1932+
Type getThrownError() const { return thrownError; }
1933+
1934+
/// Set the type of the error thrown from the subexpression.
1935+
void setThrownError(Type type) {
1936+
assert(!thrownError || thrownError->isEqual(type));
1937+
thrownError = type;
1938+
}
1939+
19301940
static bool classof(const Expr *e) {
19311941
return e->getKind() == ExprKind::ForceTry;
19321942
}
@@ -1937,6 +1947,7 @@ class ForceTryExpr final : public AnyTryExpr {
19371947
/// Optional. If the code does throw, \c nil is produced.
19381948
class OptionalTryExpr final : public AnyTryExpr {
19391949
SourceLoc QuestionLoc;
1950+
Type thrownError;
19401951

19411952
public:
19421953
OptionalTryExpr(SourceLoc tryLoc, Expr *sub, SourceLoc questionLoc,
@@ -1946,6 +1957,15 @@ class OptionalTryExpr final : public AnyTryExpr {
19461957

19471958
SourceLoc getQuestionLoc() const { return QuestionLoc; }
19481959

1960+
/// Retrieve the type of the error thrown from the subexpression.
1961+
Type getThrownError() const { return thrownError; }
1962+
1963+
/// Set the type of the error thrown from the subexpression.
1964+
void setThrownError(Type type) {
1965+
assert(!thrownError || thrownError->isEqual(type));
1966+
thrownError = type;
1967+
}
1968+
19491969
static bool classof(const Expr *e) {
19501970
return e->getKind() == ExprKind::OptionalTry;
19511971
}

lib/AST/ASTDumper.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,12 +2690,22 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
26902690

26912691
void visitForceTryExpr(ForceTryExpr *E, StringRef label) {
26922692
printCommon(E, "force_try_expr", label);
2693+
2694+
PrintOptions PO;
2695+
PO.PrintTypesForDebugging = true;
2696+
printFieldQuoted(E->getThrownError().getString(PO), "thrown_error", TypeColor);
2697+
26932698
printRec(E->getSubExpr());
26942699
printFoot();
26952700
}
26962701

26972702
void visitOptionalTryExpr(OptionalTryExpr *E, StringRef label) {
26982703
printCommon(E, "optional_try_expr", label);
2704+
2705+
PrintOptions PO;
2706+
PO.PrintTypesForDebugging = true;
2707+
printFieldQuoted(E->getThrownError().getString(PO), "thrown_error", TypeColor);
2708+
26992709
printRec(E->getSubExpr());
27002710
printFoot();
27012711
}

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8892,7 +8892,8 @@ static Expr *wrapAsyncLetInitializer(
88928892
ConstraintSystem &cs, Expr *initializer, DeclContext *dc) {
88938893
// Form the autoclosure type. It is always 'async', and will be 'throws'.
88948894
Type initializerType = initializer->getType();
8895-
bool throws = TypeChecker::canThrow(cs.getASTContext(), initializer);
8895+
bool throws = TypeChecker::canThrow(cs.getASTContext(), initializer)
8896+
.has_value();
88968897
auto extInfo = ASTExtInfoBuilder()
88978898
.withAsync()
88988899
.withConcurrent()

lib/Sema/TypeCheckEffects.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3102,6 +3102,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
31023102
if (!Flags.has(ContextFlags::HasTryThrowSite))
31033103
diagnoseRedundantTry(E);
31043104

3105+
if (auto thrownError = TypeChecker::canThrow(Ctx, E->getSubExpr())) {
3106+
E->setThrownError(*thrownError);
3107+
}
3108+
31053109
scope.preserveCoverageFromOptionalOrForcedTryOperand();
31063110
return ShouldNotRecurse;
31073111
}
@@ -3117,6 +3121,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
31173121
if (!Flags.has(ContextFlags::HasTryThrowSite))
31183122
diagnoseRedundantTry(E);
31193123

3124+
if (auto thrownError = TypeChecker::canThrow(Ctx, E->getSubExpr())) {
3125+
E->setThrownError(*thrownError);
3126+
}
3127+
31203128
scope.preserveCoverageFromOptionalOrForcedTryOperand();
31213129
return ShouldNotRecurse;
31223130
}
@@ -3351,11 +3359,14 @@ void TypeChecker::checkPropertyWrapperEffects(
33513359
expr->walk(LocalFunctionEffectsChecker());
33523360
}
33533361

3354-
bool TypeChecker::canThrow(ASTContext &ctx, Expr *expr) {
3362+
llvm::Optional<Type> TypeChecker::canThrow(ASTContext &ctx, Expr *expr) {
33553363
ApplyClassifier classifier(ctx);
33563364
auto classification = classifier.classifyExpr(expr, EffectKind::Throws);
3357-
return classification.getConditionalKind(EffectKind::Throws) !=
3358-
ConditionalEffectKind::None;
3365+
if (classification.getConditionalKind(EffectKind::Throws) ==
3366+
ConditionalEffectKind::None)
3367+
return llvm::None;
3368+
3369+
return classification.getThrownError();
33593370
}
33603371

33613372
Type TypeChecker::catchErrorType(ASTContext &ctx, DoCatchStmt *stmt) {

lib/Sema/TypeChecker.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,8 +1175,8 @@ void checkInitializerEffects(Initializer *I, Expr *E);
11751175
void checkEnumElementEffects(EnumElementDecl *D, Expr *expr);
11761176
void checkPropertyWrapperEffects(PatternBindingDecl *binding, Expr *expr);
11771177

1178-
/// Whether the given expression can throw.
1179-
bool canThrow(ASTContext &ctx, Expr *expr);
1178+
/// Whether the given expression can throw, and if so, the thrown type.
1179+
llvm::Optional<Type> canThrow(ASTContext &ctx, Expr *expr);
11801180

11811181
/// Determine the error type that is thrown out of the body of the given
11821182
/// do-catch statement.

test/stmt/typed_throws_ast.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@ func throwsAnything() throws {
3131
// swallow this error
3232
_ = e
3333
} // implicit rethrow
34+
35+
// CHECK: force_try_expr{{.*}}thrown_error="MyError"
36+
try! printOrFail("boom")
37+
// CHECK: optional_try_expr{{.*}}thrown_error="MyError"
38+
try? printOrFail("ssshhhhh")
3439
}

0 commit comments

Comments
 (0)