14
14
//
15
15
// ===----------------------------------------------------------------------===//
16
16
17
+ #include " swift/AST/TypeRefinementContext.h"
18
+
17
19
#include " swift/AST/ASTContext.h"
18
20
#include " swift/AST/Decl.h"
19
- #include " swift/AST/Module.h"
20
- #include " swift/AST/Stmt.h"
21
21
#include " swift/AST/Expr.h"
22
+ #include " swift/AST/Module.h"
22
23
#include " swift/AST/SourceFile.h"
24
+ #include " swift/AST/Stmt.h"
23
25
#include " swift/AST/TypeCheckRequests.h"
24
- #include " swift/AST/TypeRefinementContext.h"
25
26
#include " swift/Basic/Assertions.h"
26
27
#include " swift/Basic/SourceManager.h"
27
28
@@ -35,7 +36,7 @@ TypeRefinementContext::TypeRefinementContext(
35
36
ExplicitAvailabilityInfo(ExplicitInfo) {
36
37
if (Parent) {
37
38
assert (SrcRange.isValid ());
38
- Parent->addChild (this );
39
+ Parent->addChild (this , Ctx );
39
40
assert (Info.isContainedIn (Parent->getAvailabilityInfo ()));
40
41
}
41
42
Ctx.addDestructorCleanup (Children);
@@ -169,52 +170,64 @@ TypeRefinementContext::createForWhileStmtBody(ASTContext &Ctx, WhileStmt *S,
169
170
Ctx, S, Parent, S->getBody ()->getSourceRange (), Info, /* ExplicitInfo */ Info);
170
171
}
171
172
172
- // / Determine whether the child location is somewhere within the parent
173
- // / range.
174
- static bool rangeContainsTokenLocWithGeneratedSource (
175
- SourceManager &sourceMgr, SourceRange parentRange, SourceLoc childLoc) {
176
- if (sourceMgr.rangeContainsTokenLoc (parentRange, childLoc))
177
- return true ;
178
-
179
- auto childBuffer = sourceMgr.findBufferContainingLoc (childLoc);
180
- while (!sourceMgr.rangeContainsTokenLoc (
181
- sourceMgr.getRangeForBuffer (childBuffer), parentRange.Start )) {
182
- auto *info = sourceMgr.getGeneratedSourceInfo (childBuffer);
183
- if (!info)
184
- return false ;
185
-
186
- childLoc = info->originalSourceRange .getStart ();
187
- if (childLoc.isInvalid ())
188
- return false ;
189
-
190
- childBuffer = sourceMgr.findBufferContainingLoc (childLoc);
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 ;
191
181
}
192
182
193
- return sourceMgr.rangeContainsTokenLoc (parentRange, childLoc);
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);
194
201
}
195
202
196
203
TypeRefinementContext *
197
204
TypeRefinementContext::findMostRefinedSubContext (SourceLoc Loc,
198
205
ASTContext &Ctx) {
199
206
assert (Loc.isValid ());
200
207
201
- if (SrcRange.isValid () &&
202
- !rangeContainsTokenLocWithGeneratedSource (Ctx.SourceMgr , SrcRange, Loc))
208
+ if (SrcRange.isValid () && !Ctx.SourceMgr .containsTokenLoc (SrcRange, Loc))
203
209
return nullptr ;
204
210
205
211
auto expandedChildren = evaluateOrDefault (
206
212
Ctx.evaluator , ExpandChildTypeRefinementContextsRequest{this }, {});
207
213
208
- // For the moment, we perform a linear search here, but we can and should
209
- // do something more efficient.
210
- for (TypeRefinementContext *Child : expandedChildren) {
211
- if (auto *Found = Child->findMostRefinedSubContext (Loc, Ctx)) {
212
- return Found;
213
- }
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;
214
227
}
215
228
216
- // Loc is in this context's range but not in any child's, so this context
217
- // 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.
218
231
return this ;
219
232
}
220
233
@@ -391,7 +404,24 @@ void TypeRefinementContext::print(raw_ostream &OS, SourceManager &SrcMgr,
391
404
auto R = getSourceRange ();
392
405
if (R.isValid ()) {
393
406
OS << " src_range=" ;
394
- R.print (OS, SrcMgr, /* PrintText=*/ false );
407
+
408
+ if (getReason () != Reason::Root) {
409
+ R.print (OS, SrcMgr, /* PrintText=*/ false );
410
+ } else if (auto info = SrcMgr.getGeneratedSourceInfo (
411
+ Node.getAsSourceFile ()->getBufferID ())) {
412
+ info->originalSourceRange .print (OS, SrcMgr, /* PrintText=*/ false );
413
+ } else {
414
+ OS << " <unknown>" ;
415
+ }
416
+ }
417
+
418
+ if (getReason () == Reason::Root) {
419
+ if (auto info = SrcMgr.getGeneratedSourceInfo (
420
+ Node.getAsSourceFile ()->getBufferID ())) {
421
+ OS << " generated_kind=" << GeneratedSourceInfo::kindToString (info->kind );
422
+ } else {
423
+ OS << " file=" << Node.getAsSourceFile ()->getFilename ().str ();
424
+ }
395
425
}
396
426
397
427
if (!ExplicitAvailabilityInfo.isAlwaysAvailable ())
@@ -462,3 +492,78 @@ void ExpandChildTypeRefinementContextsRequest::cacheResult(
462
492
TRC->Children = children;
463
493
TRC->setNeedsExpansion (false );
464
494
}
495
+
496
+ // / Emit an error message, dump each context with its corresponding label, and
497
+ // / abort.
498
+ static void
499
+ verificationError (ASTContext &ctx, llvm::StringRef msg,
500
+ std::initializer_list<
501
+ std::pair<const char *, const TypeRefinementContext *>>
502
+ labelsAndNodes) {
503
+ llvm::errs () << msg << " \n " ;
504
+ for (auto pair : labelsAndNodes) {
505
+ auto label = std::get<0 >(pair);
506
+ auto context = std::get<1 >(pair);
507
+ llvm::errs () << label << " :\n " ;
508
+ context->print (llvm::errs (), ctx.SourceMgr );
509
+ }
510
+ abort ();
511
+ }
512
+
513
+ void TypeRefinementContext::verify (const TypeRefinementContext *parent,
514
+ ASTContext &ctx) const {
515
+ // Verify the children first.
516
+ for (auto child : Children) {
517
+ child->verify (this , ctx);
518
+ }
519
+
520
+ // Verify that the children are in sorted order and that their source ranges
521
+ // do not overlap.
522
+ auto &srcMgr = ctx.SourceMgr ;
523
+ if (Children.size () > 1 ) {
524
+ auto const *previous = Children.front ();
525
+ for (auto const *current : ArrayRef (Children).drop_front ()) {
526
+ if (!srcMgr.isAtOrBefore (previous->getSourceRange ().Start ,
527
+ current->getSourceRange ().Start ))
528
+ verificationError (
529
+ ctx, " out of order children" ,
530
+ {{" child 1" , previous}, {" child 2" , current}, {" parent" , this }});
531
+
532
+ if (srcMgr.containsLoc (previous->getSourceRange (),
533
+ current->getSourceRange ().Start ))
534
+ verificationError (
535
+ ctx, " overlapping children" ,
536
+ {{" child 1" , previous}, {" child 2" , current}, {" parent" , this }});
537
+
538
+ previous = current;
539
+ }
540
+ }
541
+
542
+ // Only root nodes are allowed to have no parent.
543
+ if (!parent) {
544
+ if (getReason () != Reason::Root)
545
+ verificationError (ctx, " interior node without parent" , {{" node" , this }});
546
+ return ;
547
+ }
548
+
549
+ // All nodes with a parent must have a valid source range.
550
+ if (!SrcRange.isValid ())
551
+ verificationError (ctx, " invalid source range" , {{" node" , this }});
552
+
553
+ if (getReason () != Reason::Root) {
554
+ auto parentRange = parent->SrcRange ;
555
+ if (parentRange.isValid () &&
556
+ !(srcMgr.isAtOrBefore (parentRange.Start , SrcRange.Start ) &&
557
+ srcMgr.isAtOrBefore (SrcRange.End , parentRange.End )))
558
+ verificationError (ctx, " child source range not contained" ,
559
+ {{" child" , this }, {" parent" , this }});
560
+ }
561
+
562
+ if (!AvailabilityInfo.isContainedIn (parent->AvailabilityInfo ))
563
+ verificationError (ctx, " child availability range not contained" ,
564
+ {{" child" , this }, {" parent" , this }});
565
+ }
566
+
567
+ void TypeRefinementContext::verify (ASTContext &ctx) {
568
+ verify (nullptr , ctx);
569
+ }
0 commit comments