Skip to content

Commit bf7ee49

Browse files
authored
Merge pull request #80799 from hamishknight/expanded-catch
[ASTScope] Match parent scopes in `lookupCatchNode` for brace stmts
2 parents 77eb4f0 + b8ab2c0 commit bf7ee49

File tree

3 files changed

+42
-31
lines changed

3 files changed

+42
-31
lines changed

lib/AST/ASTScopeLookup.cpp

+20-31
Original file line numberDiff line numberDiff line change
@@ -703,42 +703,24 @@ lookupEnclosingABIAttributeScope(SourceFile *sourceFile, SourceLoc loc) {
703703
return nullptr;
704704
}
705705

706-
static std::pair<CatchNode, const BraceStmtScope *>
707-
getCatchNodeBody(const ASTScopeImpl *scope, CatchNode node) {
708-
const auto &children = scope->getChildren();
709-
if (children.empty())
710-
return { CatchNode(), nullptr };
711-
712-
auto stmt = dyn_cast<BraceStmtScope>(children[0]);
713-
if (!stmt || stmt->getStmt()->empty())
714-
return { CatchNode(), nullptr };
715-
716-
return std::make_pair(node, stmt);
717-
}
718-
719706
/// Retrieve the catch node associated with this scope, if any.
720-
static std::pair<CatchNode, const BraceStmtScope *>
721-
getCatchNode(const ASTScopeImpl *scope) {
707+
static CatchNode getCatchNode(const ASTScopeImpl *scope) {
722708
// Closures introduce a catch scope for errors initiated in their body.
723709
if (auto closureParams = dyn_cast<ClosureParametersScope>(scope)) {
724-
if (auto closure = dyn_cast<ClosureExpr>(closureParams->closureExpr)) {
725-
return getCatchNodeBody(scope, const_cast<ClosureExpr *>(closure));
726-
}
710+
if (auto closure = dyn_cast<ClosureExpr>(closureParams->closureExpr))
711+
return closure;
727712
}
728713

729714
// Functions introduce a catch scope for errors initiated in their body.
730-
if (auto function = dyn_cast<FunctionBodyScope>(scope)) {
731-
return getCatchNodeBody(
732-
scope, const_cast<AbstractFunctionDecl *>(function->decl));
733-
}
715+
if (auto function = dyn_cast<FunctionBodyScope>(scope))
716+
return function->decl;
734717

735718
// Do..catch blocks introduce a catch scope for errors initiated in the `do`
736719
// body.
737-
if (auto doCatch = dyn_cast<DoCatchStmtScope>(scope)) {
738-
return getCatchNodeBody(scope, const_cast<DoCatchStmt *>(doCatch->stmt));
739-
}
720+
if (auto doCatch = dyn_cast<DoCatchStmtScope>(scope))
721+
return doCatch->stmt;
740722

741-
return { CatchNode(), nullptr };
723+
return CatchNode();
742724
}
743725

744726
/// Check whether the given location precedes the start of the catch location
@@ -767,15 +749,22 @@ CatchNode ASTScopeImpl::lookupCatchNode(ModuleDecl *module, SourceLoc loc) {
767749
ASTScopeAssert(innermost->getWasExpanded(),
768750
"If looking in a scope, it must have been expanded.");
769751

770-
// Look for a body scope that's the
752+
// Look for a body scope that's the direct descendent of a catch node.
771753
const BraceStmtScope *innerBodyScope = nullptr;
772754
for (auto scope = innermost; scope; scope = scope->getParent().getPtrOrNull()) {
773755
// If we are at a catch node and in the body of the region from which that
774756
// node catches thrown errors, we have our result.
775-
auto caught = getCatchNode(scope);
776-
if (caught.first && caught.second == innerBodyScope &&
777-
!locationIsPriorToStartOfCatchScope(loc, caught.first)) {
778-
return caught.first;
757+
if (innerBodyScope && innerBodyScope->getParent() == scope) {
758+
// For a macro expansion, we may have an intermediate source file scope,
759+
// we can look through it.
760+
auto catchScope = scope;
761+
if (auto *sfScope = dyn_cast<ASTSourceFileScope>(catchScope)) {
762+
if (auto parent = sfScope->getParent())
763+
catchScope = parent.get();
764+
}
765+
auto caught = getCatchNode(catchScope);
766+
if (caught && !locationIsPriorToStartOfCatchScope(loc, caught))
767+
return caught;
779768
}
780769

781770
// If this is a try scope for a try! or try?, it catches the error.

test/Macros/Inputs/syntax_macro_definitions.swift

+10
Original file line numberDiff line numberDiff line change
@@ -2683,6 +2683,16 @@ public struct BodyMacroWithControlFlow: BodyMacro {
26832683
}
26842684
}
26852685

2686+
struct ThrowCancellationMacro: BodyMacro {
2687+
static func expansion(
2688+
of node: AttributeSyntax,
2689+
providingBodyFor declaration: some DeclSyntaxProtocol & WithOptionalCodeBlockSyntax,
2690+
in context: some MacroExpansionContext
2691+
) throws -> [CodeBlockItemSyntax] {
2692+
["throw CancellationError()"]
2693+
}
2694+
}
2695+
26862696
@_spi(ExperimentalLanguageFeature)
26872697
public struct TracedPreambleMacro: PreambleMacro {
26882698
public static func expansion(

test/Macros/macro_expand.swift

+12
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ struct RedeclChecking {
152152
// CHECK-DIAGS: }
153153
// CHECK-DIAGS: END CONTENTS OF FILE
154154

155+
@attached(body)
156+
public macro ThrowCancellation() = #externalMacro(module: "MacroDefinition", type: "ThrowCancellationMacro")
157+
158+
// https://github.com/swiftlang/swift/issues/79039 - Make sure we diagnose the
159+
// error mismatch.
160+
@ThrowCancellation // expected-note {{in expansion of macro 'ThrowCancellation' on global function 'issue79039()' here}}
161+
func issue79039() throws(DecodingError)
162+
// CHECK-DIAGS: @__swiftmacro_9MacroUser10issue7903917ThrowCancellationfMb_.swift:2:11: error: thrown expression type 'CancellationError' cannot be converted to error type 'DecodingError'
163+
164+
@ThrowCancellation // expected-note {{in expansion of macro 'ThrowCancellation' on global function 'issue79039_2()' here}}
165+
func issue79039_2() throws(DecodingError) {}
166+
// CHECK-DIAGS: @__swiftmacro_9MacroUser12issue79039_217ThrowCancellationfMb_.swift:2:11: error: thrown expression type 'CancellationError' cannot be converted to error type 'DecodingError'
155167
#endif
156168

157169
@freestanding(declaration)

0 commit comments

Comments
 (0)