mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +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.
|
/// should dynamically assert if it does.
|
||||||
class ForceTryExpr final : public AnyTryExpr {
|
class ForceTryExpr final : public AnyTryExpr {
|
||||||
SourceLoc ExclaimLoc;
|
SourceLoc ExclaimLoc;
|
||||||
|
Type thrownError;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ForceTryExpr(SourceLoc tryLoc, Expr *sub, SourceLoc exclaimLoc,
|
ForceTryExpr(SourceLoc tryLoc, Expr *sub, SourceLoc exclaimLoc,
|
||||||
@@ -1927,6 +1928,15 @@ public:
|
|||||||
|
|
||||||
SourceLoc getExclaimLoc() const { return ExclaimLoc; }
|
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) {
|
static bool classof(const Expr *e) {
|
||||||
return e->getKind() == ExprKind::ForceTry;
|
return e->getKind() == ExprKind::ForceTry;
|
||||||
}
|
}
|
||||||
@@ -1937,6 +1947,7 @@ public:
|
|||||||
/// Optional. If the code does throw, \c nil is produced.
|
/// Optional. If the code does throw, \c nil is produced.
|
||||||
class OptionalTryExpr final : public AnyTryExpr {
|
class OptionalTryExpr final : public AnyTryExpr {
|
||||||
SourceLoc QuestionLoc;
|
SourceLoc QuestionLoc;
|
||||||
|
Type thrownError;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OptionalTryExpr(SourceLoc tryLoc, Expr *sub, SourceLoc questionLoc,
|
OptionalTryExpr(SourceLoc tryLoc, Expr *sub, SourceLoc questionLoc,
|
||||||
@@ -1946,6 +1957,15 @@ public:
|
|||||||
|
|
||||||
SourceLoc getQuestionLoc() const { return QuestionLoc; }
|
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) {
|
static bool classof(const Expr *e) {
|
||||||
return e->getKind() == ExprKind::OptionalTry;
|
return e->getKind() == ExprKind::OptionalTry;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2690,12 +2690,22 @@ public:
|
|||||||
|
|
||||||
void visitForceTryExpr(ForceTryExpr *E, StringRef label) {
|
void visitForceTryExpr(ForceTryExpr *E, StringRef label) {
|
||||||
printCommon(E, "force_try_expr", label);
|
printCommon(E, "force_try_expr", label);
|
||||||
|
|
||||||
|
PrintOptions PO;
|
||||||
|
PO.PrintTypesForDebugging = true;
|
||||||
|
printFieldQuoted(E->getThrownError().getString(PO), "thrown_error", TypeColor);
|
||||||
|
|
||||||
printRec(E->getSubExpr());
|
printRec(E->getSubExpr());
|
||||||
printFoot();
|
printFoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitOptionalTryExpr(OptionalTryExpr *E, StringRef label) {
|
void visitOptionalTryExpr(OptionalTryExpr *E, StringRef label) {
|
||||||
printCommon(E, "optional_try_expr", label);
|
printCommon(E, "optional_try_expr", label);
|
||||||
|
|
||||||
|
PrintOptions PO;
|
||||||
|
PO.PrintTypesForDebugging = true;
|
||||||
|
printFieldQuoted(E->getThrownError().getString(PO), "thrown_error", TypeColor);
|
||||||
|
|
||||||
printRec(E->getSubExpr());
|
printRec(E->getSubExpr());
|
||||||
printFoot();
|
printFoot();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8892,7 +8892,8 @@ static Expr *wrapAsyncLetInitializer(
|
|||||||
ConstraintSystem &cs, Expr *initializer, DeclContext *dc) {
|
ConstraintSystem &cs, Expr *initializer, DeclContext *dc) {
|
||||||
// Form the autoclosure type. It is always 'async', and will be 'throws'.
|
// Form the autoclosure type. It is always 'async', and will be 'throws'.
|
||||||
Type initializerType = initializer->getType();
|
Type initializerType = initializer->getType();
|
||||||
bool throws = TypeChecker::canThrow(cs.getASTContext(), initializer);
|
bool throws = TypeChecker::canThrow(cs.getASTContext(), initializer)
|
||||||
|
.has_value();
|
||||||
auto extInfo = ASTExtInfoBuilder()
|
auto extInfo = ASTExtInfoBuilder()
|
||||||
.withAsync()
|
.withAsync()
|
||||||
.withConcurrent()
|
.withConcurrent()
|
||||||
|
|||||||
@@ -3102,6 +3102,10 @@ private:
|
|||||||
if (!Flags.has(ContextFlags::HasTryThrowSite))
|
if (!Flags.has(ContextFlags::HasTryThrowSite))
|
||||||
diagnoseRedundantTry(E);
|
diagnoseRedundantTry(E);
|
||||||
|
|
||||||
|
if (auto thrownError = TypeChecker::canThrow(Ctx, E->getSubExpr())) {
|
||||||
|
E->setThrownError(*thrownError);
|
||||||
|
}
|
||||||
|
|
||||||
scope.preserveCoverageFromOptionalOrForcedTryOperand();
|
scope.preserveCoverageFromOptionalOrForcedTryOperand();
|
||||||
return ShouldNotRecurse;
|
return ShouldNotRecurse;
|
||||||
}
|
}
|
||||||
@@ -3117,6 +3121,10 @@ private:
|
|||||||
if (!Flags.has(ContextFlags::HasTryThrowSite))
|
if (!Flags.has(ContextFlags::HasTryThrowSite))
|
||||||
diagnoseRedundantTry(E);
|
diagnoseRedundantTry(E);
|
||||||
|
|
||||||
|
if (auto thrownError = TypeChecker::canThrow(Ctx, E->getSubExpr())) {
|
||||||
|
E->setThrownError(*thrownError);
|
||||||
|
}
|
||||||
|
|
||||||
scope.preserveCoverageFromOptionalOrForcedTryOperand();
|
scope.preserveCoverageFromOptionalOrForcedTryOperand();
|
||||||
return ShouldNotRecurse;
|
return ShouldNotRecurse;
|
||||||
}
|
}
|
||||||
@@ -3351,11 +3359,14 @@ void TypeChecker::checkPropertyWrapperEffects(
|
|||||||
expr->walk(LocalFunctionEffectsChecker());
|
expr->walk(LocalFunctionEffectsChecker());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeChecker::canThrow(ASTContext &ctx, Expr *expr) {
|
llvm::Optional<Type> TypeChecker::canThrow(ASTContext &ctx, Expr *expr) {
|
||||||
ApplyClassifier classifier(ctx);
|
ApplyClassifier classifier(ctx);
|
||||||
auto classification = classifier.classifyExpr(expr, EffectKind::Throws);
|
auto classification = classifier.classifyExpr(expr, EffectKind::Throws);
|
||||||
return classification.getConditionalKind(EffectKind::Throws) !=
|
if (classification.getConditionalKind(EffectKind::Throws) ==
|
||||||
ConditionalEffectKind::None;
|
ConditionalEffectKind::None)
|
||||||
|
return llvm::None;
|
||||||
|
|
||||||
|
return classification.getThrownError();
|
||||||
}
|
}
|
||||||
|
|
||||||
Type TypeChecker::catchErrorType(ASTContext &ctx, DoCatchStmt *stmt) {
|
Type TypeChecker::catchErrorType(ASTContext &ctx, DoCatchStmt *stmt) {
|
||||||
|
|||||||
@@ -1175,8 +1175,8 @@ void checkInitializerEffects(Initializer *I, Expr *E);
|
|||||||
void checkEnumElementEffects(EnumElementDecl *D, Expr *expr);
|
void checkEnumElementEffects(EnumElementDecl *D, Expr *expr);
|
||||||
void checkPropertyWrapperEffects(PatternBindingDecl *binding, Expr *expr);
|
void checkPropertyWrapperEffects(PatternBindingDecl *binding, Expr *expr);
|
||||||
|
|
||||||
/// Whether the given expression can throw.
|
/// Whether the given expression can throw, and if so, the thrown type.
|
||||||
bool canThrow(ASTContext &ctx, Expr *expr);
|
llvm::Optional<Type> canThrow(ASTContext &ctx, Expr *expr);
|
||||||
|
|
||||||
/// Determine the error type that is thrown out of the body of the given
|
/// Determine the error type that is thrown out of the body of the given
|
||||||
/// do-catch statement.
|
/// do-catch statement.
|
||||||
|
|||||||
@@ -31,4 +31,9 @@ func throwsAnything() throws {
|
|||||||
// swallow this error
|
// swallow this error
|
||||||
_ = e
|
_ = e
|
||||||
} // implicit rethrow
|
} // 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