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,52 +170,64 @@ TypeRefinementContext::createForWhileStmtBody(ASTContext &Ctx, WhileStmt *S,
169170 Ctx, S, Parent, S->getBody ()->getSourceRange (), Info, /* ExplicitInfo */ Info);
170171}
171172
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 ;
191181 }
192182
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);
194201}
195202
196203TypeRefinementContext *
197204TypeRefinementContext::findMostRefinedSubContext (SourceLoc Loc,
198205 ASTContext &Ctx) {
199206 assert (Loc.isValid ());
200207
201- if (SrcRange.isValid () &&
202- !rangeContainsTokenLocWithGeneratedSource (Ctx.SourceMgr , SrcRange, Loc))
208+ if (SrcRange.isValid () && !Ctx.SourceMgr .containsTokenLoc (SrcRange, Loc))
203209 return nullptr ;
204210
205211 auto expandedChildren = evaluateOrDefault (
206212 Ctx.evaluator , ExpandChildTypeRefinementContextsRequest{this }, {});
207213
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;
214227 }
215228
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.
218231 return this ;
219232}
220233
@@ -391,7 +404,24 @@ void TypeRefinementContext::print(raw_ostream &OS, SourceManager &SrcMgr,
391404 auto R = getSourceRange ();
392405 if (R.isValid ()) {
393406 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+ }
395425 }
396426
397427 if (!ExplicitAvailabilityInfo.isAlwaysAvailable ())
@@ -462,3 +492,78 @@ void ExpandChildTypeRefinementContextsRequest::cacheResult(
462492 TRC->Children = children;
463493 TRC->setNeedsExpansion (false );
464494}
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