Skip to content

Commit 4668824

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. (cherry picked from commit 265c8a4)
1 parent 63b9415 commit 4668824

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
@@ -934,9 +934,14 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
934934

935935
SourceLoc TrailingSemiLoc;
936936

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

941946
/// Returns the appropriate kind of entry point to generate for this class,
942947
/// 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
@@ -767,8 +767,22 @@ SourceRange Decl::getSourceRangeIncludingAttrs() const {
767767
return Range;
768768
}
769769

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

774788
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
@@ -1373,3 +1373,18 @@ public struct SimpleCodeItemMacro: CodeItemMacro {
13731373
]
13741374
}
13751375
}
1376+
1377+
public struct MultiStatementClosure: ExpressionMacro {
1378+
public static func expansion(
1379+
of node: some FreestandingMacroExpansionSyntax,
1380+
in context: some MacroExpansionContext
1381+
) throws -> ExprSyntax {
1382+
return """
1383+
{
1384+
let temp = 10
1385+
let result = temp
1386+
return result
1387+
}()
1388+
"""
1389+
}
1390+
}
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)