Skip to content

Commit 8410011

Browse files
authored
Merge pull request #37909 from CodaFi/closure-to-the-edge
[5.5] Special-case Pattern Binding Decls Created by LLDB
2 parents fa26bf2 + b6382cd commit 8410011

File tree

5 files changed

+75
-6
lines changed

5 files changed

+75
-6
lines changed

include/swift/AST/ASTScope.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,9 @@ class PatternEntryInitializerScope final : public AbstractPatternEntryScope {
957957
public:
958958
PatternEntryInitializerScope(PatternBindingDecl *pbDecl, unsigned entryIndex)
959959
: AbstractPatternEntryScope(pbDecl, entryIndex),
960-
initAsWrittenWhenCreated(pbDecl->getOriginalInit(entryIndex)) {}
960+
initAsWrittenWhenCreated(pbDecl->isDebuggerBinding() ?
961+
pbDecl->getInit(entryIndex) :
962+
pbDecl->getOriginalInit(entryIndex)) {}
961963
virtual ~PatternEntryInitializerScope() {}
962964

963965
protected:

include/swift/AST/Decl.h

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,13 @@ class alignas(1 << DeclAlignInBits) Decl {
318318
Hoisted : 1
319319
);
320320

321-
SWIFT_INLINE_BITFIELD_FULL(PatternBindingDecl, Decl, 1+2+16,
321+
SWIFT_INLINE_BITFIELD_FULL(PatternBindingDecl, Decl, 1+1+2+16,
322322
/// Whether this pattern binding declares static variables.
323323
IsStatic : 1,
324324

325+
/// Whether this pattern binding is synthesized by the debugger.
326+
IsDebugger : 1,
327+
325328
/// Whether 'static' or 'class' was used.
326329
StaticSpelling : 2,
327330

@@ -1474,9 +1477,10 @@ class PatternBindingEntry {
14741477
enum class PatternFlags {
14751478
IsText = 1 << 0,
14761479
IsFullyValidated = 1 << 1,
1480+
IsFromDebugger = 1 << 2,
14771481
};
14781482
/// The initializer context used for this pattern binding entry.
1479-
llvm::PointerIntPair<DeclContext *, 2, OptionSet<PatternFlags>>
1483+
llvm::PointerIntPair<DeclContext *, 3, OptionSet<PatternFlags>>
14801484
InitContextAndFlags;
14811485

14821486
/// Values captured by this initializer.
@@ -1504,6 +1508,14 @@ class PatternBindingEntry {
15041508
PatternFlags::IsFullyValidated);
15051509
}
15061510

1511+
/// Set if this pattern binding came from the debugger.
1512+
///
1513+
/// Stay away unless you are \c PatternBindingDecl::createForDebugger
1514+
void setFromDebugger() {
1515+
InitContextAndFlags.setInt(InitContextAndFlags.getInt() |
1516+
PatternFlags::IsFromDebugger);
1517+
}
1518+
15071519
public:
15081520
/// \p E is the initializer as parsed.
15091521
PatternBindingEntry(Pattern *P, SourceLoc EqualLoc, Expr *E,
@@ -1586,6 +1598,11 @@ class PatternBindingEntry {
15861598
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Subsumed);
15871599
}
15881600

1601+
/// Returns \c true if the debugger created this pattern binding entry.
1602+
bool isFromDebugger() const {
1603+
return InitContextAndFlags.getInt().contains(PatternFlags::IsFromDebugger);
1604+
}
1605+
15891606
// Return the first variable initialized by this pattern.
15901607
VarDecl *getAnchoringVarDecl() const;
15911608

@@ -1671,6 +1688,13 @@ class PatternBindingDecl final : public Decl,
16711688
unsigned NumPatternEntries,
16721689
DeclContext *Parent);
16731690

1691+
// A dedicated entrypoint that allows LLDB to create pattern bindings
1692+
// that look implicit to the compiler but contain user code.
1693+
static PatternBindingDecl *createForDebugger(ASTContext &Ctx,
1694+
StaticSpellingKind Spelling,
1695+
Pattern *Pat, Expr *E,
1696+
DeclContext *Parent);
1697+
16741698
SourceLoc getStartLoc() const {
16751699
return StaticLoc.isValid() ? StaticLoc : VarLoc;
16761700
}
@@ -1872,6 +1896,9 @@ class PatternBindingDecl final : public Decl,
18721896
return getPatternList()[i].getInitStringRepresentation(scratch);
18731897
}
18741898

1899+
/// Returns \c true if this pattern binding was created by the debugger.
1900+
bool isDebuggerBinding() const { return Bits.PatternBindingDecl.IsDebugger; }
1901+
18751902
static bool classof(const Decl *D) {
18761903
return D->getKind() == DeclKind::PatternBinding;
18771904
}

lib/AST/ASTScopeCreation.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -480,9 +480,15 @@ ScopeCreator::addToScopeTreeAndReturnInsertionPoint(ASTNode n,
480480
if (!n)
481481
return parent;
482482

483+
// HACK: LLDB creates implicit pattern bindings that... contain user
484+
// expressions. We need to actually honor lookups through those bindings
485+
// in case they contain closures that bind additional variables in further
486+
// scopes.
483487
if (auto *d = n.dyn_cast<Decl *>())
484488
if (d->isImplicit())
485-
return parent;
489+
if (!isa<PatternBindingDecl>(d)
490+
|| !cast<PatternBindingDecl>(d)->isDebuggerBinding())
491+
return parent;
486492

487493
NodeAdder adder(endLoc);
488494
if (auto *p = n.dyn_cast<Decl *>())
@@ -733,6 +739,23 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint(
733739
this, decl, patternEntryIndex);
734740
}
735741

742+
// If this pattern binding entry was created by the debugger, it will always
743+
// have a synthesized init that is created from user code. We special-case
744+
// lookups into these scopes to look through the debugger's chicanery to the
745+
// underlying user-defined scopes, if any.
746+
if (patternEntry.isFromDebugger() && patternEntry.getInit()) {
747+
ASTScopeAssert(
748+
patternEntry.getInit()->getSourceRange().isValid(),
749+
"pattern initializer has invalid source range");
750+
ASTScopeAssert(
751+
!getSourceManager().isBeforeInBuffer(
752+
patternEntry.getInit()->getStartLoc(), decl->getStartLoc()),
753+
"inits are always after the '='");
754+
scopeCreator
755+
.constructExpandAndInsert<PatternEntryInitializerScope>(
756+
this, decl, patternEntryIndex);
757+
}
758+
736759
// Add accessors for the variables in this pattern.
737760
patternEntry.getPattern()->forEachVariable([&](VarDecl *var) {
738761
scopeCreator.addChildrenForParsedAccessors(var, this);
@@ -751,8 +774,7 @@ void
751774
PatternEntryInitializerScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
752775
ScopeCreator &scopeCreator) {
753776
// Create a child for the initializer expression.
754-
scopeCreator.addToScopeTree(ASTNode(getPatternEntry().getOriginalInit()),
755-
this);
777+
scopeCreator.addToScopeTree(ASTNode(initAsWrittenWhenCreated), this);
756778
}
757779

758780

lib/AST/ASTScopeSourceRange.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ static SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *);
4040

4141
void ASTScopeImpl::checkSourceRangeBeforeAddingChild(ASTScopeImpl *child,
4242
const ASTContext &ctx) const {
43+
// Ignore debugger bindings - they're a special mix of user code and implicit
44+
// wrapper code that is too difficult to check for consistency.
45+
if (auto d = getDeclIfAny().getPtrOrNull())
46+
if (auto *PBD = dyn_cast<PatternBindingDecl>(d))
47+
if (PBD->isDebuggerBinding())
48+
return;
49+
4350
auto &sourceMgr = ctx.SourceMgr;
4451

4552
auto range = getCharSourceRangeOfScope(sourceMgr);

lib/AST/Decl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,17 @@ PatternBindingDecl *PatternBindingDecl::createImplicit(
13501350
return Result;
13511351
}
13521352

1353+
PatternBindingDecl *PatternBindingDecl::createForDebugger(
1354+
ASTContext &Ctx, StaticSpellingKind StaticSpelling, Pattern *Pat, Expr *E,
1355+
DeclContext *Parent) {
1356+
auto *Result = createImplicit(Ctx, StaticSpelling, Pat, E, Parent);
1357+
Result->Bits.PatternBindingDecl.IsDebugger = true;
1358+
for (auto &entry : Result->getMutablePatternList()) {
1359+
entry.setFromDebugger();
1360+
}
1361+
return Result;
1362+
}
1363+
13531364
PatternBindingDecl *
13541365
PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc,
13551366
StaticSpellingKind StaticSpelling,

0 commit comments

Comments
 (0)