Skip to content

Commit 822fd47

Browse files
CodaFiDougGregor
authored andcommitted
Add Utilities to Retrieve the (Opened) Type of a Macro Reference
1 parent dddda9d commit 822fd47

File tree

10 files changed

+267
-51
lines changed

10 files changed

+267
-51
lines changed

include/swift/AST/ASTContext.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ namespace swift {
124124
class DiagnosticEngine;
125125
struct RawComment;
126126
class DocComment;
127+
class StructDecl;
127128
class SILBoxType;
128129
class SILTransform;
129130
class TypeAliasDecl;
@@ -1435,6 +1436,14 @@ class ASTContext final {
14351436
/// The declared interface type of Builtin.TheTupleType.
14361437
BuiltinTupleType *getBuiltinTupleType();
14371438

1439+
/// Look up a macro's evaluation context by name.
1440+
///
1441+
/// If no such macro or evaluation context is found under this name, this
1442+
/// method returns \c nullptr.
1443+
StructDecl *getOrCreateASTGenMacroContext(
1444+
StringRef macroName,
1445+
llvm::function_ref<StructDecl *(StringRef)> createMacro);
1446+
14381447
private:
14391448
friend Decl;
14401449

include/swift/AST/CASTBridging.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ void TopLevelCodeDecl_dump(void *);
191191
void Expr_dump(void *);
192192
void Decl_dump(void *);
193193
void Stmt_dump(void *);
194-
void TypeRepr_dump(void *);
195194

196195
#ifdef __cplusplus
197196
}

include/swift/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4906,6 +4906,12 @@ class ConstraintSystem {
49064906
ConstraintLocator *locator,
49074907
OpenedTypeMap *replacements = nullptr);
49084908

4909+
/// Retrieve the opened type of a macro with the given name.
4910+
///
4911+
/// \returns The opened type of the macro with this name, or the null \c Type
4912+
/// if no such macro exists.
4913+
Type getTypeOfMacroReference(StringRef macro, Expr *anchor);
4914+
49094915
/// Retrieve a list of generic parameter types solver has "opened" (replaced
49104916
/// with a type variable) at the given location.
49114917
ArrayRef<OpenedType> getOpenedTypes(ConstraintLocator *locator) const {

lib/AST/ASTContext.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,9 @@ struct ASTContext::Implementation {
394394
/// is populated if the body is reparsed from other source buffers.
395395
llvm::DenseMap<const AbstractFunctionDecl *, SourceRange> OriginalBodySourceRanges;
396396

397+
/// A mapping of all the registered ASTGen macros keyed by name.
398+
llvm::StringMap<StructDecl *> ASTGenMacros;
399+
397400
/// Structure that captures data that is segregated into different
398401
/// arenas.
399402
struct Arena {
@@ -6032,3 +6035,17 @@ BuiltinTupleType *ASTContext::getBuiltinTupleType() {
60326035

60336036
return result;
60346037
}
6038+
6039+
StructDecl *ASTContext::getOrCreateASTGenMacroContext(
6040+
StringRef macroName,
6041+
llvm::function_ref<StructDecl *(StringRef)> createMacro) {
6042+
auto &impl = getImpl();
6043+
auto found = impl.ASTGenMacros.find(macroName);
6044+
if (found != impl.ASTGenMacros.end()) {
6045+
return found->second;
6046+
} else {
6047+
auto macroAndContext = createMacro(macroName);
6048+
impl.ASTGenMacros.insert({macroName, macroAndContext});
6049+
return macroAndContext;
6050+
}
6051+
}

lib/AST/CASTBridging.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,4 +458,3 @@ void TopLevelCodeDecl_dump(void *decl) { ((TopLevelCodeDecl *)decl)->dump(llvm::
458458
void Expr_dump(void *expr) { ((Expr *)expr)->dump(llvm::errs()); }
459459
void Decl_dump(void *expr) { ((Decl *)expr)->dump(llvm::errs()); }
460460
void Stmt_dump(void *expr) { ((Stmt *)expr)->dump(llvm::errs()); }
461-
void TypeRepr_dump(void *repr) { ((TypeRepr *)repr)->dump(); }

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,106 @@ extension SyntaxProtocol {
2020
}
2121
}
2222

23+
/// Describes a macro that has been "exported" to the C++ part of the
24+
/// compiler, with enough information to interface with the C++ layer.
25+
struct ExportedMacro {
26+
var macro: Macro.Type
27+
}
28+
29+
/// Look up a macro with the given name.
30+
///
31+
/// Returns an unmanaged pointer to an ExportedMacro instance that describes
32+
/// the specified macro. If there is no macro with the given name, produces
33+
/// nil.
34+
@_cdecl("swift_ASTGen_lookupMacro")
35+
public func lookupMacro(
36+
macroNamePtr: UnsafePointer<UInt8>
37+
) -> UnsafeRawPointer? {
38+
let macroSystem = MacroSystem.exampleSystem
39+
40+
// Look for a macro with this name.
41+
let macroName = String(cString: macroNamePtr)
42+
guard let macro = macroSystem.lookup(macroName) else { return nil }
43+
44+
// Allocate and initialize the exported macro.
45+
let exportedPtr = UnsafeMutablePointer<ExportedMacro>.allocate(capacity: 1)
46+
exportedPtr.initialize(to: .init(macro: macro))
47+
return UnsafeRawPointer(exportedPtr)
48+
}
49+
50+
/// Destroys the given macro.
51+
@_cdecl("swift_ASTGen_destroyMacro")
52+
public func destroyMacro(
53+
macroPtr: UnsafeMutablePointer<UInt8>
54+
) {
55+
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
56+
macro.deinitialize(count: 1)
57+
macro.deallocate()
58+
}
59+
}
60+
61+
/// Allocate a copy of the given string as a UTF-8 string.
62+
private func allocateUTF8String(
63+
_ string: String,
64+
nullTerminated: Bool = false
65+
) -> (UnsafePointer<UInt8>, Int) {
66+
var string = string
67+
return string.withUTF8 { utf8 in
68+
let capacity = utf8.count + (nullTerminated ? 1 : 0)
69+
let ptr = UnsafeMutablePointer<UInt8>.allocate(
70+
capacity: capacity
71+
)
72+
if let baseAddress = utf8.baseAddress {
73+
ptr.initialize(from: baseAddress, count: utf8.count)
74+
}
75+
76+
if nullTerminated {
77+
ptr[utf8.count] = 0
78+
}
79+
80+
return (UnsafePointer<UInt8>(ptr), capacity)
81+
}
82+
}
83+
84+
/// Query the type signature of the given macro.
85+
@_cdecl("swift_ASTGen_getMacroTypeSignature")
86+
public func getMacroTypeSignature(
87+
macroPtr: UnsafeMutablePointer<UInt8>,
88+
evaluationContextPtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
89+
evaluationContextLengthPtr: UnsafeMutablePointer<Int>
90+
) {
91+
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
92+
(evaluationContextPtr.pointee, evaluationContextLengthPtr.pointee) =
93+
allocateUTF8String(macro.pointee.evaluationContext, nullTerminated: true)
94+
}
95+
}
96+
97+
extension ExportedMacro {
98+
var evaluationContext: String {
99+
"""
100+
struct __MacroEvaluationContext\(self.macro.genericSignature?.description ?? "") {
101+
typealias SignatureType = \(self.macro.signature)
102+
}
103+
"""
104+
}
105+
}
106+
107+
/// Query the macro evaluation context of the given macro.
108+
@_cdecl("swift_ASTGen_getMacroEvaluationContext")
109+
public func getMacroEvaluationContext(
110+
sourceFilePtr: UnsafePointer<UInt8>,
111+
declContext: UnsafeMutableRawPointer,
112+
context: UnsafeMutableRawPointer,
113+
macroPtr: UnsafeMutablePointer<UInt8>,
114+
contextPtr: UnsafeMutablePointer<UnsafeMutableRawPointer?>
115+
) {
116+
contextPtr.pointee = macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
117+
return ASTGenVisitor(ctx: context, base: sourceFilePtr, declContext: declContext)
118+
.visit(StructDeclSyntax(stringLiteral: macro.pointee.evaluationContext))
119+
}
120+
}
121+
122+
23123
@_cdecl("swift_ASTGen_evaluateMacro")
24124
public func evaluateMacro(
25125
sourceFilePtr: UnsafePointer<UInt8>,

lib/Sema/CSGen.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
//===----------------------------------------------------------------------===//
1616
#include "TypeCheckConcurrency.h"
1717
#include "TypeCheckDecl.h"
18-
#include "TypeCheckType.h"
18+
#include "TypeCheckMacros.h"
1919
#include "TypeCheckRegex.h"
20+
#include "TypeCheckType.h"
2021
#include "TypeChecker.h"
2122
#include "swift/AST/ASTVisitor.h"
2223
#include "swift/AST/ASTWalker.h"
@@ -1188,6 +1189,30 @@ namespace {
11881189
}
11891190

11901191
Type visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *expr) {
1192+
#ifdef SWIFT_SWIFT_PARSER
1193+
auto &ctx = CS.getASTContext();
1194+
if (ctx.LangOpts.hasFeature(Feature::BuiltinMacros)) {
1195+
auto kind = MagicIdentifierLiteralExpr::getKindString(expr->getKind())
1196+
.drop_front();
1197+
1198+
auto protocol =
1199+
TypeChecker::getLiteralProtocol(CS.getASTContext(), expr);
1200+
if (!protocol)
1201+
return Type();
1202+
1203+
auto openedType = CS.getTypeOfMacroReference(kind, expr);
1204+
if (!openedType)
1205+
return Type();
1206+
1207+
CS.addConstraint(ConstraintKind::LiteralConformsTo, openedType,
1208+
protocol->getDeclaredInterfaceType(),
1209+
CS.getConstraintLocator(expr));
1210+
1211+
return openedType;
1212+
}
1213+
// Fall through to use old implementation.
1214+
#endif
1215+
11911216
switch (expr->getKind()) {
11921217
// Magic pointer identifiers are of type UnsafeMutableRawPointer.
11931218
#define MAGIC_POINTER_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
@@ -3603,7 +3628,17 @@ namespace {
36033628
}
36043629

36053630
Type visitMacroExpansionExpr(MacroExpansionExpr *expr) {
3606-
// FIXME: not implemented
3631+
#if SWIFT_SWIFT_PARSER
3632+
auto &ctx = CS.getASTContext();
3633+
if (ctx.LangOpts.hasFeature(Feature::BuiltinMacros)) {
3634+
auto *UDRE = dyn_cast<UnresolvedDeclRefExpr>(expr->getMacro());
3635+
if (!UDRE)
3636+
return Type();
3637+
3638+
auto macroIdent = UDRE->getName().getBaseIdentifier();
3639+
return CS.getTypeOfMacroReference(macroIdent.str(), expr);
3640+
}
3641+
#endif
36073642
return Type();
36083643
}
36093644

lib/Sema/ConstraintSystem.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,22 @@
1515
// inference for expressions.
1616
//
1717
//===----------------------------------------------------------------------===//
18+
#include "swift/Sema/ConstraintSystem.h"
1819
#include "CSDiagnostics.h"
19-
#include "TypeChecker.h"
2020
#include "TypeCheckAvailability.h"
2121
#include "TypeCheckConcurrency.h"
22+
#include "TypeCheckMacros.h"
2223
#include "TypeCheckType.h"
23-
#include "swift/AST/Initializer.h"
24+
#include "TypeChecker.h"
2425
#include "swift/AST/GenericEnvironment.h"
26+
#include "swift/AST/Initializer.h"
2527
#include "swift/AST/ParameterList.h"
2628
#include "swift/AST/ProtocolConformance.h"
2729
#include "swift/AST/TypeCheckRequests.h"
2830
#include "swift/Basic/Defer.h"
2931
#include "swift/Basic/Statistic.h"
3032
#include "swift/Sema/CSFix.h"
3133
#include "swift/Sema/ConstraintGraph.h"
32-
#include "swift/Sema/ConstraintSystem.h"
3334
#include "swift/Sema/SolutionResult.h"
3435
#include "llvm/ADT/SetVector.h"
3536
#include "llvm/ADT/SmallSet.h"
@@ -2470,6 +2471,27 @@ ConstraintSystem::getTypeOfMemberReference(
24702471
return { origOpenedType, openedType, origType, type };
24712472
}
24722473

2474+
Type ConstraintSystem::getTypeOfMacroReference(StringRef macroName,
2475+
Expr *anchor) {
2476+
auto macroCtx = swift::macro_context::lookup(macroName, DC);
2477+
if (!macroCtx)
2478+
return Type();
2479+
2480+
auto *locator = getConstraintLocator(anchor);
2481+
// Dig through to __MacroEvaluationContext.SignatureType
2482+
auto sig = getASTContext().getIdentifier("SignatureType");
2483+
auto *signature = macroCtx->lookupDirect(sig).front();
2484+
auto type = cast<TypeAliasDecl>(signature)->getUnderlyingType();
2485+
2486+
// Open up the generic type.
2487+
OpenedTypeMap replacements;
2488+
openGeneric(cast<TypeAliasDecl>(signature)->getParent(),
2489+
cast<TypeAliasDecl>(signature)->getGenericSignature(), locator,
2490+
replacements);
2491+
2492+
return openType(type, replacements);
2493+
}
2494+
24732495
Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
24742496
const OverloadChoice &overload,
24752497
bool allowMembers,

lib/Sema/TypeCheckMacros.cpp

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,36 +29,66 @@ extern "C" void *swift_ASTGen_lookupMacro(const char *macroName);
2929

3030
extern "C" void swift_ASTGen_destroyMacro(void *macro);
3131

32-
extern "C" void swift_ASTGen_getMacroTypeSignature(
33-
void *sourceFile, void *declContext, void *astContext, void *macro,
34-
void **genericSignature,
35-
void **signature);
32+
extern "C" void
33+
swift_ASTGen_getMacroEvaluationContext(const void *sourceFile,
34+
void *declContext, void *astContext,
35+
void *macro, void **evaluationContext);
3636

3737
extern "C" ptrdiff_t swift_ASTGen_evaluateMacro(
3838
void *sourceFile, const void *sourceLocation,
3939
const char **evaluatedSource, ptrdiff_t *evaluatedSourceLength);
4040

41+
extern "C" void
42+
swift_ASTGen_getMacroTypeSignature(void *macro, const char **genericSignature,
43+
ptrdiff_t *genericSignatureLength);
44+
4145
#if SWIFT_SWIFT_PARSER
4246

43-
llvm::Optional<ASTGenMacroRAII> ASTGenMacroRAII::lookup(StringRef macroName,
44-
void *sourceFile,
45-
DeclContext *DC,
46-
ASTContext &ctx) {
47-
auto *macro = swift_ASTGen_lookupMacro(macroName.str().c_str());
48-
if (!macro)
49-
return None;
50-
51-
void *genericParamList = nullptr;
52-
void *signatureAST = nullptr;
53-
swift_ASTGen_getMacroTypeSignature(sourceFile, (void *)DC, (void *)&ctx,
54-
macro, &genericParamList,
55-
&signatureAST);
56-
57-
return ASTGenMacroRAII{macro, (TypeRepr *)signatureAST,
58-
(GenericParamList *)genericParamList};
47+
StructDecl *
48+
swift::macro_context::lookup(StringRef macroName, DeclContext *DC) {
49+
auto &ctx = DC->getASTContext();
50+
51+
return ctx.getOrCreateASTGenMacroContext(
52+
macroName, [&](StringRef macroName) -> StructDecl * {
53+
auto *macro = swift_ASTGen_lookupMacro(macroName.str().c_str());
54+
if (!macro)
55+
return nullptr;
56+
57+
const char *evaluatedSource;
58+
ptrdiff_t evaluatedSourceLength;
59+
swift_ASTGen_getMacroTypeSignature(macro, &evaluatedSource,
60+
&evaluatedSourceLength);
61+
62+
// Create a new source buffer with the contents of the macro's
63+
// signature.
64+
SourceManager &sourceMgr = ctx.SourceMgr;
65+
std::string bufferName;
66+
{
67+
llvm::raw_string_ostream out(bufferName);
68+
out << "Macro signature of #" << macroName;
69+
}
70+
auto macroBuffer = llvm::MemoryBuffer::getMemBuffer(
71+
StringRef(evaluatedSource, evaluatedSourceLength), bufferName);
72+
unsigned macroBufferID =
73+
sourceMgr.addNewSourceBuffer(std::move(macroBuffer));
74+
auto macroSourceFile = new (ctx) SourceFile(
75+
*DC->getParentModule(), SourceFileKind::Library, macroBufferID);
76+
// Make sure implicit imports are resolved in this file.
77+
performImportResolution(*macroSourceFile);
78+
79+
auto *start = sourceMgr.getLocForBufferStart(macroBufferID)
80+
.getOpaquePointerValue();
81+
void *context = nullptr;
82+
swift_ASTGen_getMacroEvaluationContext(
83+
(const void *)start, (void *)(DeclContext *)macroSourceFile,
84+
(void *)&ctx, macro, &context);
85+
86+
ctx.addCleanup([macro]() { swift_ASTGen_destroyMacro(macro); });
87+
return dyn_cast<StructDecl>((Decl *)context);
88+
});
5989
}
6090

61-
ASTGenMacroRAII::~ASTGenMacroRAII() { /*swift_ASTGen_destroyMacro(opaqueMacro);*/ }
91+
#endif // SWIFT_SWIFT_PARSER
6292

6393
Expr *swift::expandMacroExpr(
6494
DeclContext *dc, Expr *expr, StringRef macroName, Type expandedType
@@ -152,5 +182,3 @@ Expr *swift::expandMacroExpr(
152182
"Type checking changed the result type?");
153183
return expandedExpr;
154184
}
155-
156-
#endif // SWIFT_SWIFT_PARSER

0 commit comments

Comments
 (0)