Skip to content

Commit c80a19e

Browse files
beccadaxtshortli
authored andcommitted
[NFC] Allow many TypeRefinementContexts per decl
This PR modifies TypeRefinementContextBuilder to separate the implicit TRC around accessors from the creation of a new TRC for other declarations. This ability to introduce several TRCs for a single declaration will come in handy later. It also refines the modeling of TRCs, particularly for properties and accessors, in a few others ways. Those changes are also currently NFC, but will become important down the line when function bodies start to become their own TRCs.
1 parent bbcd980 commit c80a19e

File tree

1 file changed

+50
-25
lines changed

1 file changed

+50
-25
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -355,34 +355,61 @@ class TypeRefinementContextBuilder : private ASTWalker {
355355

356356
private:
357357
bool walkToDeclPre(Decl *D) override {
358-
TypeRefinementContext *DeclTRC = getNewContextForWalkOfDecl(D);
358+
// Adds in a parent TRC for decls which are syntatically nested but are not
359+
// represented that way in the AST. (Particularly, AbstractStorageDecl
360+
// parents for AccessorDecl children.)
361+
if (auto ParentTRC = getEffectiveParentContextForDecl(D)) {
362+
pushContext(ParentTRC, D);
363+
}
359364

360-
if (DeclTRC) {
365+
// Adds in a TRC that covers the entire declaration.
366+
if (auto DeclTRC = getNewContextForSignatureOfDecl(D)) {
361367
pushContext(DeclTRC, D);
362368
}
363369

364370
return true;
365371
}
366372

367373
bool walkToDeclPost(Decl *D) override {
368-
if (ContextStack.back().ScopeNode.getAsDecl() == D) {
374+
// As seen above, we could have up to two TRCs in the stack for a single
375+
// declaration.
376+
while (ContextStack.back().ScopeNode.getAsDecl() == D) {
369377
ContextStack.pop_back();
370378
}
371379
return true;
372380
}
373381

374-
/// Returns a new context to be introduced for the declaration, or nullptr
375-
/// if no new context should be introduced.
376-
TypeRefinementContext *getNewContextForWalkOfDecl(Decl *D) {
382+
TypeRefinementContext *getEffectiveParentContextForDecl(Decl *D) {
377383
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
378384
// Use TRC of the storage rather the current TRC when walking this
379385
// function.
386+
// FIXME: Can we assert that we won't process storage later that should
387+
// have been returned now?
380388
auto it = StorageContexts.find(accessor->getStorage());
381389
if (it != StorageContexts.end()) {
382390
return it->second;
383391
}
384392
}
385-
393+
return nullptr;
394+
}
395+
396+
/// If necessary, records a TRC so it can be returned by subsequent calls to
397+
/// `getEffectiveParentContextForDecl()`.
398+
void recordEffectiveParentContext(Decl *D, TypeRefinementContext *NewTRC) {
399+
// Record the TRC for this storage declaration so that
400+
// when we process the accessor, we can use this TRC as the
401+
// parent in `getEffectiveParentContextForDecl()`.
402+
if (auto *StorageDecl = dyn_cast<AbstractStorageDecl>(D)) {
403+
if (StorageDecl->hasParsedAccessors()) {
404+
// FIXME: Can we assert that we've never queried for this storage?
405+
StorageContexts[StorageDecl] = NewTRC;
406+
}
407+
}
408+
}
409+
410+
/// Returns a new context to be introduced for the declaration, or nullptr
411+
/// if no new context should be introduced.
412+
TypeRefinementContext *getNewContextForSignatureOfDecl(Decl *D) {
386413
if (declarationIntroducesNewContext(D)) {
387414
return buildDeclarationRefinementContext(D);
388415
}
@@ -414,15 +441,10 @@ class TypeRefinementContextBuilder : private ASTWalker {
414441
ExplicitDeclInfo,
415442
refinementSourceRangeForDecl(D));
416443

417-
// Record the TRC for this storage declaration so that
418-
// when we process the accessor, we can use this TRC as the
419-
// parent.
420-
if (auto *StorageDecl = dyn_cast<AbstractStorageDecl>(D)) {
421-
if (StorageDecl->hasParsedAccessors()) {
422-
StorageContexts[StorageDecl] = NewTRC;
423-
}
424-
}
425-
444+
445+
// Possibly use this as an effective parent context later.
446+
recordEffectiveParentContext(D, NewTRC);
447+
426448
return NewTRC;
427449
}
428450

@@ -460,6 +482,16 @@ class TypeRefinementContextBuilder : private ASTWalker {
460482
// Use the declaration's availability for the context when checking
461483
// the bodies of its accessors.
462484

485+
Decl *locDecl = D;
486+
// For a variable declaration (without accessors) we use the range of the
487+
// containing pattern binding declaration to make sure that we include
488+
// any type annotation in the type refinement context range.
489+
if (auto varDecl = dyn_cast<VarDecl>(storageDecl)) {
490+
auto *PBD = varDecl->getParentPatternBinding();
491+
if (PBD)
492+
locDecl = PBD;
493+
}
494+
463495
// HACK: For synthesized trivial accessors we may have not a valid
464496
// location for the end of the braces, so in that case we will fall back
465497
// to using the range for the storage declaration. The right fix here is
@@ -468,18 +500,11 @@ class TypeRefinementContextBuilder : private ASTWalker {
468500
// locations.
469501
SourceLoc BracesEnd = storageDecl->getBracesRange().End;
470502
if (storageDecl->hasParsedAccessors() && BracesEnd.isValid()) {
471-
return SourceRange(storageDecl->getStartLoc(),
503+
return SourceRange(locDecl->getStartLoc(),
472504
BracesEnd);
473505
}
474506

475-
// For a variable declaration (without accessors) we use the range of the
476-
// containing pattern binding declaration to make sure that we include
477-
// any type annotation in the type refinement context range.
478-
if (auto varDecl = dyn_cast<VarDecl>(storageDecl)) {
479-
auto *PBD = varDecl->getParentPatternBinding();
480-
if (PBD)
481-
return PBD->getSourceRange();
482-
}
507+
return locDecl->getSourceRange();
483508
}
484509

485510
return D->getSourceRange();

0 commit comments

Comments
 (0)