Skip to content

Commit 7c2a73e

Browse files
committed
[Macros] Create type refinement context for MacroExpansionDecl
1 parent 8263e15 commit 7c2a73e

6 files changed

+79
-10
lines changed

lib/AST/ASTWalker.cpp

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

14831483
bool shouldSkip(Decl *D) {
14841484
if (!Walker.shouldWalkMacroArgumentsAndExpansion().second &&
1485-
D->isInMacroExpansionInContext())
1485+
D->isInMacroExpansionInContext() && !Walker.Parent.isNull())
14861486
return true;
14871487

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

lib/AST/Decl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/Decl.h"
1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/ASTMangler.h"
20+
#include "swift/AST/ASTPrinter.h"
2021
#include "swift/AST/ASTWalker.h"
2122
#include "swift/AST/AccessRequests.h"
2223
#include "swift/AST/AccessScope.h"
@@ -10078,6 +10079,13 @@ void swift::simple_display(llvm::raw_ostream &out, const Decl *decl) {
1007810079
typeRepr->print(out);
1007910080
else
1008010081
ext->getSelfNominalTypeDecl()->dumpRef(out);
10082+
} else if (auto med = dyn_cast<MacroExpansionDecl>(decl)) {
10083+
out << '#' << med->getMacroName() << " in ";
10084+
printContext(out, med->getDeclContext());
10085+
if (med->getLoc().isValid()) {
10086+
out << '@';
10087+
med->getLoc().print(out, med->getASTContext().SourceMgr);
10088+
}
1008110089
} else {
1008210090
out << "(unknown decl)";
1008310091
}

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
473473

474474
private:
475475
MacroWalking getMacroWalkingBehavior() const override {
476+
// Expansion buffers will have their type refinement contexts built lazily.
476477
return MacroWalking::Arguments;
477478
}
478479

@@ -558,7 +559,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
558559
/// Returns a new context to be introduced for the declaration, or nullptr
559560
/// if no new context should be introduced.
560561
TypeRefinementContext *getNewContextForSignatureOfDecl(Decl *D) {
561-
if (!isa<ValueDecl>(D) && !isa<ExtensionDecl>(D))
562+
if (!isa<ValueDecl>(D) && !isa<ExtensionDecl>(D) && !isa<MacroExpansionDecl>(D))
562563
return nullptr;
563564

564565
// Only introduce for an AbstractStorageDecl if it is not local. We
@@ -1430,7 +1431,9 @@ class InnermostAncestorFinder : private ASTWalker {
14301431
Optional<ASTNode> getInnermostMatchingNode() { return InnermostMatchingNode; }
14311432

14321433
MacroWalking getMacroWalkingBehavior() const override {
1433-
return MacroWalking::ArgumentsAndExpansion;
1434+
// This is SourceRange based finder. 'SM.rangeContains()' fails anyway when
1435+
// crossing source buffers.
1436+
return MacroWalking::Arguments;
14341437
}
14351438

14361439
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
@@ -3192,7 +3195,8 @@ class ExprAvailabilityWalker : public ASTWalker {
31923195
bool shouldWalkIntoTapExpression() override { return false; }
31933196

31943197
MacroWalking getMacroWalkingBehavior() const override {
3195-
return MacroWalking::ArgumentsAndExpansion;
3198+
// Expanded source should be type checked and diagnosed separately.
3199+
return MacroWalking::Arguments;
31963200
}
31973201

31983202
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,10 +2060,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
20602060
}
20612061

20622062
void visitMacroExpansionDecl(MacroExpansionDecl *MED) {
2063-
// TODO: Type check attributes.
2064-
// Type checking arguments should reflect the attributes.
2065-
// e.g. '@available(macOS 999) #Future { newAPIFrom999() }'.
2066-
20672063
// Assign a discriminator.
20682064
(void)MED->getDiscriminator();
20692065
// Decls in expansion already visited as auxiliary decls.

test/Macros/Inputs/top_level_freestanding_other.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ var globalVar2 = { #stringify(1 + 1) }()
1111
func deprecated() -> Int { 0 }
1212

1313
var globalVar3 = #stringify({ deprecated() })
14-
// expected-note@-1 2{{in expansion of macro 'stringify' here}}
14+
// expected-note@-1 {{in expansion of macro 'stringify' here}}
1515
// expected-warning@-2{{'deprecated()' is deprecated}}
1616

1717
var globalVar4 = #stringify({ deprecated() })
18-
// expected-note@-1 2{{in expansion of macro 'stringify' here}}
18+
// expected-note@-1 {{in expansion of macro 'stringify' here}}
1919
// expected-warning@-2{{'deprecated()' is deprecated}}

test/Macros/macro_attribute_expansiondecl.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,26 @@ public struct LocalFuncAndVarMacro: DeclarationMacro {
5757
}
5858
}
5959

60+
public struct FuncFromClosureMacro: DeclarationMacro {
61+
public static func expansion(
62+
of node: some FreestandingMacroExpansionSyntax,
63+
in context: some MacroExpansionContext
64+
) throws -> [DeclSyntax] {
65+
guard
66+
let closure = node.trailingClosure,
67+
let arg1 = node.argumentList.first?.expression else {
68+
return []
69+
}
70+
71+
return ["""
72+
func fromClosure() {
73+
print(\(arg1))
74+
\(closure.statements)
75+
}
76+
"""]
77+
}
78+
}
79+
6080
//--- test.swift
6181

6282
@freestanding(declaration, names: named(globalFunc), named(globalVar)) macro globalDecls() = #externalMacro(module: "MacroDefinition", type: "GlobalFuncAndVarMacro")
@@ -97,3 +117,44 @@ func testLocal() {
97117
}
98118
#endif
99119
}
120+
121+
@freestanding(declaration, names: named(fromClosure)) macro funcFromClosureMacro(_: String, _: () -> Void) = #externalMacro(module: "MacroDefinition", type: "FuncFromClosureMacro")
122+
123+
@available(macOS 99, *)
124+
func APIFrom99() -> String { "" }
125+
@available(macOS 999, *)
126+
func APIFrom999() -> String { "" }
127+
128+
@available(macOS 99, *)
129+
#funcFromClosureMacro(APIFrom99()) {
130+
_ = APIFrom99()
131+
if #available(macOS 999, *) {
132+
_ = APIFrom99()
133+
_ = APIFrom999()
134+
}
135+
}
136+
137+
struct S1 {
138+
@available(macOS 99, *)
139+
#funcFromClosureMacro(APIFrom99()) {
140+
_ = APIFrom99()
141+
if #available(macOS 999, *) {
142+
_ = APIFrom99()
143+
_ = APIFrom999()
144+
}
145+
}
146+
}
147+
148+
// FIXME: Diagnostics could be better.
149+
struct S2 { // expected-note 4 {{add @available attribute to enclosing struct}}
150+
// expected-note@+3 6 {{in expansion of macro 'funcFromClosureMacro' here}}
151+
// expected-error@+2 {{'APIFrom99()' is only available in macOS 99 or newer}}
152+
// expected-error@+2 {{'APIFrom99()' is only available in macOS 99 or newer}} expected-note@+2 {{add 'if #available' version check}}
153+
#funcFromClosureMacro(APIFrom99()) {
154+
_ = APIFrom99()
155+
if #available(macOS 999, *) {
156+
_ = APIFrom99()
157+
_ = APIFrom999()
158+
}
159+
}
160+
}

0 commit comments

Comments
 (0)