Skip to content

Commit 5405f1a

Browse files
authored
Merge pull request #70128 from DougGregor/preamble-macros-introducing-names
Allow preamble macros to introduce declarations with documented names
2 parents 2bb035e + 1c158b5 commit 5405f1a

File tree

7 files changed

+131
-66
lines changed

7 files changed

+131
-66
lines changed

lib/AST/ASTScopeCreation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1323,7 +1323,7 @@ AbstractPatternEntryScope::AbstractPatternEntryScope(
13231323
#pragma mark - expandBody
13241324

13251325
void FunctionBodyScope::expandBody(ScopeCreator &scopeCreator) {
1326-
scopeCreator.addToScopeTree(decl->getBody(), this);
1326+
scopeCreator.addToScopeTree(decl->getMacroExpandedBody(), this);
13271327
}
13281328

13291329
void GenericTypeOrExtensionScope::expandBody(ScopeCreator &) {}

lib/AST/Decl.cpp

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9127,24 +9127,74 @@ bool AbstractFunctionDecl::hasBody() const {
91279127
}
91289128
}
91299129

9130+
/// Expand all preamble macros attached to the given function declaration.
9131+
static std::vector<ASTNode> expandPreamble(AbstractFunctionDecl *func) {
9132+
std::vector<ASTNode> preamble;
91309133

9134+
ASTContext &ctx = func->getASTContext();
9135+
ExpandPreambleMacroRequest request{func};
9136+
auto module = func->getParentModule();
9137+
for (auto bufferID : evaluateOrDefault(ctx.evaluator, request, { })) {
9138+
auto bufferStart = ctx.SourceMgr.getLocForBufferStart(bufferID);
9139+
auto preambleSF = module->getSourceFileContainingLocation(bufferStart);
9140+
preamble.insert(preamble.end(),
9141+
preambleSF->getTopLevelItems().begin(),
9142+
preambleSF->getTopLevelItems().end());
9143+
}
9144+
9145+
return preamble;
9146+
}
9147+
9148+
/// Expand body macros and produce the resulting body.
91319149
static BraceStmt *expandBodyMacro(AbstractFunctionDecl *fn) {
91329150
ASTContext &ctx = fn->getASTContext();
91339151

9134-
auto bufferID = evaluateOrDefault(
9135-
ctx.evaluator, ExpandBodyMacroRequest{fn}, llvm::None);
9136-
if (!bufferID) {
9152+
// Expand the preamble.
9153+
auto preamble = expandPreamble(fn);
9154+
9155+
// Expand a body macro, if there is one.
9156+
if (auto bufferID = evaluateOrDefault(
9157+
ctx.evaluator, ExpandBodyMacroRequest{fn}, llvm::None)) {
9158+
CharSourceRange bufferRange = ctx.SourceMgr.getRangeForBuffer(*bufferID);
9159+
auto bufferStart = bufferRange.getStart();
9160+
auto module = fn->getParentModule();
9161+
auto macroSourceFile = module->getSourceFileContainingLocation(bufferStart);
9162+
9163+
// When there is no preamble, adopt the body itself.
9164+
if (preamble.empty()) {
9165+
return BraceStmt::create(
9166+
ctx, bufferRange.getStart(), macroSourceFile->getTopLevelItems(),
9167+
bufferRange.getEnd());
9168+
}
9169+
9170+
// Merge the preamble into the macro-produced body.
9171+
auto contents = std::move(preamble);
9172+
contents.insert(
9173+
contents.end(),
9174+
macroSourceFile->getTopLevelItems().begin(),
9175+
macroSourceFile->getTopLevelItems().end());
9176+
return BraceStmt::create(
9177+
ctx, bufferRange.getStart(), contents, bufferRange.getEnd());
9178+
}
9179+
9180+
// There is no body macro. If there's no preamble, either, then there is
9181+
// nothing to do.
9182+
if (preamble.empty())
91379183
return nullptr;
9138-
}
91399184

9140-
CharSourceRange bufferRange = ctx.SourceMgr.getRangeForBuffer(*bufferID);
9141-
auto bufferStart = bufferRange.getStart();
9142-
auto module = fn->getParentModule();
9143-
auto macroSourceFile = module->getSourceFileContainingLocation(bufferStart);
9185+
// If there is no body, the preamble has nowhere to go.
9186+
auto body = fn->getBody(/*canSynthesize=*/true);
9187+
if (!body) {
9188+
// FIXME: diagnose this
9189+
return nullptr;
9190+
}
91449191

9192+
// Merge the preamble into the existing body.
9193+
auto contents = std::move(preamble);
9194+
contents.insert(
9195+
contents.end(), body->getElements().begin(), body->getElements().end());
91459196
return BraceStmt::create(
9146-
ctx, bufferRange.getStart(), macroSourceFile->getTopLevelItems(),
9147-
bufferRange.getEnd());
9197+
ctx, body->getLBraceLoc(), contents, body->getRBraceLoc());
91489198
}
91499199

91509200
BraceStmt *AbstractFunctionDecl::getMacroExpandedBody() const {

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7166,7 +7166,6 @@ void AttributeChecker::visitMacroRoleAttr(MacroRoleAttr *attr) {
71667166
// TODO: Check property observer names?
71677167
break;
71687168
case MacroRole::MemberAttribute:
7169-
case MacroRole::Preamble:
71707169
case MacroRole::Body:
71717170
if (!attr->getNames().empty())
71727171
diagnoseAndRemoveAttr(attr, diag::macro_cannot_introduce_names,
@@ -7188,6 +7187,7 @@ void AttributeChecker::visitMacroRoleAttr(MacroRoleAttr *attr) {
71887187
break;
71897188
}
71907189
case MacroRole::Extension:
7190+
case MacroRole::Preamble:
71917191
break;
71927192
default:
71937193
diagnoseAndRemoveAttr(attr, diag::invalid_macro_role_for_macro_syntax,

lib/Sema/TypeCheckMacros.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,29 @@ getExplicitInitializerRange(AbstractStorageDecl *storage) {
834834
return SourceRange(equalLoc, initRange.End);
835835
}
836836

837+
/// Compute the original source range for expanding a preamble macro.
838+
static CharSourceRange getPreambleMacroOriginalRange(AbstractFunctionDecl *fn) {
839+
ASTContext &ctx = fn->getASTContext();
840+
841+
SourceLoc insertionLoc;
842+
843+
// If there is a body macro, start at the beginning of it.
844+
if (auto bodyBufferID = evaluateOrDefault(
845+
ctx.evaluator, ExpandBodyMacroRequest{fn}, llvm::None)) {
846+
insertionLoc = ctx.SourceMgr.getRangeForBuffer(*bodyBufferID).getStart();
847+
} else {
848+
// If there is a parsed body, start at the beginning of it.
849+
SourceRange range = fn->getBodySourceRange();
850+
if (range.isValid()) {
851+
insertionLoc = range.Start;
852+
} else {
853+
insertionLoc = fn->getEndLoc();
854+
}
855+
}
856+
857+
return CharSourceRange(insertionLoc, 0);
858+
}
859+
837860
static CharSourceRange getExpansionInsertionRange(MacroRole role,
838861
ASTNode target,
839862
SourceManager &sourceMgr) {
@@ -907,15 +930,11 @@ static CharSourceRange getExpansionInsertionRange(MacroRole role,
907930
}
908931

909932
case MacroRole::Preamble: {
910-
SourceLoc inBodyLoc;
911933
if (auto fn = dyn_cast<AbstractFunctionDecl>(target.get<Decl *>())) {
912-
inBodyLoc = fn->getMacroExpandedBody()->getStartLoc();
934+
return getPreambleMacroOriginalRange(fn);
913935
}
914936

915-
if (inBodyLoc.isInvalid())
916-
inBodyLoc = target.getEndLoc();
917-
918-
return CharSourceRange(Lexer::getLocForEndOfToken(sourceMgr, inBodyLoc), 0);
937+
return CharSourceRange(Lexer::getLocForEndOfToken(sourceMgr, target.getEndLoc()), 0);
919938
}
920939

921940
case MacroRole::Body: {

lib/Sema/TypeCheckStmt.cpp

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2764,24 +2764,6 @@ static bool requiresNoDefinition(Decl *decl) {
27642764
return false;
27652765
}
27662766

2767-
/// Expand all preamble macros attached to the given function declaration.
2768-
static std::vector<ASTNode> expandPreamble(AbstractFunctionDecl *func) {
2769-
std::vector<ASTNode> preamble;
2770-
2771-
ASTContext &ctx = func->getASTContext();
2772-
ExpandPreambleMacroRequest request{func};
2773-
auto module = func->getParentModule();
2774-
for (auto bufferID : evaluateOrDefault(ctx.evaluator, request, { })) {
2775-
auto bufferStart = ctx.SourceMgr.getLocForBufferStart(bufferID);
2776-
auto preambleSF = module->getSourceFileContainingLocation(bufferStart);
2777-
preamble.insert(preamble.end(),
2778-
preambleSF->getTopLevelItems().begin(),
2779-
preambleSF->getTopLevelItems().end());
2780-
}
2781-
2782-
return preamble;
2783-
}
2784-
27852767
BraceStmt *
27862768
TypeCheckFunctionBodyRequest::evaluate(Evaluator &eval,
27872769
AbstractFunctionDecl *AFD) const {
@@ -2857,17 +2839,6 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &eval,
28572839
}
28582840
}
28592841

2860-
// Expand any preamble macros and introduce them into the body.
2861-
auto preamble = expandPreamble(AFD);
2862-
if (!preamble.empty()) {
2863-
auto newBody = std::move(preamble);
2864-
newBody.insert(
2865-
newBody.end(), body->getElements().begin(), body->getElements().end());
2866-
2867-
body = BraceStmt::create(
2868-
ctx, body->getLBraceLoc(), newBody, body->getRBraceLoc());
2869-
}
2870-
28712842
// Typechecking, in particular ApplySolution is going to replace closures
28722843
// with OpaqueValueExprs and then try to do lookups into the closures.
28732844
// So, build out the body now.

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,7 +2183,7 @@ public struct TracedPreambleMacro: PreambleMacro {
21832183
}
21842184

21852185
@_spi(ExperimentalLanguageFeature)
2186-
public struct Log2PreambleMacro: PreambleMacro {
2186+
public struct LoggerMacro: PreambleMacro {
21872187
public static func expansion(
21882188
of node: AttributeSyntax,
21892189
providingPreambleFor declaration: some DeclSyntaxProtocol & WithOptionalCodeBlockSyntax,
@@ -2203,16 +2203,19 @@ public struct Log2PreambleMacro: PreambleMacro {
22032203
let passedArgs = paramNames.map { "\($0): \\(\($0))" }.joined(separator: ", ")
22042204

22052205
let entry: CodeBlockItemSyntax = """
2206-
log2("Entering \(funcBaseName)(\(raw: passedArgs))")
2206+
logger.log(entering: "\(funcBaseName)(\(raw: passedArgs))")
22072207
"""
22082208

22092209
let argLabels = paramNames.map { "\($0):" }.joined()
22102210

22112211
let exit: CodeBlockItemSyntax = """
2212-
log2("Exiting \(funcBaseName)(\(raw: argLabels))")
2212+
logger.log(exiting: "\(funcBaseName)(\(raw: argLabels))")
22132213
"""
22142214

22152215
return [
2216+
"""
2217+
let logger = Logger()
2218+
""",
22162219
entry,
22172220
"""
22182221
defer {

test/Macros/macro_expand_body.swift

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ macro Remote() = #externalMacro(module: "MacroDefinition", type: "RemoteBodyMacr
1616
@attached(preamble)
1717
macro Traced() = #externalMacro(module: "MacroDefinition", type: "TracedPreambleMacro")
1818

19-
@attached(preamble)
20-
macro Log2() = #externalMacro(module: "MacroDefinition", type: "Log2PreambleMacro")
19+
@attached(preamble, names: named(logger))
20+
macro Logged() = #externalMacro(module: "MacroDefinition", type: "LoggerMacro")
2121

2222
protocol ConjureRemoteValue {
2323
static func conjureValue() -> Self
@@ -27,36 +27,53 @@ extension String: ConjureRemoteValue {
2727
static func conjureValue() -> String { "" }
2828
}
2929

30+
struct Logger {
31+
func log(entering function: String) {
32+
print("Logger entering \(function)")
33+
}
34+
35+
func log(_ message: String) {
36+
print("--- \(message)")
37+
}
38+
39+
func log(exiting function: String) {
40+
print("Logger exiting \(function)")
41+
}
42+
}
43+
44+
func log(_ message: String) {
45+
print(message)
46+
}
47+
3048
@available(SwiftStdlib 5.1, *)
3149
func remoteCall<Result: ConjureRemoteValue>(function: String, arguments: [String: Any]) async throws -> Result {
32-
let printedArgs = arguments.keys.sorted().map { key in
50+
let printedArgs = arguments.keys.sorted().map { key in
3351
"\(key): \(arguments[key]!)"
3452
}.joined(separator: ", ")
3553
print("Remote call \(function)(\(printedArgs))")
3654
return Result.conjureValue()
3755
}
3856

39-
func log(_ value: String) {
40-
print(value)
41-
}
42-
43-
func log2(_ value: String) {
44-
print("log2(\(value))")
45-
}
57+
@available(SwiftStdlib 5.1, *)
58+
@Remote
59+
func f(a: Int, b: String) async throws -> String
4660

4761
@Traced
4862
func doubleTheValue(value: Int) -> Int {
4963
return value * 2
5064
}
5165

52-
@available(SwiftStdlib 5.1, *)
53-
@Remote
54-
func f(a: Int, b: String) async throws -> String
66+
@Logged
67+
func useLogger() {
68+
let x = 1
69+
logger.log("use it")
70+
print(x)
71+
}
5572

5673
@available(SwiftStdlib 5.1, *)
5774
@Remote
5875
@Traced
59-
@Log2
76+
@Logged
6077
func g(a: Int, b: String) async throws -> String {
6178
doesNotTypeCheck()
6279
}
@@ -80,9 +97,14 @@ if #available(SwiftStdlib 5.1, *) {
8097
print(try await f(a: 5, b: "Hello"))
8198

8299
// CHECK: Entering g(a: 5, b: World)
83-
// CHECK: log2(Entering g(a: 5, b: World))
100+
// CHECK: Logger entering g(a: 5, b: World)
84101
// CHECK: Remote call g(a: 5, b: World)
85-
// CHECK: log2(Exiting g(a:b:))
102+
// CHECK: Logger exiting g(a:b:)
86103
// CHECK: Exiting g(a:b:)
87104
print(try await g(a: 5, b: "World"))
88105
}
106+
107+
// CHECK: Logger entering useLogger()
108+
// CHECK: --- use it
109+
// CHECK: Logger exiting useLogger()
110+
useLogger()

0 commit comments

Comments
 (0)