Skip to content

Commit 95d7318

Browse files
authored
Merge pull request #69225 from DougGregor/full-typed-throws
2 parents 051ffc5 + 083333f commit 95d7318

File tree

4 files changed

+60
-8
lines changed

4 files changed

+60
-8
lines changed

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ UPCOMING_FEATURE(ExistentialAny, 335, 6)
118118
UPCOMING_FEATURE(ImportObjcForwardDeclarations, 384, 6)
119119
UPCOMING_FEATURE(DisableOutwardActorInference, 401, 6)
120120
UPCOMING_FEATURE(InternalImportsByDefault, 409, 6)
121+
UPCOMING_FEATURE(FullTypedThrows, 410, 6)
121122

122123
EXPERIMENTAL_FEATURE(StaticAssert, false)
123124
EXPERIMENTAL_FEATURE(NamedOpaqueTypes, false)

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3575,6 +3575,10 @@ static bool usesFeatureNewCxxMethodSafetyHeuristics(Decl *decl) {
35753575
return decl->hasClangNode();
35763576
}
35773577

3578+
static bool usesFeatureFullTypedThrows(Decl *decl) {
3579+
return false;
3580+
}
3581+
35783582
static bool usesFeatureTypedThrows(Decl *decl) {
35793583
if (auto func = dyn_cast<AbstractFunctionDecl>(decl))
35803584
return func->getThrownTypeRepr() != nullptr;

lib/Sema/TypeCheckEffects.cpp

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,27 @@ static void simple_display(llvm::raw_ostream &out, ConditionalEffectKind kind) {
616616
llvm_unreachable("Bad conditional effect kind");
617617
}
618618

619+
/// Remove the type erasure to an existential error, to extract the
620+
/// underlying error.
621+
static Expr *removeErasureToExistentialError(Expr *expr) {
622+
Type type = expr->getType();
623+
if (!type)
624+
return expr;
625+
626+
ASTContext &ctx = type->getASTContext();
627+
if (!ctx.LangOpts.hasFeature(Feature::FullTypedThrows) ||
628+
!ctx.LangOpts.hasFeature(Feature::TypedThrows))
629+
return expr;
630+
631+
// Look for an outer erasure expression.
632+
if (auto erasure = dyn_cast<ErasureExpr>(expr)) {
633+
if (type->isEqual(ctx.getErrorExistentialType()))
634+
return erasure->getSubExpr();
635+
}
636+
637+
return expr;
638+
}
639+
619640
/// A type expressing the result of classifying whether a call or function
620641
/// throws or is async.
621642
class Classification {
@@ -989,6 +1010,10 @@ class ApplyClassifier {
9891010
if (!thrownValue)
9901011
return Classification::forInvalidCode();
9911012

1013+
// If we are doing full typed throws, look through an existential
1014+
// conversion to find the underlying type.
1015+
thrownValue = removeErasureToExistentialError(thrownValue);
1016+
9921017
Type thrownType = thrownValue->getType();
9931018
if (!thrownType)
9941019
return Classification::forInvalidCode();
@@ -2893,6 +2918,18 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
28932918

28942919
if (!CurContext.handlesThrows(ConditionalEffectKind::Always))
28952920
CurContext.diagnoseUnhandledThrowStmt(Ctx.Diags, S);
2921+
else {
2922+
SourceLoc loc = S->getThrowLoc();
2923+
Expr *thrownValue = S->getSubExpr();
2924+
Type thrownErrorType = thrownValue->getType();
2925+
Type caughtErrorType = getCaughtErrorTypeAt(loc);
2926+
if (!caughtErrorType->isEqual(thrownErrorType)) {
2927+
thrownValue = removeErasureToExistentialError(thrownValue);
2928+
Type thrownErrorType = thrownValue->getType();
2929+
if (!checkThrownErrorType(loc, thrownErrorType))
2930+
S->setSubExpr(thrownValue);
2931+
}
2932+
}
28962933
}
28972934

28982935
return ShouldRecurse;
@@ -2978,16 +3015,19 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
29783015

29793016
/// Check the thrown error type against the type that can be caught or
29803017
/// rethrown by the context.
2981-
void checkThrownErrorType(SourceLoc loc, Type thrownErrorType) {
3018+
///
3019+
/// Returns \c true if an error occurred, false otherwise.
3020+
bool checkThrownErrorType(SourceLoc loc, Type thrownErrorType) {
29823021
Type caughtErrorType = getCaughtErrorTypeAt(loc);
29833022
if (caughtErrorType->isEqual(thrownErrorType))
2984-
return;
3023+
return false ;
29853024

29863025
OpaqueValueExpr *opaque = new (Ctx) OpaqueValueExpr(loc, thrownErrorType);
29873026
Expr *rethrowExpr = opaque;
2988-
TypeChecker::typeCheckExpression(
3027+
Type resultType = TypeChecker::typeCheckExpression(
29893028
rethrowExpr, CurContext.getDeclContext(),
29903029
{caughtErrorType, /*FIXME:*/CTP_ThrowStmt});
3030+
return resultType.isNull();
29913031
}
29923032

29933033
ShouldRecurse_t checkAwait(AwaitExpr *E) {

test/stmt/typed_throws.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift -enable-experimental-feature TypedThrows
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature TypedThrows -enable-upcoming-feature FullTypedThrows
22

33
enum MyError: Error {
44
case failed
@@ -15,16 +15,23 @@ func processMyError(_: MyError) { }
1515
func doSomething() throws(MyError) { }
1616
func doHomework() throws(HomeworkError) { }
1717

18-
func testDoCatchErrorTyped() {
19-
#if false
20-
// FIXME: Deal with throws directly in the do...catch blocks.
18+
func testDoCatchErrorTyped(cond: Bool) {
2119
do {
2220
throw MyError.failed
2321
} catch {
2422
assert(error == .failed)
2523
processMyError(error)
2624
}
27-
#endif
25+
26+
do {
27+
if cond {
28+
throw MyError.failed
29+
} else {
30+
throw HomeworkError.dogAteIt
31+
}
32+
} catch {
33+
processMyError(error) // expected-error{{cannot convert value of type 'any Error' to expected argument type 'MyError'}}
34+
}
2835

2936
// Throwing a typed error in a do...catch catches the error with that type.
3037
do {

0 commit comments

Comments
 (0)