Skip to content

Commit

Permalink
Merge pull request swiftlang#74454 from hborla/throws-never-diagnostics
Browse files Browse the repository at this point in the history
[TypeCheckEffects] Diagnose type mismatches for thrown errors in contexts that throw `Never`.
  • Loading branch information
hborla committed Jun 20, 2024
2 parents ca266d3 + 8d64344 commit 991e7fd
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
17 changes: 17 additions & 0 deletions lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,23 @@ ParserResult<Expr> Parser::parseExprSequence(Diag<> Message,
if (SequencedExprs.size() == 1)
return makeParserResult(SequenceStatus, SequencedExprs[0]);

// If the left-most sequence expr is a 'try', hoist it up to turn
// '(try x) + y' into 'try (x + y)'. This is necessary to do in the
// parser because 'try' nodes are represented in the ASTScope tree
// to look up catch nodes. The scope tree must be syntactic because
// it's constructed before sequence folding happens during preCheckExpr.
// Otherwise, catch node lookup would find the incorrect catch node for
// 'try x + y' at the source location for 'y'.
//
// 'try' has restrictions for where it can appear within a sequence
// expr. This is still diagnosed in TypeChecker::foldSequence.
if (auto *tryEval = dyn_cast<AnyTryExpr>(SequencedExprs[0])) {
SequencedExprs[0] = tryEval->getSubExpr();
auto *sequence = SequenceExpr::create(Context, SequencedExprs);
tryEval->setSubExpr(sequence);
return makeParserResult(SequenceStatus, tryEval);
}

return makeParserResult(SequenceStatus,
SequenceExpr::create(Context, SequencedExprs));
}
Expand Down
15 changes: 15 additions & 0 deletions lib/Sema/TypeCheckEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3020,9 +3020,24 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
Type getCaughtErrorTypeAt(SourceLoc loc) {
auto dc = CurContext.getDeclContext();
auto module = dc->getParentModule();

// Autoclosures can't be found via ASTScope lookup.
if (CurContext.isAutoClosure()) {
auto *closure = dyn_cast<AutoClosureExpr>(CurContext.getDeclContext());
if (auto type = closure->getEffectiveThrownType())
return *type;

// Otherwise, the closure does not throw.
return Ctx.getNeverType();
}

if (CatchNode catchNode = ASTScope::lookupCatchNode(module, loc)) {
if (auto caughtType = catchNode.getThrownErrorTypeInContext(Ctx))
return *caughtType;

// If a catch node returns null for its thrown error type, we're
// in a non-throwing context.
return Ctx.getNeverType();
}

// Fall back to the error existential.
Expand Down
26 changes: 26 additions & 0 deletions test/stmt/typed_throws.swift
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,29 @@ func testDoCatchInClosure(cond: Bool, x: ThrowingMembers) {
}
}
}

func takesThrowingAutoclosure(_: @autoclosure () throws(MyError) -> Int) {}
func takesNonThrowingAutoclosure(_: @autoclosure () throws(Never) -> Int) {}

func getInt() throws -> Int { 0 }

func throwingAutoclosures() {
takesThrowingAutoclosure(try getInt())
// expected-error@-1 {{thrown expression type 'any Error' cannot be converted to error type 'MyError'}}

takesNonThrowingAutoclosure(try getInt())
// expected-error@-1 {{thrown expression type 'any Error' cannot be converted to error type 'Never'}}
}

func noThrow() throws(Never) {
throw MyError.epicFailed
// expected-error@-1 {{thrown expression type 'MyError' cannot be converted to error type 'Never'}}

try doSomething()
// expected-error@-1 {{thrown expression type 'MyError' cannot be converted to error type 'Never'}}

do throws(Never) {
throw MyError.epicFailed
// expected-error@-1 {{thrown expression type 'MyError' cannot be converted to error type 'Never'}}
} catch {}
}

0 comments on commit 991e7fd

Please sign in to comment.