Skip to content

Commit ac38469

Browse files
committed
AST: Add verifier support for the TypeRefinementContext tree.
Verify the integrity of the tree formed by `TypeRefinementContext` nodes. In general, parent nodes should "contain" their children and children always be in sorted order.
1 parent 5cf7141 commit ac38469

File tree

3 files changed

+88
-14
lines changed

3 files changed

+88
-14
lines changed

include/swift/AST/TypeRefinementContext.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
185185
unsigned needsExpansion : 1;
186186
} LazyInfo = {};
187187

188+
void verify(const TypeRefinementContext *parent, ASTContext &ctx) const;
189+
188190
TypeRefinementContext(ASTContext &Ctx, IntroNode Node,
189191
TypeRefinementContext *Parent, SourceRange SrcRange,
190192
const AvailabilityRange &Info,
@@ -303,6 +305,10 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
303305
LazyInfo.needsExpansion = needsExpansion;
304306
}
305307

308+
/// Recursively check the tree for integrity. If any errors are found, emits
309+
/// diagnosticts to stderr and aborts.
310+
void verify(ASTContext &ctx);
311+
306312
SWIFT_DEBUG_DUMPER(dump(SourceManager &SrcMgr));
307313
void dump(raw_ostream &OS, SourceManager &SrcMgr) const;
308314
void print(raw_ostream &OS, SourceManager &SrcMgr, unsigned Indent = 0) const;

lib/AST/ASTVerifier.cpp

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "swift/AST/SourceFile.h"
3737
#include "swift/AST/Stmt.h"
3838
#include "swift/AST/TypeCheckRequests.h"
39+
#include "swift/AST/TypeRefinementContext.h"
3940
#include "swift/AST/TypeRepr.h"
4041
#include "swift/Basic/Assertions.h"
4142
#include "swift/Basic/SourceManager.h"
@@ -3882,23 +3883,15 @@ void swift::verify(SourceFile &SF) {
38823883
return;
38833884
Verifier verifier(SF, &SF);
38843885
SF.walk(verifier);
3885-
}
38863886

3887-
bool swift::shouldVerify(const Decl *D, const ASTContext &Context) {
3888-
if (!shouldVerifyGivenContext(Context))
3889-
return false;
3890-
3891-
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
3892-
return shouldVerify(ED->getExtendedNominal(), Context);
3893-
}
3894-
3895-
const auto *VD = dyn_cast<ValueDecl>(D);
3896-
if (!VD) {
3897-
// Verify declarations without names everywhere.
3898-
return true;
3887+
// Verify the TypeRefinementContext hierarchy.
3888+
if (auto TRC = SF.getTypeRefinementContext()) {
3889+
TRC->verify(SF.getASTContext());
38993890
}
3891+
}
39003892

3901-
return true;
3893+
bool swift::shouldVerify(const Decl *D, const ASTContext &Context) {
3894+
return shouldVerifyGivenContext(Context);
39023895
}
39033896

39043897
void swift::verify(Decl *D) {

lib/AST/TypeRefinementContext.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,3 +475,78 @@ void ExpandChildTypeRefinementContextsRequest::cacheResult(
475475
TRC->Children = children;
476476
TRC->setNeedsExpansion(false);
477477
}
478+
479+
/// Emit an error message, dump each context with its corresponding label, and
480+
/// abort.
481+
static void
482+
verificationError(ASTContext &ctx, llvm::StringRef msg,
483+
std::initializer_list<
484+
std::pair<const char *, const TypeRefinementContext *>>
485+
labelsAndNodes) {
486+
llvm::errs() << msg << "\n";
487+
for (auto pair : labelsAndNodes) {
488+
auto label = std::get<0>(pair);
489+
auto context = std::get<1>(pair);
490+
llvm::errs() << label << ":\n";
491+
context->print(llvm::errs(), ctx.SourceMgr);
492+
}
493+
abort();
494+
}
495+
496+
void TypeRefinementContext::verify(const TypeRefinementContext *parent,
497+
ASTContext &ctx) const {
498+
// Verify the children first.
499+
for (auto child : Children) {
500+
child->verify(this, ctx);
501+
}
502+
503+
// Verify that the children are in sorted order and that their source ranges
504+
// do not overlap.
505+
auto &srcMgr = ctx.SourceMgr;
506+
if (Children.size() > 1) {
507+
auto const *previous = Children.front();
508+
for (auto const *current : ArrayRef(Children).drop_front()) {
509+
if (!srcMgr.isAtOrBefore(previous->getSourceRange().Start,
510+
current->getSourceRange().Start))
511+
verificationError(
512+
ctx, "out of order children",
513+
{{"child 1", previous}, {"child 2", current}, {"parent", this}});
514+
515+
if (srcMgr.containsLoc(previous->getSourceRange(),
516+
current->getSourceRange().Start))
517+
verificationError(
518+
ctx, "overlapping children",
519+
{{"child 1", previous}, {"child 2", current}, {"parent", this}});
520+
521+
previous = current;
522+
}
523+
}
524+
525+
// Only root nodes are allowed to have no parent.
526+
if (!parent) {
527+
if (getReason() != Reason::Root)
528+
verificationError(ctx, "interior node without parent", {{"node", this}});
529+
return;
530+
}
531+
532+
// All nodes with a parent must have a valid source range.
533+
if (!SrcRange.isValid())
534+
verificationError(ctx, "invalid source range", {{"node", this}});
535+
536+
if (getReason() != Reason::Root) {
537+
auto parentRange = parent->SrcRange;
538+
if (parentRange.isValid() &&
539+
!(srcMgr.isAtOrBefore(parentRange.Start, SrcRange.Start) &&
540+
srcMgr.isAtOrBefore(SrcRange.End, parentRange.End)))
541+
verificationError(ctx, "child source range not contained",
542+
{{"child", this}, {"parent", this}});
543+
}
544+
545+
if (!AvailabilityInfo.isContainedIn(parent->AvailabilityInfo))
546+
verificationError(ctx, "child availability range not contained",
547+
{{"child", this}, {"parent", this}});
548+
}
549+
550+
void TypeRefinementContext::verify(ASTContext &ctx) {
551+
verify(nullptr, ctx);
552+
}

0 commit comments

Comments
 (0)