Skip to content

Commit 265c8a4

Browse files
committed
[Macros] Fix an issue where the constraint system skipped local declarations
inside closures while type checking a macro expansion. PreCheckExpr, ConstraintGenerator, and other walkers do not walk into macro expansions. However, the implementation of this macro walking behavior in ASTWalker would skip any declaration that appears inside any macro expansion buffer. This is incorrect for cases where the parent is in the same macro expansion buffer, because the local declaration is not inside a new macro expansion. This caused bogus errors when type checking expanded macro expressions containing closures with local declarations, because pre-check and constraint generation mistakenly skipped local pattern bindings.
1 parent ae32673 commit 265c8a4

File tree

6 files changed

+57
-7
lines changed

6 files changed

+57
-7
lines changed

include/swift/AST/Decl.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -935,9 +935,14 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
935935

936936
SourceLoc TrailingSemiLoc;
937937

938-
/// Whether this declaration is within a generated buffer, \c false if this
939-
/// declaration was constructed from a serialized module.
940-
bool isInGeneratedBuffer() const;
938+
/// Whether this declaration is within a macro expansion relative to
939+
/// its decl context. If the decl context is itself in a macro expansion,
940+
/// the method returns \c true if this decl is in a different macro
941+
/// expansion buffer than the context.
942+
///
943+
/// \Note this method returns \c false if this declaration was
944+
/// constructed from a serialized module.
945+
bool isInMacroExpansionInContext() const;
941946

942947
/// Returns the appropriate kind of entry point to generate for this class,
943948
/// based on its attributes.

lib/AST/ASTWalker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
14811481

14821482
bool shouldSkip(Decl *D) {
14831483
if (!Walker.shouldWalkMacroArgumentsAndExpansion().second &&
1484-
D->isInGeneratedBuffer())
1484+
D->isInMacroExpansionInContext())
14851485
return true;
14861486

14871487
if (auto *VD = dyn_cast<VarDecl>(D)) {

lib/AST/Decl.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -765,8 +765,22 @@ SourceRange Decl::getSourceRangeIncludingAttrs() const {
765765
return Range;
766766
}
767767

768-
bool Decl::isInGeneratedBuffer() const {
769-
return getModuleContext()->isInGeneratedBuffer(getStartLoc());
768+
bool Decl::isInMacroExpansionInContext() const {
769+
auto *dc = getDeclContext();
770+
auto parentFile = dc->getParentSourceFile();
771+
auto *mod = getModuleContext();
772+
auto *file = mod->getSourceFileContainingLocation(getStartLoc());
773+
774+
// Decls in macro expansions always have a source file. The source
775+
// file can be null if the decl is implicit or has an invalid
776+
// source location.
777+
if (!parentFile || !file)
778+
return false;
779+
780+
if (file->getBufferID() == parentFile->getBufferID())
781+
return false;
782+
783+
return file->getFulfilledMacroRole() != None;
770784
}
771785

772786
SourceLoc Decl::getLocFromSource() const {

lib/IDE/SourceEntityWalker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,7 @@ bool SemaAnnotator::shouldIgnore(Decl *D) {
889889
// by a member attribute expansion. Note that we would have already skipped
890890
// this decl if we were ignoring expansions, so no need to check that.
891891
if (auto *missing = dyn_cast<MissingDecl>(D)) {
892-
if (D->isInGeneratedBuffer())
892+
if (D->isInMacroExpansionInContext())
893893
return false;
894894
}
895895

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,3 +1360,18 @@ public struct SimpleCodeItemMacro: CodeItemMacro {
13601360
]
13611361
}
13621362
}
1363+
1364+
public struct MultiStatementClosure: ExpressionMacro {
1365+
public static func expansion(
1366+
of node: some FreestandingMacroExpansionSyntax,
1367+
in context: some MacroExpansionContext
1368+
) throws -> ExprSyntax {
1369+
return """
1370+
{
1371+
let temp = 10
1372+
let result = temp
1373+
return result
1374+
}()
1375+
"""
1376+
}
1377+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// REQUIRES: swift_swift_parser, executable_test
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
5+
// RUN: %target-build-swift -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) %s -o %t/main -module-name MacroUser -swift-version 5
6+
// RUN: %target-codesign %t/main
7+
// RUN: %target-run %t/main | %FileCheck %s
8+
9+
@freestanding(expression) public macro multiStatement() -> Int = #externalMacro(module: "MacroDefinition", type: "MultiStatementClosure")
10+
11+
func multiStatementInference() -> Int {
12+
#multiStatement()
13+
}
14+
15+
// CHECK: 10
16+
print(multiStatementInference())

0 commit comments

Comments
 (0)