Skip to content

Commit b20f2c0

Browse files
authored
Merge pull request #79517 from tshortli/availability-scope-decl-context
AST: Store the active `DeclContext` in `AvailabilityScope`
2 parents 3db2b97 + 1ff1a8d commit b20f2c0

File tree

3 files changed

+115
-72
lines changed

3 files changed

+115
-72
lines changed

include/swift/AST/AvailabilityScope.h

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class AvailabilityScope : public ASTAllocated<AvailabilityScope> {
9898
/// Represents the AST node that introduced an availability scope.
9999
class IntroNode {
100100
Reason IntroReason;
101+
const DeclContext *DC;
101102
union {
102103
SourceFile *SF;
103104
Decl *D;
@@ -108,25 +109,26 @@ class AvailabilityScope : public ASTAllocated<AvailabilityScope> {
108109
};
109110

110111
public:
111-
IntroNode(SourceFile *SF) : IntroReason(Reason::Root), SF(SF) {}
112-
IntroNode(Decl *D, Reason introReason = Reason::Decl)
113-
: IntroReason(introReason), D(D) {
114-
(void)getAsDecl(); // check that assertion succeeds
115-
}
116-
IntroNode(IfStmt *IS, bool IsThen)
112+
IntroNode(SourceFile *SF);
113+
IntroNode(Decl *D, Reason introReason = Reason::Decl);
114+
IntroNode(IfStmt *IS, const DeclContext *DC, bool IsThen)
117115
: IntroReason(IsThen ? Reason::IfStmtThenBranch
118116
: Reason::IfStmtElseBranch),
119-
IS(IS) {}
120-
IntroNode(PoundAvailableInfo *PAI)
121-
: IntroReason(Reason::ConditionFollowingAvailabilityQuery), PAI(PAI) {}
122-
IntroNode(GuardStmt *GS, bool IsFallthrough)
117+
DC(DC), IS(IS) {}
118+
IntroNode(PoundAvailableInfo *PAI, const DeclContext *DC)
119+
: IntroReason(Reason::ConditionFollowingAvailabilityQuery), DC(DC),
120+
PAI(PAI) {}
121+
IntroNode(GuardStmt *GS, const DeclContext *DC, bool IsFallthrough)
123122
: IntroReason(IsFallthrough ? Reason::GuardStmtFallthrough
124123
: Reason::GuardStmtElseBranch),
125-
GS(GS) {}
126-
IntroNode(WhileStmt *WS) : IntroReason(Reason::WhileStmtBody), WS(WS) {}
124+
DC(DC), GS(GS) {}
125+
IntroNode(WhileStmt *WS, const DeclContext *DC)
126+
: IntroReason(Reason::WhileStmtBody), DC(DC), WS(WS) {}
127127

128128
Reason getReason() const { return IntroReason; }
129129

130+
const DeclContext *getDeclContext() const { return DC; }
131+
130132
SourceFile *getAsSourceFile() const {
131133
assert(IntroReason == Reason::Root);
132134
return SF;
@@ -200,37 +202,39 @@ class AvailabilityScope : public ASTAllocated<AvailabilityScope> {
200202

201203
/// Create an availability scope for the Then branch of the given IfStmt.
202204
static AvailabilityScope *createForIfStmtThen(ASTContext &Ctx, IfStmt *S,
205+
const DeclContext *DC,
203206
AvailabilityScope *Parent,
204207
const AvailabilityContext Info);
205208

206209
/// Create an availability scope for the Else branch of the given IfStmt.
207210
static AvailabilityScope *createForIfStmtElse(ASTContext &Ctx, IfStmt *S,
211+
const DeclContext *DC,
208212
AvailabilityScope *Parent,
209213
const AvailabilityContext Info);
210214

211215
/// Create an availability scope for the true-branch control flow to
212216
/// further StmtConditionElements following a #available() query in
213217
/// a StmtCondition.
214-
static AvailabilityScope *
215-
createForConditionFollowingQuery(ASTContext &Ctx, PoundAvailableInfo *PAI,
216-
const StmtConditionElement &LastElement,
217-
AvailabilityScope *Parent,
218-
const AvailabilityContext Info);
218+
static AvailabilityScope *createForConditionFollowingQuery(
219+
ASTContext &Ctx, PoundAvailableInfo *PAI,
220+
const StmtConditionElement &LastElement, const DeclContext *DC,
221+
AvailabilityScope *Parent, const AvailabilityContext Info);
219222

220223
/// Create an availability scope for the fallthrough of a GuardStmt.
221224
static AvailabilityScope *createForGuardStmtFallthrough(
222225
ASTContext &Ctx, GuardStmt *RS, BraceStmt *ContainingBraceStmt,
223-
AvailabilityScope *Parent, const AvailabilityContext Info);
226+
const DeclContext *DC, AvailabilityScope *Parent,
227+
const AvailabilityContext Info);
224228

225229
/// Create an availability scope for the else branch of a GuardStmt.
226230
static AvailabilityScope *
227-
createForGuardStmtElse(ASTContext &Ctx, GuardStmt *RS,
231+
createForGuardStmtElse(ASTContext &Ctx, GuardStmt *RS, const DeclContext *DC,
228232
AvailabilityScope *Parent,
229233
const AvailabilityContext Info);
230234

231235
/// Create an availability scope for the body of a WhileStmt.
232236
static AvailabilityScope *
233-
createForWhileStmtBody(ASTContext &Ctx, WhileStmt *WS,
237+
createForWhileStmtBody(ASTContext &Ctx, WhileStmt *WS, const DeclContext *DC,
234238
AvailabilityScope *Parent,
235239
const AvailabilityContext Info);
236240

lib/AST/AvailabilityScope.cpp

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@
3030

3131
using namespace swift;
3232

33+
AvailabilityScope::IntroNode::IntroNode(SourceFile *SF)
34+
: IntroReason(Reason::Root), DC(SF), SF(SF) {}
35+
36+
AvailabilityScope::IntroNode::IntroNode(Decl *D, Reason introReason)
37+
: IntroReason(introReason), DC(D->getDeclContext()), D(D) {
38+
(void)getAsDecl(); // check that assertion succeeds
39+
}
40+
3341
AvailabilityScope::AvailabilityScope(ASTContext &Ctx, IntroNode Node,
3442
AvailabilityScope *Parent,
3543
SourceRange SrcRange,
@@ -99,67 +107,66 @@ AvailabilityScope *AvailabilityScope::createForDeclImplicit(
99107
Parent, SrcRange, Info);
100108
}
101109

102-
AvailabilityScope *
103-
AvailabilityScope::createForIfStmtThen(ASTContext &Ctx, IfStmt *S,
104-
AvailabilityScope *Parent,
105-
const AvailabilityContext Info) {
110+
AvailabilityScope *AvailabilityScope::createForIfStmtThen(
111+
ASTContext &Ctx, IfStmt *S, const DeclContext *DC,
112+
AvailabilityScope *Parent, const AvailabilityContext Info) {
106113
assert(S);
107114
assert(Parent);
108-
return new (Ctx) AvailabilityScope(Ctx, IntroNode(S, /*IsThen=*/true), Parent,
109-
S->getThenStmt()->getSourceRange(), Info);
115+
return new (Ctx)
116+
AvailabilityScope(Ctx, IntroNode(S, DC, /*IsThen=*/true), Parent,
117+
S->getThenStmt()->getSourceRange(), Info);
110118
}
111119

112-
AvailabilityScope *
113-
AvailabilityScope::createForIfStmtElse(ASTContext &Ctx, IfStmt *S,
114-
AvailabilityScope *Parent,
115-
const AvailabilityContext Info) {
120+
AvailabilityScope *AvailabilityScope::createForIfStmtElse(
121+
ASTContext &Ctx, IfStmt *S, const DeclContext *DC,
122+
AvailabilityScope *Parent, const AvailabilityContext Info) {
116123
assert(S);
117124
assert(Parent);
118125
return new (Ctx)
119-
AvailabilityScope(Ctx, IntroNode(S, /*IsThen=*/false), Parent,
126+
AvailabilityScope(Ctx, IntroNode(S, DC, /*IsThen=*/false), Parent,
120127
S->getElseStmt()->getSourceRange(), Info);
121128
}
122129

123130
AvailabilityScope *AvailabilityScope::createForConditionFollowingQuery(
124131
ASTContext &Ctx, PoundAvailableInfo *PAI,
125-
const StmtConditionElement &LastElement, AvailabilityScope *Parent,
126-
const AvailabilityContext Info) {
132+
const StmtConditionElement &LastElement, const DeclContext *DC,
133+
AvailabilityScope *Parent, const AvailabilityContext Info) {
127134
assert(PAI);
128135
assert(Parent);
129136
SourceRange Range(PAI->getEndLoc(), LastElement.getEndLoc());
130-
return new (Ctx) AvailabilityScope(Ctx, PAI, Parent, Range, Info);
137+
return new (Ctx)
138+
AvailabilityScope(Ctx, IntroNode(PAI, DC), Parent, Range, Info);
131139
}
132140

133141
AvailabilityScope *AvailabilityScope::createForGuardStmtFallthrough(
134142
ASTContext &Ctx, GuardStmt *RS, BraceStmt *ContainingBraceStmt,
135-
AvailabilityScope *Parent, const AvailabilityContext Info) {
143+
const DeclContext *DC, AvailabilityScope *Parent,
144+
const AvailabilityContext Info) {
136145
assert(RS);
137146
assert(ContainingBraceStmt);
138147
assert(Parent);
139148
SourceRange Range(RS->getEndLoc(), ContainingBraceStmt->getEndLoc());
140-
return new (Ctx) AvailabilityScope(Ctx, IntroNode(RS, /*IsFallthrough=*/true),
141-
Parent, Range, Info);
149+
return new (Ctx) AvailabilityScope(
150+
Ctx, IntroNode(RS, DC, /*IsFallthrough=*/true), Parent, Range, Info);
142151
}
143152

144-
AvailabilityScope *
145-
AvailabilityScope::createForGuardStmtElse(ASTContext &Ctx, GuardStmt *RS,
146-
AvailabilityScope *Parent,
147-
const AvailabilityContext Info) {
153+
AvailabilityScope *AvailabilityScope::createForGuardStmtElse(
154+
ASTContext &Ctx, GuardStmt *RS, const DeclContext *DC,
155+
AvailabilityScope *Parent, const AvailabilityContext Info) {
148156
assert(RS);
149157
assert(Parent);
150158
return new (Ctx)
151-
AvailabilityScope(Ctx, IntroNode(RS, /*IsFallthrough=*/false), Parent,
159+
AvailabilityScope(Ctx, IntroNode(RS, DC, /*IsFallthrough=*/false), Parent,
152160
RS->getBody()->getSourceRange(), Info);
153161
}
154162

155-
AvailabilityScope *
156-
AvailabilityScope::createForWhileStmtBody(ASTContext &Ctx, WhileStmt *S,
157-
AvailabilityScope *Parent,
158-
const AvailabilityContext Info) {
163+
AvailabilityScope *AvailabilityScope::createForWhileStmtBody(
164+
ASTContext &Ctx, WhileStmt *S, const DeclContext *DC,
165+
AvailabilityScope *Parent, const AvailabilityContext Info) {
159166
assert(S);
160167
assert(Parent);
161-
return new (Ctx)
162-
AvailabilityScope(Ctx, S, Parent, S->getBody()->getSourceRange(), Info);
168+
return new (Ctx) AvailabilityScope(Ctx, IntroNode(S, DC), Parent,
169+
S->getBody()->getSourceRange(), Info);
163170
}
164171

165172
void AvailabilityScope::addChild(AvailabilityScope *Child, ASTContext &Ctx) {

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,17 @@ class AvailabilityScopeBuilder : private ASTWalker {
412412
};
413413
std::vector<DeclBodyContextInfo> DeclBodyContextStack;
414414

415+
std::vector<const DeclContext *> DeclContextStack;
416+
415417
AvailabilityScope *getCurrentScope() {
416418
return ContextStack.back().Scope;
417419
}
418420

421+
const DeclContext *getCurrentDeclContext() const {
422+
assert(!DeclContextStack.empty());
423+
return DeclContextStack.back();
424+
}
425+
419426
bool isCurrentScopeContainedByDeploymentTarget() {
420427
return ContextStack.back().ContainedByDeploymentTarget;
421428
}
@@ -467,6 +474,7 @@ class AvailabilityScopeBuilder : private ASTWalker {
467474
: Context(Context) {
468475
assert(Scope);
469476
pushContext(Scope, ParentTy());
477+
DeclContextStack.push_back(Scope->getIntroductionNode().getDeclContext());
470478
}
471479

472480
void build(Decl *D) {
@@ -588,27 +596,30 @@ class AvailabilityScopeBuilder : private ASTWalker {
588596

589597
// Implicit decls don't have source locations so they cannot have a scope.
590598
// However, some implicit nodes contain non-implicit nodes (e.g. defer
591-
// blocks) so continue rather than skipping the node entirely.
592-
if (D->isImplicit())
593-
return Action::Continue();
594-
595-
if (shouldSkipDecl(D))
596-
return Action::SkipNode();
597-
598-
// The AST of this decl may not be ready to traverse yet if it hasn't been
599-
// full typechecked. If that's the case, we leave a placeholder node in the
600-
// tree to indicate that the subtree should be expanded lazily when it
601-
// needs to be traversed.
602-
if (buildLazyContextForDecl(D))
603-
return Action::SkipNode();
599+
// blocks) so we must continue through them.
600+
if (!D->isImplicit()) {
601+
if (shouldSkipDecl(D))
602+
return Action::SkipNode();
603+
604+
// The AST of this decl may not be ready to traverse yet if it hasn't been
605+
// full typechecked. If that's the case, we leave a placeholder node in
606+
// the tree to indicate that the subtree should be expanded lazily when it
607+
// needs to be traversed.
608+
if (buildLazyContextForDecl(D))
609+
return Action::SkipNode();
610+
611+
// Adds in a scope that covers the entire declaration.
612+
if (auto DeclScope = getNewContextForSignatureOfDecl(D)) {
613+
pushContext(DeclScope, D);
614+
}
604615

605-
// Adds in a scope that covers the entire declaration.
606-
if (auto DeclScope = getNewContextForSignatureOfDecl(D)) {
607-
pushContext(DeclScope, D);
616+
// Create scopes that cover only the body of the declaration.
617+
buildContextsForBodyOfDecl(D);
608618
}
609619

610-
// Create scopes that cover only the body of the declaration.
611-
buildContextsForBodyOfDecl(D);
620+
if (auto *DC = dyn_cast<DeclContext>(D)) {
621+
DeclContextStack.push_back(DC);
622+
}
612623

613624
// If this decl is the concrete syntax decl for some abstract syntax decl,
614625
// push it onto the stack so that the abstract syntax decls may be visited.
@@ -624,6 +635,11 @@ class AvailabilityScopeBuilder : private ASTWalker {
624635
ConcreteDeclStack.pop_back();
625636
}
626637

638+
if (auto *DC = dyn_cast<DeclContext>(D)) {
639+
assert(DeclContextStack.back() == DC);
640+
DeclContextStack.pop_back();
641+
}
642+
627643
while (ContextStack.back().ScopeNode.getAsDecl() == D) {
628644
ContextStack.pop_back();
629645
}
@@ -1041,7 +1057,8 @@ class AvailabilityScopeBuilder : private ASTWalker {
10411057
auto AvailabilityContext =
10421058
constrainCurrentAvailabilityWithPlatformRange(ThenRange.value());
10431059
auto *ThenScope = AvailabilityScope::createForIfStmtThen(
1044-
Context, IS, getCurrentScope(), AvailabilityContext);
1060+
Context, IS, getCurrentDeclContext(), getCurrentScope(),
1061+
AvailabilityContext);
10451062
AvailabilityScopeBuilder(ThenScope, Context).build(IS->getThenStmt());
10461063
} else {
10471064
build(IS->getThenStmt());
@@ -1064,7 +1081,8 @@ class AvailabilityScopeBuilder : private ASTWalker {
10641081
auto AvailabilityContext =
10651082
constrainCurrentAvailabilityWithPlatformRange(ElseRange.value());
10661083
auto *ElseScope = AvailabilityScope::createForIfStmtElse(
1067-
Context, IS, getCurrentScope(), AvailabilityContext);
1084+
Context, IS, getCurrentDeclContext(), getCurrentScope(),
1085+
AvailabilityContext);
10681086
AvailabilityScopeBuilder(ElseScope, Context).build(ElseStmt);
10691087
} else {
10701088
build(IS->getElseStmt());
@@ -1085,7 +1103,8 @@ class AvailabilityScopeBuilder : private ASTWalker {
10851103
auto AvailabilityContext =
10861104
constrainCurrentAvailabilityWithPlatformRange(BodyRange.value());
10871105
auto *BodyScope = AvailabilityScope::createForWhileStmtBody(
1088-
Context, WS, getCurrentScope(), AvailabilityContext);
1106+
Context, WS, getCurrentDeclContext(), getCurrentScope(),
1107+
AvailabilityContext);
10891108
AvailabilityScopeBuilder(BodyScope, Context).build(WS->getBody());
10901109
} else {
10911110
build(WS->getBody());
@@ -1118,7 +1137,8 @@ class AvailabilityScopeBuilder : private ASTWalker {
11181137
auto AvailabilityContext =
11191138
constrainCurrentAvailabilityWithPlatformRange(ElseRange.value());
11201139
auto *TrueScope = AvailabilityScope::createForGuardStmtElse(
1121-
Context, GS, getCurrentScope(), AvailabilityContext);
1140+
Context, GS, getCurrentDeclContext(), getCurrentScope(),
1141+
AvailabilityContext);
11221142

11231143
AvailabilityScopeBuilder(TrueScope, Context).build(ElseBody);
11241144
} else {
@@ -1135,7 +1155,8 @@ class AvailabilityScopeBuilder : private ASTWalker {
11351155
auto FallthroughAvailability =
11361156
constrainCurrentAvailabilityWithPlatformRange(FallthroughRange.value());
11371157
auto *FallthroughScope = AvailabilityScope::createForGuardStmtFallthrough(
1138-
Context, GS, ParentBrace, getCurrentScope(), FallthroughAvailability);
1158+
Context, GS, ParentBrace, getCurrentDeclContext(), getCurrentScope(),
1159+
FallthroughAvailability);
11391160

11401161
pushContext(FallthroughScope, ParentBrace);
11411162
}
@@ -1293,7 +1314,8 @@ class AvailabilityScopeBuilder : private ASTWalker {
12931314
auto ConstrainedAvailability =
12941315
constrainCurrentAvailabilityWithPlatformRange(NewConstraint);
12951316
auto *Scope = AvailabilityScope::createForConditionFollowingQuery(
1296-
Context, Query, LastElement, CurrentScope, ConstrainedAvailability);
1317+
Context, Query, LastElement, getCurrentDeclContext(), CurrentScope,
1318+
ConstrainedAvailability);
12971319

12981320
pushContext(Scope, ParentTy());
12991321
++NestedCount;
@@ -1399,6 +1421,11 @@ class AvailabilityScopeBuilder : private ASTWalker {
13991421

14001422
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
14011423
(void)consumeDeclBodyContextIfNecessary(E);
1424+
1425+
if (auto CE = dyn_cast<ClosureExpr>(E)) {
1426+
DeclContextStack.push_back(CE);
1427+
}
1428+
14021429
return Action::Continue(E);
14031430
}
14041431

@@ -1407,6 +1434,11 @@ class AvailabilityScopeBuilder : private ASTWalker {
14071434
ContextStack.pop_back();
14081435
}
14091436

1437+
if (auto *CE = dyn_cast<ClosureExpr>(E)) {
1438+
assert(DeclContextStack.back() == CE);
1439+
DeclContextStack.pop_back();
1440+
}
1441+
14101442
return Action::Continue(E);
14111443
}
14121444
};

0 commit comments

Comments
 (0)