Skip to content

Commit 7386a7e

Browse files
committed
[Macros] Rework the way we assign closure and local discriminators
Setting closure and local discriminators depends on an in-order walk of the AST. For macros, it was walking into both macro expansions and arguments. However, this doesn't work well with lazy macro expansions, and could result in some closures/local variables not getting discriminators set at all. Make the assignment of discriminators only walk macro arguments, and then lazily assign discriminators for anything within a macro expansion or in ill-formed code. This replaces the single global "next autoclosure discriminator" scheme with a per-DeclContext scheme, that is more reliable/robust, although it does mean that discriminators of closures and locals within macro expansions are dependent on ordering. That shouldn't matter, because these are local values. Fixes rdar://108682196.
1 parent c3fbe24 commit 7386a7e

File tree

6 files changed

+66
-21
lines changed

6 files changed

+66
-21
lines changed

include/swift/AST/ASTContext.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,6 @@ class ASTContext final {
342342
/// The # of times we have performed typo correction.
343343
unsigned NumTypoCorrections = 0;
344344

345-
/// The next auto-closure discriminator. This needs to be preserved
346-
/// across invocations of both the parser and the type-checker.
347-
unsigned NextAutoClosureDiscriminator = 0;
348-
349345
/// Cached mapping from types to their associated tangent spaces.
350346
llvm::DenseMap<Type, Optional<TangentSpace>> AutoDiffTangentSpaces;
351347

@@ -1121,6 +1117,13 @@ class ASTContext final {
11211117
unsigned getNextMacroDiscriminator(MacroDiscriminatorContext context,
11221118
DeclBaseName baseName);
11231119

1120+
/// Get the next discriminator within the given declaration context.
1121+
unsigned getNextDiscriminator(const DeclContext *dc);
1122+
1123+
/// Set the maximum assigned discriminator within the given declaration context.
1124+
void setMaxAssignedDiscriminator(
1125+
const DeclContext *dc, unsigned discriminator);
1126+
11241127
/// Retrieve the Clang module loader for this ASTContext.
11251128
///
11261129
/// If there is no Clang module loader, returns a null pointer.

lib/AST/ASTContext.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,9 @@ struct ASTContext::Implementation {
403403
llvm::DenseMap<std::pair<const void *, Identifier>, unsigned>
404404
NextMacroDiscriminator;
405405

406+
/// Local and closure discriminators per context.
407+
llvm::DenseMap<const DeclContext *, unsigned> NextDiscriminator;
408+
406409
/// Structure that captures data that is segregated into different
407410
/// arenas.
408411
struct Arena {
@@ -2185,6 +2188,18 @@ unsigned ASTContext::getNextMacroDiscriminator(
21852188
return getImpl().NextMacroDiscriminator[key]++;
21862189
}
21872190

2191+
/// Get the next discriminator within the given declaration context.
2192+
unsigned ASTContext::getNextDiscriminator(const DeclContext *dc) {
2193+
return getImpl().NextDiscriminator[dc];
2194+
}
2195+
2196+
/// Set the maximum assigned discriminator within the given declaration context.
2197+
void ASTContext::setMaxAssignedDiscriminator(
2198+
const DeclContext *dc, unsigned discriminator) {
2199+
assert(discriminator >= getImpl().NextDiscriminator[dc]);
2200+
getImpl().NextDiscriminator[dc] = discriminator;
2201+
}
2202+
21882203
void ASTContext::verifyAllLoadedModules() const {
21892204
#ifndef NDEBUG
21902205
FrontendStatsTracer tracer(Stats, "verify-all-loaded-modules");

lib/AST/Decl.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2934,10 +2934,26 @@ unsigned ValueDecl::getLocalDiscriminator() const {
29342934
return 0;
29352935

29362936
// Assign local discriminators in this context.
2937+
ASTContext &ctx = getASTContext();
29372938
evaluateOrDefault(
2938-
getASTContext().evaluator,
2939+
ctx.evaluator,
29392940
LocalDiscriminatorsRequest{getDeclContext()}, InvalidDiscriminator);
29402941

2942+
// If we don't have a discriminator, and either
2943+
// 1. We have ill-formed code and we're able to assign a discriminator, or
2944+
// 2. We are in a macro expansion buffer
2945+
//
2946+
// then assign the next discriminator now.
2947+
if (LocalDiscriminator == InvalidDiscriminator &&
2948+
(ctx.Diags.hadAnyError() ||
2949+
(getLoc().isValid() &&
2950+
getModuleContext()->getSourceFileContainingLocation(getLoc())
2951+
->getFulfilledMacroRole() != None))) {
2952+
auto discriminator = ctx.getNextDiscriminator(getDeclContext());
2953+
ctx.setMaxAssignedDiscriminator(getDeclContext(), discriminator + 1);
2954+
const_cast<ValueDecl *>(this)->LocalDiscriminator = discriminator;
2955+
}
2956+
29412957
assert(LocalDiscriminator != InvalidDiscriminator);
29422958

29432959
return LocalDiscriminator;

lib/AST/Expr.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,16 +1901,22 @@ unsigned AbstractClosureExpr::getDiscriminator() const {
19011901
if (raw != InvalidDiscriminator)
19021902
return raw;
19031903

1904+
ASTContext &ctx = getASTContext();
19041905
evaluateOrDefault(
1905-
getASTContext().evaluator, LocalDiscriminatorsRequest{getParent()}, 0);
1906+
ctx.evaluator, LocalDiscriminatorsRequest{getParent()}, 0);
19061907

1907-
// Ill-formed code might not be able to assign discriminators, so assign
1908-
// a new one now.
1908+
// If we don't have a discriminator, and either
1909+
// 1. We have ill-formed code and we're able to assign a discriminator, or
1910+
// 2. We are in a macro expansion buffer
1911+
//
1912+
// then assign the next discriminator now.
19091913
if (getRawDiscriminator() == InvalidDiscriminator &&
1910-
getASTContext().Diags.hadAnyError()) {
1914+
(ctx.Diags.hadAnyError() ||
1915+
getParentSourceFile()->getFulfilledMacroRole() != None)) {
1916+
auto discriminator = ctx.getNextDiscriminator(getParent());
1917+
ctx.setMaxAssignedDiscriminator(getParent(), discriminator + 1);
19111918
const_cast<AbstractClosureExpr *>(this)->
1912-
Bits.AbstractClosureExpr.Discriminator =
1913-
getASTContext().NextAutoClosureDiscriminator++;
1919+
Bits.AbstractClosureExpr.Discriminator = discriminator;
19141920
}
19151921

19161922
assert(getRawDiscriminator() != InvalidDiscriminator);

lib/Sema/TypeCheckStmt.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ namespace {
255255
}
256256

257257
MacroWalking getMacroWalkingBehavior() const override {
258-
return MacroWalking::ArgumentsAndExpansion;
258+
return MacroWalking::Arguments;
259259
}
260260

261261
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
@@ -410,7 +410,6 @@ unsigned LocalDiscriminatorsRequest::evaluate(
410410
LocalDiscriminatorsRequest{dc->getParent()}, 0);
411411
}
412412

413-
Optional<unsigned> expectedNextAutoclosureDiscriminator = None;
414413
ASTNode node;
415414
ParameterList *params = nullptr;
416415
ParamDecl *selfParam = nullptr;
@@ -436,7 +435,7 @@ unsigned LocalDiscriminatorsRequest::evaluate(
436435
params = closure->getParameters();
437436
} else if (auto topLevel = dyn_cast<TopLevelCodeDecl>(dc)) {
438437
node = topLevel->getBody();
439-
expectedNextAutoclosureDiscriminator = ctx.NextAutoClosureDiscriminator;
438+
dc = topLevel->getParentModule();
440439
} else if (auto patternBindingInit = dyn_cast<PatternBindingInitializer>(dc)){
441440
auto patternBinding = patternBindingInit->getBinding();
442441
node = patternBinding->getInit(patternBindingInit->getBindingIndex());
@@ -472,12 +471,11 @@ unsigned LocalDiscriminatorsRequest::evaluate(
472471
params = getParameterList(dc);
473472
}
474473

474+
auto startDiscriminator = ctx.getNextDiscriminator(dc);
475475
if (!node && !params && !selfParam)
476-
return 0;
476+
return startDiscriminator;
477477

478-
SetLocalDiscriminators visitor(
479-
expectedNextAutoclosureDiscriminator.value_or(0)
480-
);
478+
SetLocalDiscriminators visitor(startDiscriminator);
481479

482480
// Set local discriminator for the 'self' parameter.
483481
if (selfParam)
@@ -494,9 +492,7 @@ unsigned LocalDiscriminatorsRequest::evaluate(
494492
node.walk(visitor);
495493

496494
unsigned nextDiscriminator = visitor.maxAssignedDiscriminator();
497-
if (expectedNextAutoclosureDiscriminator) {
498-
ctx.NextAutoClosureDiscriminator = nextDiscriminator;
499-
}
495+
ctx.setMaxAssignedDiscriminator(dc, nextDiscriminator);
500496

501497
// Return the next discriminator.
502498
return nextDiscriminator;

test/Macros/macro_expand.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,3 +400,12 @@ func testFreestandingWithClosure(i: Int) {
400400
return x
401401
}
402402
}
403+
404+
// Nested macros with closures
405+
@freestanding(expression) macro coerceToInt<T>(_ value: T) -> Int = #externalMacro(module: "MacroDefinition", type: "CoerceToIntMacro")
406+
407+
func testFreestandingClosureNesting() {
408+
_ = #stringify({ () -> Int in
409+
#coerceToInt(2)
410+
})
411+
}

0 commit comments

Comments
 (0)