Skip to content

Commit ef93134

Browse files
committed
AST/ASTWalker: Refactor for recursive MemberTypeRepr representation
1 parent cdfe5a0 commit ef93134

18 files changed

+979
-152
lines changed

include/swift/AST/ASTWalker.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,37 @@ enum class MacroWalking {
103103
None
104104
};
105105

106+
/// A scheme for walking a `MemberTypeRepr`.
107+
enum class MemberTypeReprWalkingScheme {
108+
/// Walk in source order, such that each subsequent dot-separated component is
109+
/// a child of the previous one. For example, walk `A.B<T.U>.C` like so
110+
/// (top-down order):
111+
///
112+
/// ```
113+
/// A
114+
/// ╰─B
115+
/// ├─T
116+
/// │ ╰─U
117+
/// ╰─C
118+
/// ```
119+
SourceOrderRecursive,
120+
121+
/// Walk in AST order (that is, according to how member type
122+
/// representations are modeled in the AST, such that each previous
123+
/// dot-separated component is a child of the subsequent one), base before
124+
/// generic arguments. For example, walk `A.B<T.U>.C` like so
125+
/// (top-down order):
126+
///
127+
/// ```
128+
/// C
129+
/// ╰─B
130+
/// ├─A
131+
/// ╰─U
132+
/// ╰─T
133+
/// ```
134+
ASTOrderRecursive
135+
};
136+
106137
/// An abstract class used to traverse an AST.
107138
class ASTWalker {
108139
public:
@@ -563,6 +594,11 @@ class ASTWalker {
563594
return Action::Continue();
564595
}
565596

597+
/// This method configures how to walk `MemberTypeRepr` nodes.
598+
virtual MemberTypeReprWalkingScheme getMemberTypeReprWalkingScheme() const {
599+
return MemberTypeReprWalkingScheme::ASTOrderRecursive;
600+
}
601+
566602
/// This method configures whether the walker should explore into the generic
567603
/// params in AbstractFunctionDecl and NominalTypeDecl.
568604
virtual bool shouldWalkIntoGenericParams() { return false; }

include/swift/AST/TypeDeclFinder.h

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
namespace swift {
2020

2121
class BoundGenericType;
22-
class IdentTypeRepr;
22+
class DeclRefTypeRepr;
2323
class NominalType;
2424
class TypeAliasType;
2525

@@ -57,15 +57,13 @@ class SimpleTypeDeclFinder : public TypeDeclFinder {
5757
: Callback(callback) {}
5858
};
5959

60-
/// Walks a \c TypeRepr to find all \c IdentTypeRepr nodes with bound
61-
/// type declarations.
62-
///
63-
/// Subclasses can either override #visitTypeDecl if they only care about
64-
/// types on their own, or #visitIdentTypeRepr if they want to keep
65-
/// the TypeRepr around.
66-
class TypeReprIdentFinder : public ASTWalker {
67-
/// The function to call when a \c IdentTypeRepr is seen.
68-
llvm::function_ref<bool(const IdentTypeRepr *)> Callback;
60+
/// Walks a `TypeRepr` and reports all `DeclRefTypeRepr` nodes with bound
61+
/// type declarations by invoking a given callback. These nodes are reported in
62+
/// depth- and base-first AST order. For example, nodes in `A<T>.B<U>` will be
63+
/// reported in the following order: `TAUB`.
64+
class DeclRefTypeReprFinder : public ASTWalker {
65+
/// The function to call when a `DeclRefTypeRepr` is seen.
66+
llvm::function_ref<bool(const DeclRefTypeRepr *)> Callback;
6967

7068
MacroWalking getMacroWalkingBehavior() const override {
7169
return MacroWalking::Arguments;
@@ -74,11 +72,10 @@ class TypeReprIdentFinder : public ASTWalker {
7472
PostWalkAction walkToTypeReprPost(TypeRepr *TR) override;
7573

7674
public:
77-
explicit TypeReprIdentFinder(
78-
llvm::function_ref<bool(const IdentTypeRepr *)> callback)
79-
: Callback(callback) {}
75+
explicit DeclRefTypeReprFinder(
76+
llvm::function_ref<bool(const DeclRefTypeRepr *)> callback)
77+
: Callback(callback) {}
8078
};
81-
8279
}
8380

8481
#endif

lib/AST/ASTWalker.cpp

Lines changed: 119 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,8 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
14381438
#define TYPEREPR(Id, Parent) bool visit##Id##TypeRepr(Id##TypeRepr *T);
14391439
#include "swift/AST/TypeReprNodes.def"
14401440

1441+
bool visitDeclRefTypeRepr(DeclRefTypeRepr *T);
1442+
14411443
using Action = ASTWalker::Action;
14421444

14431445
using PreWalkAction = ASTWalker::PreWalkAction;
@@ -1624,9 +1626,24 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
16241626
return false;
16251627
}
16261628

1629+
private:
1630+
/// Walk a `MemberTypeRepr` in source order such that each subsequent
1631+
/// dot-separated component is a child of the previous one
1632+
[[nodiscard]] bool doItInSourceOrderRecursive(MemberTypeRepr *T);
1633+
1634+
public:
16271635
/// Returns true on failure.
16281636
[[nodiscard]]
16291637
bool doIt(TypeRepr *T) {
1638+
if (auto *MTR = dyn_cast<MemberTypeRepr>(T)) {
1639+
switch (Walker.getMemberTypeReprWalkingScheme()) {
1640+
case MemberTypeReprWalkingScheme::SourceOrderRecursive:
1641+
return doItInSourceOrderRecursive(MTR);
1642+
case MemberTypeReprWalkingScheme::ASTOrderRecursive:
1643+
break;
1644+
}
1645+
}
1646+
16301647
return traverse(
16311648
Walker.walkToTypeReprPre(T),
16321649
[&]() { return visit(T); },
@@ -1706,6 +1723,89 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
17061723

17071724
} // end anonymous namespace
17081725

1726+
bool Traversal::doItInSourceOrderRecursive(MemberTypeRepr *T) {
1727+
// Qualified types are modeled resursively such that each previous
1728+
// dot-separated component is a child of the next one. To walk a member type
1729+
// representation according to
1730+
// `MemberTypeReprWalkingScheme::SourceOrderRecursive`:
1731+
1732+
// 1. Pre-walk the dot-separated components in source order. If asked to skip
1733+
// the children of a given component:
1734+
// 1. Set the depth at which to start post-walking later.
1735+
// 2. Skip its generic arguments and subsequent components.
1736+
std::function<bool(TypeRepr *, std::optional<unsigned> &, unsigned)>
1737+
doItInSourceOrderPre = [&](TypeRepr *T,
1738+
std::optional<unsigned> &StartPostWalkDepth,
1739+
unsigned Depth) {
1740+
if (auto *MemberTR = dyn_cast<MemberTypeRepr>(T)) {
1741+
if (doItInSourceOrderPre(MemberTR->getBase(), StartPostWalkDepth,
1742+
Depth + 1)) {
1743+
return true;
1744+
}
1745+
1746+
if (StartPostWalkDepth.has_value()) {
1747+
return false;
1748+
}
1749+
}
1750+
1751+
switch (this->Walker.walkToTypeReprPre(T).Action) {
1752+
case PreWalkAction::Stop:
1753+
return true;
1754+
case PreWalkAction::SkipChildren:
1755+
StartPostWalkDepth = Depth;
1756+
return false;
1757+
case PreWalkAction::SkipNode:
1758+
StartPostWalkDepth = Depth + 1;
1759+
return false;
1760+
case PreWalkAction::Continue:
1761+
break;
1762+
}
1763+
1764+
if (auto *DeclRefTR = dyn_cast<DeclRefTypeRepr>(T)) {
1765+
for (auto *Arg : DeclRefTR->getGenericArgs()) {
1766+
if (doIt(Arg)) {
1767+
return true;
1768+
}
1769+
}
1770+
} else if (visit(T)) {
1771+
return true;
1772+
}
1773+
1774+
return false;
1775+
};
1776+
1777+
// 2. Post-walk the components in reverse order, respecting the depth at which
1778+
// to start post-walking if set.
1779+
std::function<bool(TypeRepr *, std::optional<unsigned>, unsigned)>
1780+
doItInSourceOrderPost = [&](TypeRepr *T,
1781+
std::optional<unsigned> StartPostWalkDepth,
1782+
unsigned Depth) {
1783+
if (!StartPostWalkDepth.has_value() || Depth >= *StartPostWalkDepth) {
1784+
switch (this->Walker.walkToTypeReprPost(T).Action) {
1785+
case PostWalkAction::Continue:
1786+
break;
1787+
case PostWalkAction::Stop:
1788+
return true;
1789+
}
1790+
}
1791+
1792+
if (auto *MemberTR = dyn_cast<MemberTypeRepr>(T)) {
1793+
return doItInSourceOrderPost(MemberTR->getBase(), StartPostWalkDepth,
1794+
Depth + 1);
1795+
}
1796+
1797+
return false;
1798+
};
1799+
1800+
std::optional<unsigned> StartPostWalkDepth;
1801+
1802+
if (doItInSourceOrderPre(T, StartPostWalkDepth, 0)) {
1803+
return true;
1804+
}
1805+
1806+
return doItInSourceOrderPost(T, StartPostWalkDepth, 0);
1807+
}
1808+
17091809
#pragma mark Statement traversal
17101810
Stmt *Traversal::visitBreakStmt(BreakStmt *BS) {
17111811
return BS;
@@ -2130,27 +2230,32 @@ bool Traversal::visitAttributedTypeRepr(AttributedTypeRepr *T) {
21302230
return doIt(T->getTypeRepr());
21312231
}
21322232

2133-
bool Traversal::visitSimpleIdentTypeRepr(SimpleIdentTypeRepr *T) {
2134-
return false;
2135-
}
2233+
bool Traversal::visitDeclRefTypeRepr(DeclRefTypeRepr *T) {
2234+
if (auto *memberTR = dyn_cast<MemberTypeRepr>(T)) {
2235+
if (doIt(memberTR->getBase())) {
2236+
return true;
2237+
}
2238+
}
21362239

2137-
bool Traversal::visitGenericIdentTypeRepr(GenericIdentTypeRepr *T) {
2138-
for (auto genArg : T->getGenericArgs()) {
2139-
if (doIt(genArg))
2240+
for (auto *genericArg : T->getGenericArgs()) {
2241+
if (doIt(genericArg)) {
21402242
return true;
2243+
}
21412244
}
2245+
21422246
return false;
21432247
}
21442248

2145-
bool Traversal::visitMemberTypeRepr(MemberTypeRepr *T) {
2146-
if (doIt(T->getRoot()))
2147-
return true;
2249+
bool Traversal::visitSimpleIdentTypeRepr(SimpleIdentTypeRepr *T) {
2250+
return visitDeclRefTypeRepr(T);
2251+
}
21482252

2149-
for (auto comp : T->getMemberComponents()) {
2150-
if (doIt(comp))
2151-
return true;
2152-
}
2153-
return false;
2253+
bool Traversal::visitGenericIdentTypeRepr(GenericIdentTypeRepr *T) {
2254+
return visitDeclRefTypeRepr(T);
2255+
}
2256+
2257+
bool Traversal::visitMemberTypeRepr(MemberTypeRepr *T) {
2258+
return visitDeclRefTypeRepr(T);
21542259
}
21552260

21562261
bool Traversal::visitFunctionTypeRepr(FunctionTypeRepr *T) {

lib/AST/NameLookup.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3361,15 +3361,19 @@ CollectedOpaqueReprs swift::collectOpaqueTypeReprs(TypeRepr *r, ASTContext &ctx,
33613361
if (!composition->isTypeReprAny())
33623362
Reprs.push_back(composition);
33633363
return Action::SkipNode();
3364-
} else if (auto generic = dyn_cast<GenericIdentTypeRepr>(repr)) {
3365-
if (generic->isProtocolOrProtocolComposition(dc)){
3366-
Reprs.push_back(generic);
3367-
return Action::SkipNode();
3364+
} else if (isa<DeclRefTypeRepr>(repr)) {
3365+
// We only care about the type of an outermost member type
3366+
// representation. For example, in `A<T>.B.C<U>`, check `C` and generic
3367+
// arguments `U` and `T`, but not `A` or `B`.
3368+
if (auto *parentMemberTR =
3369+
dyn_cast_or_null<MemberTypeRepr>(Parent.getAsTypeRepr())) {
3370+
if (repr == parentMemberTR->getBase()) {
3371+
return Action::Continue();
3372+
}
33683373
}
3369-
return Action::Continue();
3370-
} else if (auto declRef = dyn_cast<DeclRefTypeRepr>(repr)) {
3371-
if (declRef->isProtocolOrProtocolComposition(dc))
3372-
Reprs.push_back(declRef);
3374+
3375+
if (repr->isProtocolOrProtocolComposition(dc))
3376+
Reprs.push_back(repr);
33733377
}
33743378
return Action::Continue();
33753379
}

lib/AST/TypeDeclFinder.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ SimpleTypeDeclFinder::visitTypeAliasType(TypeAliasType *ty) {
5050
}
5151

5252
ASTWalker::PostWalkAction
53-
TypeReprIdentFinder::walkToTypeReprPost(TypeRepr *TR) {
54-
auto ITR = dyn_cast<IdentTypeRepr>(TR);
55-
if (!ITR || !ITR->getBoundDecl())
53+
DeclRefTypeReprFinder::walkToTypeReprPost(TypeRepr *TR) {
54+
auto *declRefTR = dyn_cast<DeclRefTypeRepr>(TR);
55+
if (!declRefTR || !declRefTR->getBoundDecl())
5656
return Action::Continue();
57-
return Action::StopIf(!Callback(ITR));
57+
return Action::StopIf(!Callback(declRefTR));
5858
}

lib/IDE/SourceEntityWalker.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ class SemaAnnotator : public ASTWalker {
6262
return SEWalker.getMacroWalkingBehavior();
6363
}
6464

65+
MemberTypeReprWalkingScheme getMemberTypeReprWalkingScheme() const override {
66+
return MemberTypeReprWalkingScheme::SourceOrderRecursive;
67+
}
68+
6569
PreWalkAction walkToDeclPre(Decl *D) override;
6670
PreWalkAction walkToDeclPreProper(Decl *D);
6771
PreWalkResult<Expr *> walkToExprPre(Expr *E) override;
@@ -627,15 +631,15 @@ ASTWalker::PreWalkAction SemaAnnotator::walkToTypeReprPre(TypeRepr *T) {
627631
if (!Continue)
628632
return Action::Stop();
629633

630-
if (auto IdT = dyn_cast<IdentTypeRepr>(T)) {
631-
if (ValueDecl *VD = IdT->getBoundDecl()) {
634+
if (auto *DeclRefT = dyn_cast<DeclRefTypeRepr>(T)) {
635+
if (ValueDecl *VD = DeclRefT->getBoundDecl()) {
632636
if (auto *ModD = dyn_cast<ModuleDecl>(VD)) {
633-
auto ident = IdT->getNameRef().getBaseIdentifier();
634-
auto Continue = passReference(ModD, {ident, IdT->getLoc()});
637+
auto ident = DeclRefT->getNameRef().getBaseIdentifier();
638+
auto Continue = passReference(ModD, {ident, DeclRefT->getLoc()});
635639
return Action::StopIf(!Continue);
636640
}
637641
auto Continue = passReference(
638-
VD, Type(), IdT->getNameLoc(),
642+
VD, Type(), DeclRefT->getNameLoc(),
639643
ReferenceMetaData(SemaReferenceKind::TypeRef, llvm::None));
640644
return Action::StopIf(!Continue);
641645
}

lib/IDE/SyntaxModel.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,13 @@ class ModelASTWalker : public ASTWalker {
402402
PostWalkResult<Stmt *> walkToStmtPost(Stmt *S) override;
403403
PreWalkAction walkToDeclPre(Decl *D) override;
404404
PostWalkAction walkToDeclPost(Decl *D) override;
405+
406+
MemberTypeReprWalkingScheme getMemberTypeReprWalkingScheme() const override {
407+
return MemberTypeReprWalkingScheme::SourceOrderRecursive;
408+
}
409+
405410
PreWalkAction walkToTypeReprPre(TypeRepr *T) override;
411+
406412
bool shouldWalkIntoGenericParams() override { return true; }
407413

408414
private:
@@ -1122,12 +1128,12 @@ ASTWalker::PreWalkAction ModelASTWalker::walkToTypeReprPre(TypeRepr *T) {
11221128
if (!handleAttrs(AttrT->getAttrs()))
11231129
return Action::SkipNode();
11241130

1125-
} else if (auto IdT = dyn_cast<IdentTypeRepr>(T)) {
1126-
if (!passTokenNodesUntil(IdT->getStartLoc(),
1127-
ExcludeNodeAtLocation).shouldContinue)
1131+
} else if (auto *DeclRefT = dyn_cast<DeclRefTypeRepr>(T)) {
1132+
if (!passTokenNodesUntil(DeclRefT->getLoc(), ExcludeNodeAtLocation)
1133+
.shouldContinue)
11281134
return Action::SkipNode();
11291135
if (TokenNodes.empty() ||
1130-
TokenNodes.front().Range.getStart() != IdT->getStartLoc())
1136+
TokenNodes.front().Range.getStart() != DeclRefT->getLoc())
11311137
return Action::SkipNode();
11321138
if (!passNode({SyntaxNodeKind::TypeId, TokenNodes.front().Range}))
11331139
return Action::SkipNode();

lib/Parse/ParseType.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -557,10 +557,11 @@ ParserResult<TypeRepr> Parser::parseTypeScalar(
557557
}
558558

559559
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
560-
if (auto ident = dyn_cast<IdentTypeRepr>(T)) {
561-
if (auto decl = ident->getBoundDecl()) {
562-
if (auto genericParam = dyn_cast<GenericTypeParamDecl>(decl))
563-
ident->overwriteNameRef(genericParam->createNameRef());
560+
// Only unqualified identifiers can reference generic parameters.
561+
if (auto *simpleIdentTR = dyn_cast<SimpleIdentTypeRepr>(T)) {
562+
if (auto *genericParam = dyn_cast_or_null<GenericTypeParamDecl>(
563+
simpleIdentTR->getBoundDecl())) {
564+
simpleIdentTR->overwriteNameRef(genericParam->createNameRef());
564565
}
565566
}
566567
return Action::Continue();

0 commit comments

Comments
 (0)