Skip to content

[5.9][Macros] Requestify MacroExpansionExpr expansion #65480

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -3930,6 +3930,26 @@ class ExpandMacroExpansionDeclRequest
void noteCycleStep(DiagnosticEngine &diags) const;
};

/// Expand a 'MacroExpansionExpr',
class ExpandMacroExpansionExprRequest
: public SimpleRequest<ExpandMacroExpansionExprRequest,
Optional<unsigned>(MacroExpansionExpr *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

Optional<unsigned>
evaluate(Evaluator &evaluator, MacroExpansionExpr *mee) const;

public:
bool isCached() const { return true; }
void diagnoseCycle(DiagnosticEngine &diags) const;
void noteCycleStep(DiagnosticEngine &diags) const;
};

/// Expand all accessor macros attached to the given declaration.
///
/// Produces the set of macro expansion buffer IDs.
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,9 @@ SWIFT_REQUEST(TypeChecker, ExternalMacroDefinitionRequest,
SWIFT_REQUEST(TypeChecker, ExpandMacroExpansionDeclRequest,
ArrayRef<Decl *>(MacroExpansionDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ExpandMacroExpansionExprRequest,
ArrayRef<Decl *>(MacroExpansionExpr *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ExpandMemberAttributeMacros,
ArrayRef<unsigned>(Decl *),
Cached, NoLocationInfo)
Expand Down
28 changes: 28 additions & 0 deletions include/swift/Basic/Lazy.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,41 @@
#define SWIFT_BASIC_LAZY_H

#include <memory>
#include <functional>

#include "swift/Basic/Malloc.h"
#include "swift/Basic/type_traits.h"
#include "swift/Threading/Once.h"

namespace swift {

/// A template for lazy-initialized values.
/// Usage:
///
/// LazyValue<std::string> value([]() { return createString(); })
/// if (condition) {
/// // 'createString()' is evaluated only when 'value` is dereferenced.
/// doSomething(*value);
/// }
template <typename T, typename Initializer = std::function<T()>>
class LazyValue {
Initializer Init;
llvm::Optional<T> Value;

public:
LazyValue(Initializer Init) : Init(Init){};

T &get() {
if (!Value.hasValue()) {
Value = Init();
}
return Value.value();
}

T *operator->() { return &get(); }
T &operator*() { return get(); }
};

/// A template for lazily-constructed, zero-initialized, leaked-on-exit
/// global objects.
template <class T> class Lazy {
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Basic/StringExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ class NullTerminatedStringRef {

/// Create a null-terminated string, copying \p Str into \p A .
template <typename Allocator>
NullTerminatedStringRef(StringRef Str, Allocator &A) : Ref() {
NullTerminatedStringRef(StringRef Str, Allocator &A) : Ref("") {
if (Str.empty())
return;

Expand Down
16 changes: 16 additions & 0 deletions lib/AST/TypeCheckRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1833,6 +1833,22 @@ void ExpandMacroExpansionDeclRequest::noteCycleStep(DiagnosticEngine &diags) con
decl->getMacroName().getFullName());
}

void ExpandMacroExpansionExprRequest::diagnoseCycle(DiagnosticEngine &diags) const {
auto expr = std::get<0>(getStorage());
diags.diagnose(expr->getStartLoc(),
diag::macro_expand_circular_reference,
"freestanding",
expr->getMacroName().getFullName());
}

void ExpandMacroExpansionExprRequest::noteCycleStep(DiagnosticEngine &diags) const {
auto expr = std::get<0>(getStorage());
diags.diagnose(expr->getStartLoc(),
diag::macro_expand_circular_reference_through,
"freestanding",
expr->getMacroName().getFullName());
}

void ExpandAccessorMacros::diagnoseCycle(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
diags.diagnose(decl->getLoc(),
Expand Down
8 changes: 3 additions & 5 deletions lib/Refactoring/Refactoring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8622,11 +8622,9 @@ bool RefactoringActionAddAsyncWrapper::performChange() {
/// expression.
static Optional<unsigned> getMacroExpansionBuffer(
SourceManager &sourceMgr, MacroExpansionExpr *expansion) {
if (auto rewritten = expansion->getRewritten()) {
return sourceMgr.findBufferContainingLoc(rewritten->getStartLoc());
}

return None;
return evaluateOrDefault(
expansion->getDeclContext()->getASTContext().evaluator,
ExpandMacroExpansionExprRequest{expansion}, {});
}

/// Retrieve the macro expansion buffer for the given macro expansion
Expand Down
45 changes: 21 additions & 24 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2937,13 +2937,14 @@ namespace {

auto macro = cast<MacroDecl>(overload.choice.getDecl());
ConcreteDeclRef macroRef = resolveConcreteDeclRef(macro, locator);
if (auto newExpr = expandMacroExpr(dc, expr, macroRef, expandedType)) {
auto expansion = new (ctx) MacroExpansionExpr(
dc, expr->getStartLoc(), DeclNameRef(macro->getName()),
DeclNameLoc(expr->getLoc()), SourceLoc(), { }, SourceLoc(),
nullptr, MacroRole::Expression, /*isImplicit=*/true, expandedType);
expansion->setMacroRef(macroRef);
expansion->setRewritten(newExpr);
auto expansion = new (ctx) MacroExpansionExpr(
dc, expr->getStartLoc(), DeclNameRef(macro->getName()),
DeclNameLoc(expr->getLoc()), SourceLoc(), {}, SourceLoc(), nullptr,
MacroRole::Expression, /*isImplicit=*/true, expandedType);
expansion->setMacroRef(macroRef);
(void)evaluateOrDefault(
ctx.evaluator, ExpandMacroExpansionExprRequest{expansion}, None);
if (expansion->getRewritten()) {
cs.cacheExprTypes(expansion);
return expansion;
}
Expand Down Expand Up @@ -5386,23 +5387,19 @@ namespace {
auto macro = cast<MacroDecl>(overload.choice.getDecl());
ConcreteDeclRef macroRef = resolveConcreteDeclRef(macro, locator);
E->setMacroRef(macroRef);

if (!cs.Options.contains(ConstraintSystemFlags::DisableMacroExpansions)) {
if (macro->getMacroRoles().contains(MacroRole::Expression)) {
if (auto newExpr = expandMacroExpr(dc, E, macroRef, expandedType)) {
E->setRewritten(newExpr);
}
}
// For a non-expression macro, expand it as a declaration.
else if (macro->getMacroRoles().contains(MacroRole::Declaration) ||
macro->getMacroRoles().contains(MacroRole::CodeItem)) {
if (!E->getSubstituteDecl()) {
auto *med = E->createSubstituteDecl();
TypeChecker::typeCheckDecl(med);
}
}
// Other macro roles may also be encountered here, as they use
// `MacroExpansionExpr` for resolution. In those cases, do not expand.
E->setType(expandedType);

// FIXME: Expansion should be lazy.
// i.e. 'ExpandMacroExpansionExprRequest' should be sinked into
// 'getRewritten()', and performed on-demand.
if (!cs.Options.contains(ConstraintSystemFlags::DisableMacroExpansions) &&
// Do not expand macros inside macro arguments. For example for
// '#stringify(#assert(foo))' when typechecking `#assert(foo)`,
// we don't want to expand it.
llvm::none_of(makeArrayRef(ExprStack).drop_back(1),
[](Expr *E) { return isa<MacroExpansionExpr>(E); })) {
(void)evaluateOrDefault(cs.getASTContext().evaluator,
ExpandMacroExpansionExprRequest{E}, None);
}

cs.cacheExprTypes(E);
Expand Down
Loading