Skip to content

Commit 5f41f94

Browse files
authored
Merge pull request #37742 from CodaFi/sorry-to-bug-you
Special-case Pattern Binding Decls Created by LLDB
2 parents b64a3ac + d52b33d commit 5f41f94

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

@@ -1471,9 +1474,10 @@ class PatternBindingEntry {
14711474
enum class PatternFlags {
14721475
IsText = 1 << 0,
14731476
IsFullyValidated = 1 << 1,
1477+
IsFromDebugger = 1 << 2,
14741478
};
14751479
/// The initializer context used for this pattern binding entry.
1476-
llvm::PointerIntPair<DeclContext *, 2, OptionSet<PatternFlags>>
1480+
llvm::PointerIntPair<DeclContext *, 3, OptionSet<PatternFlags>>
14771481
InitContextAndFlags;
14781482

14791483
/// Values captured by this initializer.
@@ -1501,6 +1505,14 @@ class PatternBindingEntry {
15011505
PatternFlags::IsFullyValidated);
15021506
}
15031507

1508+
/// Set if this pattern binding came from the debugger.
1509+
///
1510+
/// Stay away unless you are \c PatternBindingDecl::createForDebugger
1511+
void setFromDebugger() {
1512+
InitContextAndFlags.setInt(InitContextAndFlags.getInt() |
1513+
PatternFlags::IsFromDebugger);
1514+
}
1515+
15041516
public:
15051517
/// \p E is the initializer as parsed.
15061518
PatternBindingEntry(Pattern *P, SourceLoc EqualLoc, Expr *E,
@@ -1583,6 +1595,11 @@ class PatternBindingEntry {
15831595
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Subsumed);
15841596
}
15851597

1598+
/// Returns \c true if the debugger created this pattern binding entry.
1599+
bool isFromDebugger() const {
1600+
return InitContextAndFlags.getInt().contains(PatternFlags::IsFromDebugger);
1601+
}
1602+
15861603
// Return the first variable initialized by this pattern.
15871604
VarDecl *getAnchoringVarDecl() const;
15881605

@@ -1668,6 +1685,13 @@ class PatternBindingDecl final : public Decl,
16681685
unsigned NumPatternEntries,
16691686
DeclContext *Parent);
16701687

1688+
// A dedicated entrypoint that allows LLDB to create pattern bindings
1689+
// that look implicit to the compiler but contain user code.
1690+
static PatternBindingDecl *createForDebugger(ASTContext &Ctx,
1691+
StaticSpellingKind Spelling,
1692+
Pattern *Pat, Expr *E,
1693+
DeclContext *Parent);
1694+
16711695
SourceLoc getStartLoc() const {
16721696
return StaticLoc.isValid() ? StaticLoc : VarLoc;
16731697
}
@@ -1869,6 +1893,9 @@ class PatternBindingDecl final : public Decl,
18691893
return getPatternList()[i].getInitStringRepresentation(scratch);
18701894
}
18711895

1896+
/// Returns \c true if this pattern binding was created by the debugger.
1897+
bool isDebuggerBinding() const { return Bits.PatternBindingDecl.IsDebugger; }
1898+
18721899
static bool classof(const Decl *D) {
18731900
return D->getKind() == DeclKind::PatternBinding;
18741901
}

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
@@ -1341,6 +1341,17 @@ PatternBindingDecl *PatternBindingDecl::createImplicit(
13411341
return Result;
13421342
}
13431343

1344+
PatternBindingDecl *PatternBindingDecl::createForDebugger(
1345+
ASTContext &Ctx, StaticSpellingKind StaticSpelling, Pattern *Pat, Expr *E,
1346+
DeclContext *Parent) {
1347+
auto *Result = createImplicit(Ctx, StaticSpelling, Pat, E, Parent);
1348+
Result->Bits.PatternBindingDecl.IsDebugger = true;
1349+
for (auto &entry : Result->getMutablePatternList()) {
1350+
entry.setFromDebugger();
1351+
}
1352+
return Result;
1353+
}
1354+
13441355
PatternBindingDecl *
13451356
PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc,
13461357
StaticSpellingKind StaticSpelling,

0 commit comments

Comments
 (0)