Skip to content

Commit f1742fd

Browse files
committed
[Macros] Initial implementation for synthesized member macro expansion.
1 parent 8b9be30 commit f1742fd

File tree

9 files changed

+271
-7
lines changed

9 files changed

+271
-7
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3856,6 +3856,23 @@ class ExpandMemberAttributeMacros
38563856
bool isCached() const { return true; }
38573857
};
38583858

3859+
/// Expand synthesized member macros attached to the given declaration.
3860+
class ExpandSynthesizedMemberMacroRequest
3861+
: public SimpleRequest<ExpandSynthesizedMemberMacroRequest,
3862+
bool(Decl *),
3863+
RequestFlags::Cached> {
3864+
public:
3865+
using SimpleRequest::SimpleRequest;
3866+
3867+
private:
3868+
friend SimpleRequest;
3869+
3870+
bool evaluate(Evaluator &evaluator, Decl *decl) const;
3871+
3872+
public:
3873+
bool isCached() const { return true; }
3874+
};
3875+
38593876
/// Resolve an external macro given its module and type name.
38603877
class ExternalMacroDefinitionRequest
38613878
: public SimpleRequest<ExternalMacroDefinitionRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,9 @@ SWIFT_REQUEST(TypeChecker, ExpandMacroExpansionDeclRequest,
458458
SWIFT_REQUEST(TypeChecker, ExpandMemberAttributeMacros,
459459
bool(Decl *),
460460
Cached, NoLocationInfo)
461+
SWIFT_REQUEST(TypeCHecker, ExpandSynthesizedMemberMacroRequest,
462+
bool(Decl *),
463+
Cached, NoLocationInfo)
461464
SWIFT_REQUEST(TypeChecker, SynthesizeRuntimeMetadataAttrGenerator,
462465
Expr *(CustomAttr *, ValueDecl *),
463466
Cached, NoLocationInfo)

lib/AST/ASTVerifier.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3654,12 +3654,13 @@ class Verifier : public ASTWalker {
36543654
void checkSourceRanges(Decl *D) {
36553655
PrettyStackTraceDecl debugStack("verifying ranges", D);
36563656
const auto SR = D->getSourceRange();
3657+
3658+
// We don't care about source ranges on implicitly-generated
3659+
// decls.
3660+
if (D->isImplicit())
3661+
return;
3662+
36573663
if (!SR.isValid()) {
3658-
// We don't care about source ranges on implicitly-generated
3659-
// decls.
3660-
if (D->isImplicit())
3661-
return;
3662-
36633664
Out << "invalid source range for decl: ";
36643665
D->print(Out);
36653666
Out << "\n";

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,18 @@ func expandAttachedMacro(
344344
$0.withoutTrivia().description
345345
}.joined(separator: " ")
346346

347+
case let attachedMacro as MemberDeclarationMacro.Type:
348+
let members = try attachedMacro.expansion(
349+
of: customAttrNode,
350+
attachedTo: declarationNode,
351+
in: &context
352+
)
353+
354+
// Form a buffer of member declarations to return to the caller.
355+
evaluatedSyntaxStr = members.map {
356+
$0.withoutTrivia().description
357+
}.joined(separator: "\n\n")
358+
347359
default:
348360
print("\(macroPtr) does not conform to any known attached macro protocol")
349361
return 1

lib/Sema/TypeCheckMacros.cpp

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,31 @@ bool ExpandMemberAttributeMacros::evaluate(Evaluator &evaluator,
338338
return addedAttributes;
339339
}
340340

341+
bool ExpandSynthesizedMemberMacroRequest::evaluate(Evaluator &evaluator,
342+
Decl *decl) const {
343+
auto &ctx = decl->getASTContext();
344+
auto *dc = decl->getInnermostDeclContext();
345+
bool synthesizedMembers = false;
346+
347+
for (auto customAttrConst : decl->getSemanticAttrs().getAttributes<CustomAttr>()) {
348+
auto customAttr = const_cast<CustomAttr *>(customAttrConst);
349+
auto *macroDecl = evaluateOrDefault(
350+
ctx.evaluator,
351+
ResolveAttachedMacroRequest{customAttr, dc},
352+
nullptr);
353+
354+
if (!macroDecl)
355+
continue;
356+
357+
if (!macroDecl->getMacroRoles().contains(MacroRole::SynthesizedMembers))
358+
continue;
359+
360+
// Expand the synthesized members.
361+
synthesizedMembers |= expandSynthesizedMembers(customAttr, macroDecl, decl);
362+
}
363+
364+
return synthesizedMembers;
365+
}
341366

342367
/// Determine whether the given source file is from an expansion of the given
343368
/// macro.
@@ -1082,6 +1107,181 @@ bool swift::expandAttributes(CustomAttr *attr, MacroDecl *macro, Decl *member) {
10821107
return addedAttributes;
10831108
}
10841109

1110+
bool swift::expandSynthesizedMembers(CustomAttr *attr, MacroDecl *macro,
1111+
Decl *decl) {
1112+
auto *dc = decl->getInnermostDeclContext();
1113+
ASTContext &ctx = dc->getASTContext();
1114+
SourceManager &sourceMgr = ctx.SourceMgr;
1115+
auto moduleDecl = dc->getParentModule();
1116+
1117+
auto attrSourceFile =
1118+
moduleDecl->getSourceFileContainingLocation(attr->AtLoc);
1119+
if (!attrSourceFile)
1120+
return false;
1121+
1122+
auto declSourceFile =
1123+
moduleDecl->getSourceFileContainingLocation(decl->getStartLoc());
1124+
if (!declSourceFile)
1125+
return false;
1126+
1127+
// Evaluate the macro.
1128+
NullTerminatedStringRef evaluatedSource;
1129+
1130+
if (isFromExpansionOfMacro(attrSourceFile, macro) ||
1131+
isFromExpansionOfMacro(declSourceFile, macro)) {
1132+
decl->diagnose(diag::macro_recursive, macro->getName());
1133+
return false;
1134+
}
1135+
1136+
auto macroDef = macro->getDefinition();
1137+
switch (macroDef.kind) {
1138+
case MacroDefinition::Kind::Undefined:
1139+
case MacroDefinition::Kind::Invalid:
1140+
// Already diagnosed as an error elsewhere.
1141+
return false;
1142+
1143+
case MacroDefinition::Kind::Builtin: {
1144+
switch (macroDef.getBuiltinKind()) {
1145+
case BuiltinMacroKind::ExternalMacro:
1146+
// FIXME: Error here.
1147+
return false;
1148+
}
1149+
}
1150+
1151+
case MacroDefinition::Kind::External: {
1152+
// Retrieve the external definition of the macro.
1153+
auto external = macroDef.getExternalMacro();
1154+
ExternalMacroDefinitionRequest request{
1155+
&ctx, external.moduleName, external.macroTypeName
1156+
};
1157+
auto externalDef = evaluateOrDefault(
1158+
ctx.evaluator, request, ExternalMacroDefinition()
1159+
);
1160+
if (!externalDef.opaqueHandle) {
1161+
decl->diagnose(diag::external_macro_not_found,
1162+
external.moduleName.str(),
1163+
external.macroTypeName.str(),
1164+
macro->getName()
1165+
);
1166+
macro->diagnose(diag::decl_declared_here, macro->getName());
1167+
return false;
1168+
}
1169+
1170+
// Make sure macros are enabled before we expand.
1171+
if (!ctx.LangOpts.hasFeature(Feature::Macros)) {
1172+
decl->diagnose(diag::macro_experimental);
1173+
return false;
1174+
}
1175+
1176+
#if SWIFT_SWIFT_PARSER
1177+
PrettyStackTraceDecl debugStack("expanding attribute macro", decl);
1178+
1179+
auto astGenAttrSourceFile = attrSourceFile->exportedSourceFile;
1180+
if (!astGenAttrSourceFile)
1181+
return false;
1182+
1183+
auto astGenDeclSourceFile = declSourceFile->exportedSourceFile;
1184+
if (!astGenDeclSourceFile)
1185+
return false;
1186+
1187+
const char *evaluatedSourceAddress;
1188+
ptrdiff_t evaluatedSourceLength;
1189+
swift_ASTGen_expandAttachedMacro(
1190+
&ctx.Diags,
1191+
externalDef.opaqueHandle,
1192+
astGenAttrSourceFile, attr->AtLoc.getOpaquePointerValue(),
1193+
astGenDeclSourceFile, decl->getStartLoc().getOpaquePointerValue(),
1194+
/*parentDeclSourceFile*/nullptr, /*parentDeclLoc*/nullptr,
1195+
&evaluatedSourceAddress, &evaluatedSourceLength);
1196+
if (!evaluatedSourceAddress)
1197+
return false;
1198+
evaluatedSource = NullTerminatedStringRef(evaluatedSourceAddress,
1199+
(size_t)evaluatedSourceLength);
1200+
break;
1201+
#else
1202+
decl->diagnose(diag::macro_unsupported);
1203+
return false;
1204+
#endif
1205+
}
1206+
}
1207+
1208+
// Figure out a reasonable name for the macro expansion buffer.
1209+
std::string bufferName;
1210+
{
1211+
llvm::raw_string_ostream out(bufferName);
1212+
1213+
out << "macro:"
1214+
<< "@" << macro->getName().getBaseName();
1215+
if (auto bufferID = declSourceFile->getBufferID()) {
1216+
unsigned startLine, startColumn;
1217+
std::tie(startLine, startColumn) =
1218+
sourceMgr.getLineAndColumnInBuffer(decl->getStartLoc(), *bufferID);
1219+
1220+
SourceLoc endLoc =
1221+
Lexer::getLocForEndOfToken(sourceMgr, decl->getEndLoc());
1222+
unsigned endLine, endColumn;
1223+
std::tie(endLine, endColumn) =
1224+
sourceMgr.getLineAndColumnInBuffer(endLoc, *bufferID);
1225+
1226+
out << ":" << sourceMgr.getIdentifierForBuffer(*bufferID) << ":"
1227+
<< startLine << ":" << startColumn
1228+
<< "-" << endLine << ":" << endColumn;
1229+
}
1230+
}
1231+
1232+
// Dump macro expansions to standard output, if requested.
1233+
if (ctx.LangOpts.DumpMacroExpansions) {
1234+
llvm::errs() << bufferName
1235+
<< "\n------------------------------\n"
1236+
<< evaluatedSource
1237+
<< "\n------------------------------\n";
1238+
}
1239+
1240+
// Create a new source buffer with the contents of the expanded macro.
1241+
auto macroBuffer =
1242+
llvm::MemoryBuffer::getMemBufferCopy(evaluatedSource, bufferName);
1243+
unsigned macroBufferID = sourceMgr.addNewSourceBuffer(std::move(macroBuffer));
1244+
auto macroBufferRange = sourceMgr.getRangeForBuffer(macroBufferID);
1245+
GeneratedSourceInfo sourceInfo{
1246+
GeneratedSourceInfo::SynthesizedMemberMacroExpansion,
1247+
decl->getEndLoc(),
1248+
SourceRange(macroBufferRange.getStart(), macroBufferRange.getEnd()),
1249+
ASTNode(decl).getOpaqueValue(),
1250+
dc,
1251+
attr
1252+
};
1253+
sourceMgr.setGeneratedSourceInfo(macroBufferID, sourceInfo);
1254+
free((void*)evaluatedSource.data());
1255+
1256+
// Create a source file to hold the macro buffer. This is automatically
1257+
// registered with the enclosing module.
1258+
auto macroSourceFile = new (ctx) SourceFile(
1259+
*dc->getParentModule(), SourceFileKind::MacroExpansion, macroBufferID,
1260+
/*parsingOpts=*/{}, /*isPrimary=*/false);
1261+
macroSourceFile->setImports(declSourceFile->getImports());
1262+
1263+
PrettyStackTraceDecl debugStack(
1264+
"type checking expanded declaration macro", decl);
1265+
1266+
bool synthesizedMembers = false;
1267+
auto topLevelDecls = macroSourceFile->getTopLevelDecls();
1268+
for (auto member : topLevelDecls) {
1269+
member->setDeclContext(decl->getInnermostDeclContext());
1270+
member->setImplicit();
1271+
1272+
if (auto *nominal = dyn_cast<NominalTypeDecl>(decl)) {
1273+
nominal->addMember(member);
1274+
} else if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
1275+
extension->addMember(member);
1276+
}
1277+
1278+
TypeChecker::typeCheckDecl(member);
1279+
synthesizedMembers = true;
1280+
}
1281+
1282+
return synthesizedMembers;
1283+
}
1284+
10851285
MacroDecl *
10861286
ResolveAttachedMacroRequest::evaluate(Evaluator &evaluator,
10871287
CustomAttr *attr,

lib/Sema/TypeCheckMacros.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ void expandAccessors(
5353
/// on the custom attribute that references the given macro.
5454
bool expandAttributes(CustomAttr *attr, MacroDecl *macro, Decl *member);
5555

56+
/// Expand the synthesized members for the given declaration based on
57+
/// the custom attribute that references the given macro.
58+
///
59+
/// Returns \c true if the macro added new synthesized members, \c false
60+
/// otherwise.
61+
bool expandSynthesizedMembers(CustomAttr *attr, MacroDecl *macro, Decl *decl);
62+
5663
} // end namespace swift
5764

5865
#endif /* SWIFT_SEMA_TYPECHECKMACROS_H */

lib/Sema/TypeCheckStorage.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ static void computeLoweredStoredProperties(NominalTypeDecl *decl,
113113
if (decl->hasTypeWrapper())
114114
(void)decl->getTypeWrapperProperty();
115115

116+
// Expand synthesized member macros.
117+
// FIXME: Member macros can add members other than stored properties.
118+
auto &ctx = decl->getASTContext();
119+
evaluateOrDefault(ctx.evaluator,
120+
ExpandSynthesizedMemberMacroRequest{decl},
121+
false);
122+
116123
// Just walk over the members of the type, forcing backing storage
117124
// for lazy properties and property wrappers to be synthesized.
118125
for (auto *member : implDecl->getMembers()) {

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,20 @@ public struct AccessViaStorageMacro: AccessorDeclarationMacro {
327327
]
328328
}
329329
}
330+
331+
public struct TypeWrapperStorageMacro: MemberDeclarationMacro {
332+
public static func expansion(
333+
of node: AttributeSyntax,
334+
attachedTo decl: DeclSyntax,
335+
in context: inout MacroExpansionContext
336+
) throws -> [DeclSyntax] {
337+
let storageVariable: VariableDeclSyntax =
338+
"""
339+
private var _storage = _Storage()
340+
"""
341+
342+
return [
343+
DeclSyntax(storageVariable),
344+
]
345+
}
346+
}

test/Macros/composed_macro.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// REQUIRES: OS=macosx
1111

1212
@attached(memberAttributes) macro myTypeWrapper() = #externalMacro(module: "MacroDefinition", type: "TypeWrapperMacro")
13+
@attached(synthesizedMembers) macro typeWrapperStorage() = #externalMacro(module: "MacroDefinition", type: "TypeWrapperStorageMacro")
1314
@attached(accessor) macro accessViaStorage() = #externalMacro(module: "MacroDefinition", type: "AccessViaStorageMacro")
1415

1516
struct _Storage {
@@ -21,10 +22,9 @@ struct _Storage {
2122
}
2223
}
2324

25+
@typeWrapperStorage
2426
@myTypeWrapper
2527
struct S {
26-
var _storage = _Storage()
27-
2828
var x: Int
2929
var y: Int
3030
}

0 commit comments

Comments
 (0)