Record the thrown error type for try? and try! in the AST

SILGen wants this so it knows what kind of error its going to end up
with.
This commit is contained in:
Doug Gregor
2023-10-31 14:18:31 -07:00
parent d3ede19150
commit c90c055fb6
6 changed files with 53 additions and 6 deletions

View File

@@ -1918,6 +1918,7 @@ public:
/// should dynamically assert if it does.
class ForceTryExpr final : public AnyTryExpr {
SourceLoc ExclaimLoc;
Type thrownError;
public:
ForceTryExpr(SourceLoc tryLoc, Expr *sub, SourceLoc exclaimLoc,
@@ -1927,6 +1928,15 @@ public:
SourceLoc getExclaimLoc() const { return ExclaimLoc; }
/// Retrieve the type of the error thrown from the subexpression.
Type getThrownError() const { return thrownError; }
/// Set the type of the error thrown from the subexpression.
void setThrownError(Type type) {
assert(!thrownError || thrownError->isEqual(type));
thrownError = type;
}
static bool classof(const Expr *e) {
return e->getKind() == ExprKind::ForceTry;
}
@@ -1937,6 +1947,7 @@ public:
/// Optional. If the code does throw, \c nil is produced.
class OptionalTryExpr final : public AnyTryExpr {
SourceLoc QuestionLoc;
Type thrownError;
public:
OptionalTryExpr(SourceLoc tryLoc, Expr *sub, SourceLoc questionLoc,
@@ -1946,6 +1957,15 @@ public:
SourceLoc getQuestionLoc() const { return QuestionLoc; }
/// Retrieve the type of the error thrown from the subexpression.
Type getThrownError() const { return thrownError; }
/// Set the type of the error thrown from the subexpression.
void setThrownError(Type type) {
assert(!thrownError || thrownError->isEqual(type));
thrownError = type;
}
static bool classof(const Expr *e) {
return e->getKind() == ExprKind::OptionalTry;
}

View File

@@ -2690,12 +2690,22 @@ public:
void visitForceTryExpr(ForceTryExpr *E, StringRef label) {
printCommon(E, "force_try_expr", label);
PrintOptions PO;
PO.PrintTypesForDebugging = true;
printFieldQuoted(E->getThrownError().getString(PO), "thrown_error", TypeColor);
printRec(E->getSubExpr());
printFoot();
}
void visitOptionalTryExpr(OptionalTryExpr *E, StringRef label) {
printCommon(E, "optional_try_expr", label);
PrintOptions PO;
PO.PrintTypesForDebugging = true;
printFieldQuoted(E->getThrownError().getString(PO), "thrown_error", TypeColor);
printRec(E->getSubExpr());
printFoot();
}

View File

@@ -8892,7 +8892,8 @@ static Expr *wrapAsyncLetInitializer(
ConstraintSystem &cs, Expr *initializer, DeclContext *dc) {
// Form the autoclosure type. It is always 'async', and will be 'throws'.
Type initializerType = initializer->getType();
bool throws = TypeChecker::canThrow(cs.getASTContext(), initializer);
bool throws = TypeChecker::canThrow(cs.getASTContext(), initializer)
.has_value();
auto extInfo = ASTExtInfoBuilder()
.withAsync()
.withConcurrent()

View File

@@ -3102,6 +3102,10 @@ private:
if (!Flags.has(ContextFlags::HasTryThrowSite))
diagnoseRedundantTry(E);
if (auto thrownError = TypeChecker::canThrow(Ctx, E->getSubExpr())) {
E->setThrownError(*thrownError);
}
scope.preserveCoverageFromOptionalOrForcedTryOperand();
return ShouldNotRecurse;
}
@@ -3117,6 +3121,10 @@ private:
if (!Flags.has(ContextFlags::HasTryThrowSite))
diagnoseRedundantTry(E);
if (auto thrownError = TypeChecker::canThrow(Ctx, E->getSubExpr())) {
E->setThrownError(*thrownError);
}
scope.preserveCoverageFromOptionalOrForcedTryOperand();
return ShouldNotRecurse;
}
@@ -3351,11 +3359,14 @@ void TypeChecker::checkPropertyWrapperEffects(
expr->walk(LocalFunctionEffectsChecker());
}
bool TypeChecker::canThrow(ASTContext &ctx, Expr *expr) {
llvm::Optional<Type> TypeChecker::canThrow(ASTContext &ctx, Expr *expr) {
ApplyClassifier classifier(ctx);
auto classification = classifier.classifyExpr(expr, EffectKind::Throws);
return classification.getConditionalKind(EffectKind::Throws) !=
ConditionalEffectKind::None;
if (classification.getConditionalKind(EffectKind::Throws) ==
ConditionalEffectKind::None)
return llvm::None;
return classification.getThrownError();
}
Type TypeChecker::catchErrorType(ASTContext &ctx, DoCatchStmt *stmt) {

View File

@@ -1175,8 +1175,8 @@ void checkInitializerEffects(Initializer *I, Expr *E);
void checkEnumElementEffects(EnumElementDecl *D, Expr *expr);
void checkPropertyWrapperEffects(PatternBindingDecl *binding, Expr *expr);
/// Whether the given expression can throw.
bool canThrow(ASTContext &ctx, Expr *expr);
/// Whether the given expression can throw, and if so, the thrown type.
llvm::Optional<Type> canThrow(ASTContext &ctx, Expr *expr);
/// Determine the error type that is thrown out of the body of the given
/// do-catch statement.

View File

@@ -31,4 +31,9 @@ func throwsAnything() throws {
// swallow this error
_ = e
} // implicit rethrow
// CHECK: force_try_expr{{.*}}thrown_error="MyError"
try! printOrFail("boom")
// CHECK: optional_try_expr{{.*}}thrown_error="MyError"
try? printOrFail("ssshhhhh")
}