mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user