Skip to content

Commit 5cf7141

Browse files
committed
AST: Maintain TypeRefinementContext children in sorted order.
Improve the performance of looking up the most refined `TypeRefinementContext` for a given source location by storing children in sorted order and using a binary search to query each layer of the tree. This slightly pessimizes insertion (primarily when macros are expanded out of source location order) but lookup is a far more common operation.
1 parent a4487f6 commit 5cf7141

File tree

2 files changed

+51
-16
lines changed

2 files changed

+51
-16
lines changed

include/swift/AST/TypeRefinementContext.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,7 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
290290
}
291291

292292
/// Adds a child refinement context.
293-
void addChild(TypeRefinementContext *Child) {
294-
assert(Child->getSourceRange().isValid());
295-
Children.push_back(Child);
296-
}
293+
void addChild(TypeRefinementContext *Child, ASTContext &Ctx);
297294

298295
/// Returns the inner-most TypeRefinementContext descendant of this context
299296
/// for the given source location.

lib/AST/TypeRefinementContext.cpp

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17+
#include "swift/AST/TypeRefinementContext.h"
18+
1719
#include "swift/AST/ASTContext.h"
1820
#include "swift/AST/Decl.h"
19-
#include "swift/AST/Module.h"
20-
#include "swift/AST/Stmt.h"
2121
#include "swift/AST/Expr.h"
22+
#include "swift/AST/Module.h"
2223
#include "swift/AST/SourceFile.h"
24+
#include "swift/AST/Stmt.h"
2325
#include "swift/AST/TypeCheckRequests.h"
24-
#include "swift/AST/TypeRefinementContext.h"
2526
#include "swift/Basic/Assertions.h"
2627
#include "swift/Basic/SourceManager.h"
2728

@@ -35,7 +36,7 @@ TypeRefinementContext::TypeRefinementContext(
3536
ExplicitAvailabilityInfo(ExplicitInfo) {
3637
if (Parent) {
3738
assert(SrcRange.isValid());
38-
Parent->addChild(this);
39+
Parent->addChild(this, Ctx);
3940
assert(Info.isContainedIn(Parent->getAvailabilityInfo()));
4041
}
4142
Ctx.addDestructorCleanup(Children);
@@ -169,6 +170,36 @@ TypeRefinementContext::createForWhileStmtBody(ASTContext &Ctx, WhileStmt *S,
169170
Ctx, S, Parent, S->getBody()->getSourceRange(), Info, /* ExplicitInfo */Info);
170171
}
171172

173+
void TypeRefinementContext::addChild(TypeRefinementContext *Child,
174+
ASTContext &Ctx) {
175+
assert(Child->getSourceRange().isValid());
176+
177+
// Handle the first child.
178+
if (Children.empty()) {
179+
Children.push_back(Child);
180+
return;
181+
}
182+
183+
// Handle a child that is ordered after the existing children (this should be
184+
// the common case).
185+
auto &srcMgr = Ctx.SourceMgr;
186+
if (srcMgr.isBefore(Children.back()->getSourceRange().Start,
187+
Child->getSourceRange().Start)) {
188+
Children.push_back(Child);
189+
return;
190+
}
191+
192+
// Insert the child amongst the existing sorted children.
193+
auto iter = std::upper_bound(
194+
Children.begin(), Children.end(), Child,
195+
[&srcMgr](TypeRefinementContext *lhs, TypeRefinementContext *rhs) {
196+
return srcMgr.isBefore(lhs->getSourceRange().Start,
197+
rhs->getSourceRange().Start);
198+
});
199+
200+
Children.insert(iter, Child);
201+
}
202+
172203
TypeRefinementContext *
173204
TypeRefinementContext::findMostRefinedSubContext(SourceLoc Loc,
174205
ASTContext &Ctx) {
@@ -180,16 +211,23 @@ TypeRefinementContext::findMostRefinedSubContext(SourceLoc Loc,
180211
auto expandedChildren = evaluateOrDefault(
181212
Ctx.evaluator, ExpandChildTypeRefinementContextsRequest{this}, {});
182213

183-
// For the moment, we perform a linear search here, but we can and should
184-
// do something more efficient.
185-
for (TypeRefinementContext *Child : expandedChildren) {
186-
if (auto *Found = Child->findMostRefinedSubContext(Loc, Ctx)) {
187-
return Found;
188-
}
214+
// Do a binary search to find the first child with a source range that
215+
// ends after the given location.
216+
auto iter = std::lower_bound(
217+
expandedChildren.begin(), expandedChildren.end(), Loc,
218+
[&Ctx](TypeRefinementContext *context, SourceLoc loc) {
219+
return Ctx.SourceMgr.isBefore(context->getSourceRange().End, loc);
220+
});
221+
222+
// Check whether the matching child or any of its descendants contain
223+
// the given location.
224+
if (iter != expandedChildren.end()) {
225+
if (auto found = (*iter)->findMostRefinedSubContext(Loc, Ctx))
226+
return found;
189227
}
190228

191-
// Loc is in this context's range but not in any child's, so this context
192-
// must be the inner-most context.
229+
// The location is in this context's range but not in any child's, so this
230+
// context must be the innermost context.
193231
return this;
194232
}
195233

0 commit comments

Comments
 (0)