Skip to content

Commit 37fb5dd

Browse files
authored
Merge pull request #76621 from tshortli/type-refinement-context-fixes
Sema: Various TypeRefinementContext tree fixes
2 parents 34def0e + 2f0a22c commit 37fb5dd

File tree

3 files changed

+86
-19
lines changed

3 files changed

+86
-19
lines changed

lib/AST/TypeRefinementContext.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,10 @@ void TypeRefinementContext::print(raw_ostream &OS, SourceManager &SrcMgr,
381381
if (auto VD = PBD->getAnchoringVarDecl(0)) {
382382
OS << VD->getName();
383383
}
384+
} else if (auto ECD = dyn_cast<EnumCaseDecl>(D)) {
385+
if (auto EED = ECD->getFirstElement()) {
386+
OS << EED->getName();
387+
}
384388
}
385389
}
386390

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
#include "llvm/Support/SaveAndRestore.h"
4545
using namespace swift;
4646

47+
static const Decl *
48+
concreteSyntaxDeclForAvailableAttribute(const Decl *AbstractSyntaxDecl);
49+
4750
ExportContext::ExportContext(
4851
DeclContext *DC, AvailabilityRange runningOSVersion,
4952
FragileFunctionKind kind, bool spi, bool exported, bool implicit,
@@ -451,6 +454,8 @@ class TypeRefinementContextBuilder : private ASTWalker {
451454
};
452455
std::vector<ContextInfo> ContextStack;
453456

457+
llvm::SmallVector<const Decl *, 4> ConcreteDeclStack;
458+
454459
/// Represents an entry in a stack of pending decl body type refinement
455460
/// contexts. TRCs in this stack should be pushed onto \p ContextStack when
456461
/// \p BodyStmt is encountered.
@@ -540,12 +545,27 @@ class TypeRefinementContextBuilder : private ASTWalker {
540545
return MacroWalking::Arguments;
541546
}
542547

548+
bool shouldSkipDecl(Decl *D) const {
549+
// Implicit decls don't have source locations so they cannot have a TRC.
550+
if (D->isImplicit())
551+
return true;
552+
553+
// Only visit a node that has a corresponding concrete syntax node if we are
554+
// already walking that concrete syntax node.
555+
auto *concreteDecl = concreteSyntaxDeclForAvailableAttribute(D);
556+
if (concreteDecl != D) {
557+
if (ConcreteDeclStack.empty() || ConcreteDeclStack.back() != concreteDecl)
558+
return true;
559+
}
560+
561+
return false;
562+
}
563+
543564
PreWalkAction walkToDeclPre(Decl *D) override {
544565
PrettyStackTraceDecl trace(stackTraceAction(), D);
545566

546-
// Implicit decls don't have source locations so they cannot have a TRC.
547-
if (D->isImplicit())
548-
return Action::Continue();
567+
if (shouldSkipDecl(D))
568+
return Action::SkipNode();
549569

550570
// The AST of this decl may not be ready to traverse yet if it hasn't been
551571
// full typechecked. If that's the case, we leave a placeholder node in the
@@ -561,10 +581,21 @@ class TypeRefinementContextBuilder : private ASTWalker {
561581

562582
// Create TRCs that cover only the body of the declaration.
563583
buildContextsForBodyOfDecl(D);
584+
585+
// If this decl is the concrete syntax decl for some abstract syntax decl,
586+
// push it onto the stack so that the abstract syntax decls may be visited.
587+
auto *abstractDecl = abstractSyntaxDeclForAvailableAttribute(D);
588+
if (abstractDecl != D) {
589+
ConcreteDeclStack.push_back(D);
590+
}
564591
return Action::Continue();
565592
}
566593

567594
PostWalkAction walkToDeclPost(Decl *D) override {
595+
if (!ConcreteDeclStack.empty() && ConcreteDeclStack.back() == D) {
596+
ConcreteDeclStack.pop_back();
597+
}
598+
568599
while (ContextStack.back().ScopeNode.getAsDecl() == D) {
569600
ContextStack.pop_back();
570601
}
@@ -640,6 +671,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
640671
/// if no new context should be introduced.
641672
TypeRefinementContext *getNewContextForSignatureOfDecl(Decl *D) {
642673
if (!isa<ValueDecl>(D) &&
674+
!isa<EnumCaseDecl>(D) &&
643675
!isa<ExtensionDecl>(D) &&
644676
!isa<MacroExpansionDecl>(D) &&
645677
!isa<PatternBindingDecl>(D))
@@ -651,12 +683,10 @@ class TypeRefinementContextBuilder : private ASTWalker {
651683
if (isa<AbstractStorageDecl>(D) && D->getDeclContext()->isLocalContext())
652684
return nullptr;
653685

654-
// Don't introduce for variable declarations that have a parent pattern
655-
// binding; all of the relevant information is on the pattern binding.
656-
if (auto var = dyn_cast<VarDecl>(D)) {
657-
if (var->getParentPatternBinding())
658-
return nullptr;
659-
}
686+
// Don't introduce for abstract syntax nodes that have separate concrete
687+
// syntax nodes. The TRC will be introduced for the concrete node instead.
688+
if (concreteSyntaxDeclForAvailableAttribute(D) != D)
689+
return nullptr;
660690

661691
// Declarations with an explicit availability attribute always get a TRC.
662692
if (hasActiveAvailableAttribute(D, Context)) {
@@ -1312,18 +1342,20 @@ class TypeRefinementContextBuilder : private ASTWalker {
13121342
} // end anonymous namespace
13131343

13141344
void TypeChecker::buildTypeRefinementContextHierarchy(SourceFile &SF) {
1315-
TypeRefinementContext *RootTRC = SF.getTypeRefinementContext();
13161345
ASTContext &Context = SF.getASTContext();
13171346
assert(!Context.LangOpts.DisableAvailabilityChecking);
13181347

1319-
if (!RootTRC) {
1320-
// The root type refinement context reflects the fact that all parts of
1321-
// the source file are guaranteed to be executing on at least the minimum
1322-
// platform version for inlining.
1323-
auto MinPlatformReq = AvailabilityRange::forInliningTarget(Context);
1324-
RootTRC = TypeRefinementContext::createForSourceFile(&SF, MinPlatformReq);
1325-
SF.setTypeRefinementContext(RootTRC);
1326-
}
1348+
// If there's already a root node, then we're done.
1349+
if (SF.getTypeRefinementContext())
1350+
return;
1351+
1352+
// The root type refinement context reflects the fact that all parts of
1353+
// the source file are guaranteed to be executing on at least the minimum
1354+
// platform version for inlining.
1355+
auto MinPlatformReq = AvailabilityRange::forInliningTarget(Context);
1356+
TypeRefinementContext *RootTRC =
1357+
TypeRefinementContext::createForSourceFile(&SF, MinPlatformReq);
1358+
SF.setTypeRefinementContext(RootTRC);
13271359

13281360
// Build refinement contexts, if necessary, for all declarations starting
13291361
// with StartElem.
@@ -1680,7 +1712,8 @@ concreteSyntaxDeclForAvailableAttribute(const Decl *AbstractSyntaxDecl) {
16801712
// event, multiple variables can be introduced with a single 'var'),
16811713
// so suggest adding an attribute to the PatterningBindingDecl instead.
16821714
if (auto *VD = dyn_cast<VarDecl>(AbstractSyntaxDecl)) {
1683-
return VD->getParentPatternBinding();
1715+
if (auto *PBD = VD->getParentPatternBinding())
1716+
return PBD;
16841717
}
16851718

16861719
// Similarly suggest applying the Fix-It to the parent enum case rather than

test/Sema/availability_refinement_contexts.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,33 @@ struct SomeStruct {
273273
@available(OSX 52, *)
274274
func someMethodAvailable52() -> Int { return 52 }
275275
}
276+
277+
// CHECK-NEXT: {{^}} (decl version=51 decl=SomeEnum
278+
// CHECK-NEXT: {{^}} (decl version=52 decl=a
279+
// CHECK-NEXT: {{^}} (decl version=53 decl=b
280+
281+
@available(OSX 51, *)
282+
enum SomeEnum {
283+
@available(OSX 52, *)
284+
case a
285+
286+
@available(OSX 53, *)
287+
case b, c
288+
}
289+
290+
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=someComputedGlobalVar
291+
// CHECK-NEXT: {{^}} (decl version=51 decl=_
292+
// CHECK-NEXT: {{^}} (decl version=52 decl=_
293+
294+
var someComputedGlobalVar: Int {
295+
@available(OSX 51, *)
296+
get { 1 }
297+
298+
@available(OSX 52, *)
299+
set { }
300+
}
301+
302+
// CHECK-NEXT: {{^}} (decl version=51 decl=FinalDecl
303+
304+
@available(OSX 51, *)
305+
typealias FinalDecl = Int

0 commit comments

Comments
 (0)