Skip to content

Commit 3369e33

Browse files
committed
[Typed throws] Handle explicitly-specified throws on do..catch in closures
Teach the constraint system to use the same primitives as elsewhere to determine the type context for a `throw` statement and the caught error type within a `do..catch` statement. This makes explicitly-specified `throws` work on `do..catch` that occurs in closures. Cleans up some redundant computations for caught error types.
1 parent 91df336 commit 3369e33

File tree

4 files changed

+44
-41
lines changed

4 files changed

+44
-41
lines changed

include/swift/AST/AnyFunctionRef.h

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -124,24 +124,6 @@ class AnyFunctionRef {
124124
return TheFunction.get<AbstractClosureExpr *>()->getType();
125125
}
126126

127-
Type getThrownErrorType() const {
128-
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
129-
if (Type thrownError = AFD->getThrownInterfaceType())
130-
return AFD->mapTypeIntoContext(thrownError);
131-
132-
return Type();
133-
}
134-
135-
Type closureType = TheFunction.get<AbstractClosureExpr *>()->getType();
136-
if (!closureType)
137-
return Type();
138-
139-
if (auto closureFnType = closureType->getAs<AnyFunctionType>())
140-
return closureFnType->getThrownError();
141-
142-
return Type();
143-
}
144-
145127
Type getBodyResultType() const {
146128
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
147129
if (auto *FD = dyn_cast<FuncDecl>(AFD))

lib/AST/Decl.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11702,11 +11702,19 @@ CatchNode::getThrownErrorTypeInContext(DeclContext *dc) const {
1170211702
return llvm::None;
1170311703
}
1170411704

11705-
if (auto closure = dyn_cast<AbstractClosureExpr *>()) {
11706-
if (closure->getType())
11707-
return closure->getEffectiveThrownType();
11705+
if (auto abstractClosure = dyn_cast<AbstractClosureExpr *>()) {
11706+
if (abstractClosure->getType())
11707+
return abstractClosure->getEffectiveThrownType();
11708+
11709+
if (auto closure = llvm::dyn_cast<ClosureExpr>(abstractClosure)) {
11710+
if (Type thrownType = closure->getExplicitThrownType()) {
11711+
if (thrownType->isNever())
11712+
return llvm::None;
11713+
11714+
return thrownType;
11715+
}
11716+
}
1170811717

11709-
// FIXME: Should we lazily compute this?
1171011718
return llvm::None;
1171111719
}
1171211720

lib/Sema/CSSyntacticElement.cpp

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -919,16 +919,22 @@ class SyntacticElementConstraintGenerator
919919
}
920920

921921
void visitThrowStmt(ThrowStmt *throwStmt) {
922+
// Look up the catch node for this "throw" to determine the error type.
923+
auto dc = context.getAsDeclContext();
924+
CatchNode catchNode = ASTScope::lookupCatchNode(
925+
dc->getParentModule(), throwStmt->getThrowLoc());
926+
Type errorType;
927+
if (catchNode) {
928+
errorType = catchNode.getThrownErrorTypeInContext(dc).value_or(Type());
929+
}
922930

923-
// Find the thrown type of our current context.
924-
Type errType = getContextualThrownErrorType();
925-
if (!errType) {
931+
if (!errorType) {
926932
if (!cs.getASTContext().getErrorDecl()) {
927933
hadError = true;
928934
return;
929935
}
930936

931-
errType = cs.getASTContext().getErrorExistentialType();
937+
errorType = cs.getASTContext().getErrorExistentialType();
932938
}
933939

934940
auto *errorExpr = throwStmt->getSubExpr();
@@ -937,7 +943,7 @@ class SyntacticElementConstraintGenerator
937943
{makeElement(errorExpr,
938944
cs.getConstraintLocator(
939945
locator, LocatorPathElt::SyntacticElement(errorExpr)),
940-
{errType, CTP_ThrowStmt})},
946+
{errorType, CTP_ThrowStmt})},
941947
locator);
942948
}
943949

@@ -1053,8 +1059,12 @@ class SyntacticElementConstraintGenerator
10531059
if (parent.isStmt(StmtKind::Switch)) {
10541060
auto *switchStmt = cast<SwitchStmt>(parent.get<Stmt *>());
10551061
contextualTy = cs.getType(switchStmt->getSubjectExpr());
1056-
} else if (parent.isStmt(StmtKind::DoCatch)) {
1057-
contextualTy = cs.getASTContext().getErrorExistentialType();
1062+
} else if (auto doCatch =
1063+
dyn_cast_or_null<DoCatchStmt>(parent.dyn_cast<Stmt *>())) {
1064+
auto dc = context.getAsDeclContext();
1065+
contextualTy = doCatch->getExplicitCaughtType(dc);
1066+
if (!contextualTy)
1067+
contextualTy = cs.getASTContext().getErrorExistentialType();
10581068
} else {
10591069
hadError = true;
10601070
return;
@@ -1332,18 +1342,6 @@ class SyntacticElementConstraintGenerator
13321342
return {funcRef->getBodyResultType(), CTP_ReturnStmt};
13331343
}
13341344

1335-
Type getContextualThrownErrorType() const {
1336-
auto funcRef = AnyFunctionRef::fromDeclContext(context.getAsDeclContext());
1337-
if (!funcRef)
1338-
return Type();
1339-
1340-
if (auto *closure =
1341-
getAsExpr<ClosureExpr>(funcRef->getAbstractClosureExpr()))
1342-
return cs.getClosureType(closure)->getThrownError();
1343-
1344-
return funcRef->getThrownErrorType();
1345-
}
1346-
13471345
#define UNSUPPORTED_STMT(STMT) void visit##STMT##Stmt(STMT##Stmt *) { \
13481346
llvm_unreachable("Unsupported statement kind " #STMT); \
13491347
}

test/stmt/typed_throws.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,18 @@ func tryBangQuestionMismatchingContext() throws(MyError) {
176176
try? doHomework()
177177
try doHomework() // expected-error{{thrown expression type 'HomeworkError' cannot be converted to error type 'MyError'}}
178178
}
179+
180+
func apply<T, E: Error>(body: () throws(E) -> T) throws(E) -> T {
181+
return try body()
182+
}
183+
184+
func testDoCatchErrorTypedInClosure(cond: Bool) {
185+
apply {
186+
do throws(MyError) {
187+
throw .failed
188+
} catch {
189+
assert(error == .failed)
190+
processMyError(error)
191+
}
192+
}
193+
}

0 commit comments

Comments
 (0)