Skip to content

Commit 6cd0327

Browse files
authored
Merge pull request #61691 from DougGregor/macros-expand-and-type-check
2 parents ffc6152 + 414ef86 commit 6cd0327

File tree

8 files changed

+203
-25
lines changed

8 files changed

+203
-25
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6666,5 +6666,12 @@ ERROR(experimental_no_metadata_feature_can_only_be_used_when_enabled,
66666666
" -enable-experimental-feature LayoutPrespecialization to swift to enable "
66676667
" the usage of this language feature", ())
66686668

6669+
6670+
//------------------------------------------------------------------------------
6671+
// MARK: Macros
6672+
//------------------------------------------------------------------------------
6673+
ERROR(expected_macro_expansion_expr,PointsToFirstBadToken,
6674+
"expected macro expansion to produce an expression", ())
6675+
66696676
#define UNDEFINE_DIAGNOSTIC_MACROS
66706677
#include "DefineDiagnosticMacros.h"

lib/AST/ASTDumper.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2982,6 +2982,10 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
29822982
OS << '\n';
29832983
printArgumentList(E->getArgs());
29842984
}
2985+
if (auto rewritten = E->getRewritten()) {
2986+
OS << '\n';
2987+
printRec(rewritten);
2988+
}
29852989
PrintWithColorRAII(OS, ParenthesisColor) << ')';
29862990
}
29872991
};

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public func evaluateMacro(
8383
evaluatedResultPtr[utf8.count] = 0
8484

8585
expandedSourcePointer.pointee = UnsafePointer(evaluatedResultPtr)
86-
expandedSourceLength.pointee = utf8.count + 1
86+
expandedSourceLength.pointee = utf8.count
8787
}
8888

8989
return 0

lib/Sema/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ add_swift_host_library(swiftSema STATIC
5858
TypeCheckExpr.cpp
5959
TypeCheckExprObjC.cpp
6060
TypeCheckGeneric.cpp
61+
TypeCheckMacros.cpp
6162
TypeCheckNameLookup.cpp
6263
TypeCheckPattern.cpp
6364
TypeCheckPropertyWrapper.cpp

lib/Sema/CSApply.cpp

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "CodeSynthesis.h"
2121
#include "MiscDiagnostics.h"
2222
#include "TypeCheckConcurrency.h"
23+
#include "TypeCheckMacros.h"
2324
#include "TypeCheckProtocol.h"
2425
#include "TypeCheckType.h"
2526
#include "swift/AST/ASTVisitor.h"
@@ -54,10 +55,6 @@
5455
using namespace swift;
5556
using namespace constraints;
5657

57-
extern "C" ptrdiff_t swift_ASTGen_evaluateMacro(
58-
void *sourceFile, const void *sourceLocation,
59-
const char **evaluatedSource, ptrdiff_t *evaluatedSourceLength);
60-
6158
bool Solution::hasFixedType(TypeVariableType *typeVar) const {
6259
auto knownBinding = typeBindings.find(typeVar);
6360
return knownBinding != typeBindings.end();
@@ -2977,22 +2974,19 @@ namespace {
29772974
#if SWIFT_SWIFT_PARSER
29782975
auto &ctx = cs.getASTContext();
29792976
if (ctx.LangOpts.hasFeature(Feature::BuiltinMacros)) {
2980-
if (auto sf = dc->getParentSourceFile()) {
2981-
if (auto astGenSF = sf->exportedSourceFile) {
2982-
const char *evaluatedSource;
2983-
ptrdiff_t evaluatedSourceLength;
2984-
swift_ASTGen_evaluateMacro(
2985-
astGenSF, expr->getStartLoc().getOpaquePointerValue(),
2986-
&evaluatedSource, &evaluatedSourceLength);
2987-
if (evaluatedSource) {
2988-
llvm::outs() << "Macro rewrite: "
2989-
<< MagicIdentifierLiteralExpr::getKindString(expr->getKind())
2990-
<< " --> " << StringRef(evaluatedSource, evaluatedSourceLength)
2991-
<< "\n";
2992-
free((void*)evaluatedSource);
2993-
}
2994-
}
2977+
auto kind = MagicIdentifierLiteralExpr::getKindString(expr->getKind())
2978+
.drop_front();
2979+
auto expandedType = solution.simplifyType(solution.getType(expr));
2980+
if (auto newExpr = expandMacroExpr(dc, expr, kind, expandedType)) {
2981+
auto expansion = new (ctx) MacroExpansionExpr(
2982+
expr->getStartLoc(), expr, nullptr, /*isImplicit=*/true,
2983+
expandedType);
2984+
expansion->setRewritten(newExpr);
2985+
cs.cacheExprTypes(expansion);
2986+
return expansion;
29952987
}
2988+
2989+
// Fall through to use old implementation.
29962990
}
29972991
#endif
29982992

lib/Sema/TypeCheckMacros.cpp

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
//===--- TypeCheckMacros.cpp - Macro Handling ----------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file implements support for the evaluation of macros.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "TypeCheckMacros.h"
18+
#include "TypeChecker.h"
19+
#include "swift/AST/ASTContext.h"
20+
#include "swift/AST/Expr.h"
21+
#include "swift/AST/SourceFile.h"
22+
#include "swift/Basic/SourceManager.h"
23+
#include "swift/Parse/Lexer.h"
24+
#include "swift/Parse/Parser.h"
25+
26+
using namespace swift;
27+
28+
extern "C" ptrdiff_t swift_ASTGen_evaluateMacro(
29+
void *sourceFile, const void *sourceLocation,
30+
const char **evaluatedSource, ptrdiff_t *evaluatedSourceLength);
31+
32+
#if SWIFT_SWIFT_PARSER
33+
Expr *swift::expandMacroExpr(
34+
DeclContext *dc, Expr *expr, StringRef macroName, Type expandedType
35+
) {
36+
ASTContext &ctx = dc->getASTContext();
37+
38+
// FIXME: Introduce a more robust way to ensure that we can get the "exported"
39+
// source file for a given context. If it's within a macro expansion, it
40+
// may not have a C++ SourceFile, but will have a Syntax tree.
41+
//
42+
// FIXME^2: And find a better name for "exportedSourceFile".
43+
auto sourceFile = dc->getParentSourceFile();
44+
if (!sourceFile)
45+
return nullptr;
46+
47+
auto astGenSourceFile = sourceFile->exportedSourceFile;
48+
if (!astGenSourceFile)
49+
return nullptr;
50+
51+
// Evaluate the macro.
52+
const char *evaluatedSource;
53+
ptrdiff_t evaluatedSourceLength;
54+
swift_ASTGen_evaluateMacro(
55+
astGenSourceFile, expr->getStartLoc().getOpaquePointerValue(),
56+
&evaluatedSource, &evaluatedSourceLength);
57+
if (!evaluatedSource)
58+
return nullptr;
59+
60+
SourceManager &sourceMgr = ctx.SourceMgr;
61+
62+
// Figure out a reasonable name for the macro expansion buffer.
63+
std::string bufferName;
64+
{
65+
llvm::raw_string_ostream out(bufferName);
66+
67+
out << "Macro expansion of #" << macroName;
68+
if (auto bufferID = sourceFile->getBufferID()) {
69+
unsigned startLine, startColumn;
70+
std::tie(startLine, startColumn) =
71+
sourceMgr.getLineAndColumnInBuffer(expr->getStartLoc(), *bufferID);
72+
73+
SourceLoc endLoc =
74+
Lexer::getLocForEndOfToken(sourceMgr, expr->getEndLoc());
75+
unsigned endLine, endColumn;
76+
std::tie(endLine, endColumn) =
77+
sourceMgr.getLineAndColumnInBuffer(endLoc, *bufferID);
78+
79+
out << " in " << sourceMgr.getIdentifierForBuffer(*bufferID) << ":"
80+
<< startLine << ":" << startColumn
81+
<< "-" << endLine << ":" << endColumn;
82+
}
83+
}
84+
85+
// Create a new source buffer with the contents of the expanded macro.
86+
auto macroBuffer =
87+
llvm::MemoryBuffer::getMemBuffer(
88+
StringRef(evaluatedSource, evaluatedSourceLength), bufferName);
89+
unsigned macroBufferID = sourceMgr.addNewSourceBuffer(std::move(macroBuffer));
90+
91+
// Create a source file to hold the macro buffer.
92+
// FIXME: Seems like we should record this somewhere?
93+
auto macroSourceFile = new (ctx) SourceFile(
94+
*dc->getParentModule(), SourceFileKind::Library, macroBufferID);
95+
96+
// Parse the expression.
97+
Parser parser(macroBufferID, *macroSourceFile, &ctx.Diags, nullptr, nullptr);
98+
parser.consumeTokenWithoutFeedingReceiver();
99+
auto parsedResult = parser.parseExpr(diag::expected_macro_expansion_expr);
100+
if (parsedResult.isParseError() || parsedResult.isNull()) {
101+
// Tack on a note to say where we expanded the macro from?
102+
return nullptr;
103+
}
104+
105+
// Type-check the expanded expression.
106+
// FIXME: Would like to pass through type checking options like "discarded"
107+
// that are captured by TypeCheckExprOptions.
108+
Expr *expandedExpr = parsedResult.get();
109+
constraints::ContextualTypeInfo contextualType {
110+
TypeLoc::withoutLoc(expandedType),
111+
// FIXME: Add a contextual type purpose for macro expansion.
112+
ContextualTypePurpose::CTP_CoerceOperand
113+
};
114+
115+
Type realExpandedType = TypeChecker::typeCheckExpression(
116+
expandedExpr, dc, contextualType);
117+
if (!realExpandedType)
118+
return nullptr;
119+
120+
assert((expandedType->isEqual(realExpandedType) ||
121+
realExpandedType->hasError()) &&
122+
"Type checking changed the result type?");
123+
return expandedExpr;
124+
}
125+
126+
#endif // SWIFT_SWIFT_PARSER

lib/Sema/TypeCheckMacros.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===--- TypeCheckConcurrency.h - Concurrency -------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file provides type checking support for macros.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
#ifndef SWIFT_SEMA_TYPECHECKMACROS_H
17+
#define SWIFT_SEMA_TYPECHECKMACROS_H
18+
19+
#include "swift/AST/Type.h"
20+
21+
namespace swift {
22+
23+
class Expr;
24+
25+
/// Expands the given macro expression and type-check the result with
26+
/// the given expanded type.
27+
///
28+
/// \returns the type-checked replacement expression, or NULL if the
29+
// macro could not be expanded.
30+
Expr *expandMacroExpr(
31+
DeclContext *dc, Expr *expr, StringRef macroName, Type expandedType);
32+
33+
} // end namespace swift
34+
35+
#endif /* SWIFT_SEMA_TYPECHECKMACROS_H */
36+

test/Macros/builtin_macros.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1-
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinMacros -typecheck %s -module-name MacrosTest 2>&1 | %FileCheck %s
1+
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinMacros -dump-ast %s -module-name MacrosTest 2>&1 | %FileCheck %s
22
// REQUIRES: OS=macosx
33

4-
// CHECK: #function --> "MacrosTest"
4+
// CHECK: macro_expansion_expr implicit type='String'
5+
// CHECK-NEXT: magic_identifier_literal_expr{{.*}}kind=#function
6+
// CHECK-NEXT: string_literal_expr{{.*}}Macro expansion of #function in{{.*}}value="MacrosTest"
57
print(#function)
68

79
func f(a: Int, b: Int) {
810
print(#function, #line, #column)
9-
// CHECK-NEXT: #function --> "f(a:b:)"
10-
// CHECK-NEXT: #line --> 8
11-
// CHECK-NEXT: #column --> 27
11+
// CHECK: macro_expansion_expr implicit type='String'
12+
// CHECK-NEXT: magic_identifier_literal_expr{{.*}}kind=#function
13+
// CHECK-NEXT: string_literal_expr{{.*}}Macro expansion of #function in{{.*}}value="f(a:b:)"
14+
15+
// CHECK: macro_expansion_expr implicit type='Int'
16+
// CHECK-NEXT: magic_identifier_literal_expr{{.*}}kind=#line
17+
// CHECK-NEXT: integer_literal_expr{{.*}}Macro expansion of #line in{{.*}}value=10
18+
19+
// CHECK: macro_expansion_expr implicit type='Int'
20+
// CHECK-NEXT: magic_identifier_literal_expr{{.*}}kind=#column
21+
// CHECK-NEXT: integer_literal_expr{{.*}}Macro expansion of #column in{{.*}}value=27
1222
}

0 commit comments

Comments
 (0)