mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
mode (take 2)
Allow untyped placeholder to take arbitrary type, but default to Void.
Add _undefined<T>() function, which is like fatalError() but has
arbitrary return type. In playground mode, merely warn about outstanding
placeholders instead of erroring out, and transform placeholders into
calls to _undefined(). This way, code with outstanding placeholders will
only crash when it attempts to evaluate such placeholders.
When generating constraints for an iterated sequence of type T, emit
T convertible to $T1
$T1 conforms to SequenceType
instead of
T convertible to SequenceType
This ensures that an untyped placeholder in for-each sequence position
doesn't get inferred to have type SequenceType. (The conversion is still
necessary because the sequence may have IUO type.) The new constraint
system precipitates changes in CSSimplify and CSDiag, and ends up fixing
18741539 along the way.
(NOTE: There is a small regression in diagnosis of issues like the
following:
class C {}
class D: C {}
func f(a: [C]!) { for _: D in a {} }
It complains that [C]! doesn't conform to SequenceType when it should be
complaining that C is not convertible to D.)
<rdar://problem/21167372>
(Originally Swift SVN r31481)
1553 lines
38 KiB
C++
1553 lines
38 KiB
C++
//===--- ASTWalker.cpp - AST Traversal ------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements a recursive traversal of every node in an AST.
|
|
//
|
|
// It's important to update this traversal whenever the AST is
|
|
// changed, whether by adding a new node class or adding a new child
|
|
// to an existing node. Many walker implementations rely on being
|
|
// invoked with every node in the AST.
|
|
//
|
|
// Please follow these general rules when implementing traversal for
|
|
// a node:
|
|
//
|
|
// - Every node should be walked. If a node has both syntactic and
|
|
// semantic components, you should make sure you visit every node
|
|
// in both.
|
|
//
|
|
// - Nodes should only be walked once. So if a node has both
|
|
// syntactic and semantic components, but the type-checker builds
|
|
// the semantic components directly on top of the syntactic
|
|
// components, walking the semantic components will be sufficient
|
|
// to visit all the nodes in both.
|
|
//
|
|
// - Explicitly-written nodes should be walked in left-to-right
|
|
// syntactic order. The ordering of implicit nodes isn't
|
|
// particularly important.
|
|
//
|
|
// Note that semantic components will generally preserve the
|
|
// syntactic order of their children because doing something else
|
|
// could illegally change order of evaluation. This is why, for
|
|
// example, shuffling a TupleExpr creates a TupleShuffleExpr
|
|
// instead of just making a new TupleExpr with the elements in
|
|
// different order.
|
|
//
|
|
// - Sub-expressions and sub-statements should be replaceable.
|
|
// It's reasonable to expect that the replacement won't be
|
|
// completely unrelated to the original, but try to avoid making
|
|
// assumptions about the exact representation type. For example,
|
|
// assuming that a child expression is literally a TupleExpr may
|
|
// only be a reasonable assumption in an unchecked parse tree.
|
|
//
|
|
// - Avoid relying on the AST being type-checked or even
|
|
// well-formed during traversal.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/AST/ASTWalker.h"
|
|
#include "swift/AST/ASTVisitor.h"
|
|
#include "swift/AST/ExprHandle.h"
|
|
#include "swift/AST/PrettyStackTrace.h"
|
|
using namespace swift;
|
|
|
|
void ASTWalker::anchor() {}
|
|
|
|
namespace {
|
|
|
|
/// Traversal - This class implements a simple expression/statement
|
|
/// recursive traverser which queries a user-provided walker class
|
|
/// on every node in an AST.
|
|
class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
|
|
/*Decl*/ bool,
|
|
Pattern *, /*TypeRepr*/ bool>
|
|
{
|
|
friend class ASTVisitor<Traversal, Expr*, Stmt*, bool, Pattern*, bool>;
|
|
typedef ASTVisitor<Traversal, Expr*, Stmt*, bool, Pattern*, bool> inherited;
|
|
|
|
ASTWalker &Walker;
|
|
|
|
/// \brief RAII object that sets the parent of the walk context
|
|
/// appropriately.
|
|
class SetParentRAII {
|
|
ASTWalker &Walker;
|
|
decltype(ASTWalker::Parent) PriorParent;
|
|
|
|
public:
|
|
template<typename T>
|
|
SetParentRAII(ASTWalker &walker, T *newParent)
|
|
: Walker(walker), PriorParent(walker.Parent) {
|
|
walker.Parent = newParent;
|
|
}
|
|
|
|
~SetParentRAII() {
|
|
Walker.Parent = PriorParent;
|
|
}
|
|
};
|
|
|
|
Expr *visit(Expr *E) {
|
|
SetParentRAII SetParent(Walker, E);
|
|
return inherited::visit(E);
|
|
}
|
|
|
|
Stmt *visit(Stmt *S) {
|
|
SetParentRAII SetParent(Walker, S);
|
|
return inherited::visit(S);
|
|
}
|
|
|
|
Pattern *visit(Pattern *P) {
|
|
SetParentRAII SetParent(Walker, P);
|
|
return inherited::visit(P);
|
|
}
|
|
|
|
bool visit(Decl *D) {
|
|
SetParentRAII SetParent(Walker, D);
|
|
return inherited::visit(D);
|
|
}
|
|
|
|
bool visit(TypeRepr *T) {
|
|
SetParentRAII SetParent(Walker, T);
|
|
return inherited::visit(T);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/********************************** Decls **********************************/
|
|
/***************************************************************************/
|
|
|
|
bool visitImportDecl(ImportDecl *ID) {
|
|
return false;
|
|
}
|
|
|
|
bool visitExtensionDecl(ExtensionDecl *ED) {
|
|
if (doIt(ED->getExtendedTypeLoc()))
|
|
return true;
|
|
for (auto &Inherit : ED->getInherited()) {
|
|
if (doIt(Inherit))
|
|
return true;
|
|
}
|
|
for (Decl *M : ED->getMembers()) {
|
|
if (doIt(M))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool visitPatternBindingDecl(PatternBindingDecl *PBD) {
|
|
unsigned idx = 0U-1;
|
|
for (auto entry : PBD->getPatternList()) {
|
|
++idx;
|
|
if (Pattern *Pat = doIt(entry.getPattern()))
|
|
PBD->setPattern(idx, Pat);
|
|
else
|
|
return true;
|
|
if (entry.getInit()) {
|
|
#ifndef NDEBUG
|
|
PrettyStackTraceDecl debugStack("walking into initializer for", PBD);
|
|
#endif
|
|
if (Expr *E2 = doIt(entry.getInit()))
|
|
PBD->setInit(idx, E2);
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool visitEnumCaseDecl(EnumCaseDecl *ECD) {
|
|
// We'll visit the EnumElementDecls separately.
|
|
return false;
|
|
}
|
|
|
|
bool visitTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {
|
|
if (BraceStmt *S = cast_or_null<BraceStmt>(doIt(TLCD->getBody())))
|
|
TLCD->setBody(S);
|
|
return false;
|
|
}
|
|
|
|
bool visitIfConfigDecl(IfConfigDecl *ICD) {
|
|
// By default, just visit the declarations that are actually
|
|
// injected into the enclosing context.
|
|
return false;
|
|
}
|
|
|
|
bool visitOperatorDecl(OperatorDecl *OD) {
|
|
return false;
|
|
}
|
|
|
|
bool visitTypeAliasDecl(TypeAliasDecl *TAD) {
|
|
if (doIt(TAD->getUnderlyingTypeLoc()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool visitAbstractTypeParamDecl(AbstractTypeParamDecl *TPD) {
|
|
return false;
|
|
}
|
|
|
|
bool visitNominalTypeDecl(NominalTypeDecl *NTD) {
|
|
if(auto GPS = NTD->getGenericParams()) {
|
|
for (auto GP : GPS->getParams()) {
|
|
if (doIt(GP))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
for (auto &Inherit : NTD->getInherited()) {
|
|
if (doIt(Inherit))
|
|
return true;
|
|
}
|
|
for (Decl *Member : NTD->getMembers())
|
|
if (doIt(Member))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool visitModuleDecl(ModuleDecl *MD) {
|
|
// TODO: should we recurse within the module?
|
|
return false;
|
|
}
|
|
|
|
bool visitVarDecl(VarDecl *VD) {
|
|
return false;
|
|
}
|
|
|
|
bool visitSubscriptDecl(SubscriptDecl *SD) {
|
|
if (Pattern *NewPattern = doIt(SD->getIndices()))
|
|
SD->setIndices(NewPattern);
|
|
else
|
|
return true;
|
|
return doIt(SD->getElementTypeLoc());
|
|
}
|
|
|
|
bool visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
|
|
#ifndef NDEBUG
|
|
PrettyStackTraceDecl debugStack("walking into body of", AFD);
|
|
#endif
|
|
if (Walker.shouldWalkIntoFunctionGenericParams() &&
|
|
AFD->getGenericParams()) {
|
|
|
|
// Visit generic params
|
|
for (auto &P : AFD->getGenericParams()->getParams()) {
|
|
if (doIt(P))
|
|
return true;
|
|
for(auto Inherit : P->getInherited()) {
|
|
if (doIt(Inherit))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Visit param conformance
|
|
for (auto &Req : AFD->getGenericParams()->getRequirements()) {
|
|
switch (Req.getKind()) {
|
|
case RequirementKind::SameType:
|
|
if (doIt(Req.getFirstTypeLoc()) || doIt(Req.getSecondTypeLoc()))
|
|
return true;
|
|
break;
|
|
case RequirementKind::Conformance:
|
|
if (doIt(Req.getSubjectLoc()))
|
|
return true;
|
|
break;
|
|
case RequirementKind::WitnessMarker:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto &P : AFD->getBodyParamPatterns()) {
|
|
if (Pattern *NewPattern = doIt(P))
|
|
P = NewPattern;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
if (auto *FD = dyn_cast<FuncDecl>(AFD))
|
|
if (!FD->isAccessor())
|
|
if (doIt(FD->getBodyResultTypeLoc()))
|
|
return true;
|
|
|
|
if (AFD->getBody(/*canSynthesize=*/false)) {
|
|
AbstractFunctionDecl::BodyKind PreservedKind = AFD->getBodyKind();
|
|
if (BraceStmt *S = cast_or_null<BraceStmt>(doIt(AFD->getBody())))
|
|
AFD->setBody(S, PreservedKind);
|
|
else
|
|
return true;
|
|
}
|
|
|
|
if (auto ctor = dyn_cast<ConstructorDecl>(AFD)) {
|
|
if (auto superInit = ctor->getSuperInitCall()) {
|
|
if ((superInit = doIt(superInit)))
|
|
ctor->setSuperInitCall(superInit);
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool visitEnumElementDecl(EnumElementDecl *ED) {
|
|
// The getRawValueExpr should remain the untouched original LiteralExpr for
|
|
// serialization and validation purposes. We only traverse the type-checked
|
|
// form, unless we haven't populated it yet.
|
|
if (auto *rawValueExpr = ED->getTypeCheckedRawValueExpr()) {
|
|
if (auto newRawValueExpr = doIt(rawValueExpr))
|
|
ED->setTypeCheckedRawValueExpr(newRawValueExpr);
|
|
else
|
|
return true;
|
|
} else if (auto *rawLiteralExpr = ED->getRawValueExpr()) {
|
|
Expr *newRawExpr = doIt(rawLiteralExpr);
|
|
if (auto newRawLiteralExpr = dyn_cast<LiteralExpr>(newRawExpr))
|
|
ED->setRawValueExpr(newRawLiteralExpr);
|
|
else
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/********************************** Exprs **********************************/
|
|
/***************************************************************************/
|
|
|
|
// A macro for handling the "semantic expressions" that are common
|
|
// on sugared expression nodes like string interpolation. The
|
|
// semantic expression is set up by type-checking to include all the
|
|
// other children as sub-expressions, so if it exists, we should
|
|
// just bypass the rest of the visitation.
|
|
#define HANDLE_SEMANTIC_EXPR(NODE) \
|
|
do { \
|
|
if (Expr *_semanticExpr = NODE->getSemanticExpr()) { \
|
|
if ((_semanticExpr = doIt(_semanticExpr))) { \
|
|
NODE->setSemanticExpr(_semanticExpr); \
|
|
} else { \
|
|
return nullptr; \
|
|
} \
|
|
return NODE; \
|
|
} \
|
|
} while(false)
|
|
|
|
Expr *visitErrorExpr(ErrorExpr *E) { return E; }
|
|
Expr *visitCodeCompletionExpr(CodeCompletionExpr *E) { return E; }
|
|
Expr *visitLiteralExpr(LiteralExpr *E) { return E; }
|
|
Expr *visitDiscardAssignmentExpr(DiscardAssignmentExpr *E) { return E; }
|
|
Expr *visitTypeExpr(TypeExpr *E) {
|
|
if (!E->isImplicit())
|
|
if (doIt(E->getTypeLoc()))
|
|
return nullptr;
|
|
|
|
return E;
|
|
}
|
|
Expr *visitSuperRefExpr(SuperRefExpr *E) { return E; }
|
|
Expr *visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *E) {
|
|
return E;
|
|
}
|
|
|
|
Expr *visitUnresolvedConstructorExpr(UnresolvedConstructorExpr *E) {
|
|
if (auto sub = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitOverloadedDeclRefExpr(OverloadedDeclRefExpr *E) { return E; }
|
|
Expr *visitOverloadedMemberRefExpr(OverloadedMemberRefExpr *E) {
|
|
if (auto base = doIt(E->getBase())) {
|
|
E->setBase(base);
|
|
return E;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
Expr *visitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *E) { return E; }
|
|
|
|
Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
|
|
if (E->getArgument()) {
|
|
if (auto arg = doIt(E->getArgument())) {
|
|
E->setArgument(arg);
|
|
return E;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expr *visitOpaqueValueExpr(OpaqueValueExpr *E) { return E; }
|
|
|
|
Expr *visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E) {
|
|
HANDLE_SEMANTIC_EXPR(E);
|
|
|
|
for (auto &Segment : E->getSegments()) {
|
|
if (Expr *Seg = doIt(Segment))
|
|
Segment = Seg;
|
|
else
|
|
return nullptr;
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expr *visitObjectLiteralExpr(ObjectLiteralExpr *E) {
|
|
HANDLE_SEMANTIC_EXPR(E);
|
|
|
|
if (Expr *arg = E->getArg()) {
|
|
if (Expr *arg2 = doIt(arg)) {
|
|
E->setArg(arg2);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expr *visitCollectionExpr(CollectionExpr *E) {
|
|
HANDLE_SEMANTIC_EXPR(E);
|
|
|
|
for (auto &elt : E->getElements())
|
|
if (Expr *Sub = doIt(elt))
|
|
elt = Sub;
|
|
else
|
|
return nullptr;
|
|
return E;
|
|
}
|
|
|
|
Expr *visitDeclRefExpr(DeclRefExpr *E) {
|
|
for (auto Ty : E->getGenericArgs()) {
|
|
if (doIt(Ty))
|
|
return nullptr;
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expr *visitMemberRefExpr(MemberRefExpr *E) {
|
|
if (Expr *Base = doIt(E->getBase())) {
|
|
E->setBase(Base);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitDynamicMemberRefExpr(DynamicMemberRefExpr *E) {
|
|
if (Expr *Base = doIt(E->getBase())) {
|
|
E->setBase(Base);
|
|
return E;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitAnyTryExpr(AnyTryExpr *E) {
|
|
if (Expr *subExpr = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(subExpr);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitIdentityExpr(IdentityExpr *E) {
|
|
if (Expr *subExpr = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(subExpr);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
Expr *visitTupleExpr(TupleExpr *E) {
|
|
for (unsigned i = 0, e = E->getNumElements(); i != e; ++i)
|
|
if (E->getElement(i)) {
|
|
if (Expr *Elt = doIt(E->getElement(i)))
|
|
E->setElement(i, Elt);
|
|
else
|
|
return nullptr;
|
|
}
|
|
return E;
|
|
}
|
|
Expr *visitSubscriptExpr(SubscriptExpr *E) {
|
|
if (Expr *Base = doIt(E->getBase()))
|
|
E->setBase(Base);
|
|
else
|
|
return nullptr;
|
|
|
|
if (Expr *Index = doIt(E->getIndex()))
|
|
E->setIndex(Index);
|
|
else
|
|
return nullptr;
|
|
|
|
return E;
|
|
}
|
|
Expr *visitDynamicSubscriptExpr(DynamicSubscriptExpr *E) {
|
|
if (Expr *Base = doIt(E->getBase()))
|
|
E->setBase(Base);
|
|
else
|
|
return nullptr;
|
|
|
|
if (Expr *Index = doIt(E->getIndex()))
|
|
E->setIndex(Index);
|
|
else
|
|
return nullptr;
|
|
|
|
return E;
|
|
}
|
|
Expr *visitUnresolvedDotExpr(UnresolvedDotExpr *E) {
|
|
if (!E->getBase())
|
|
return E;
|
|
|
|
if (Expr *E2 = doIt(E->getBase())) {
|
|
E->setBase(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
Expr *visitUnresolvedSelectorExpr(UnresolvedSelectorExpr *E) {
|
|
if (!E->getBase())
|
|
return E;
|
|
|
|
if (Expr *E2 = doIt(E->getBase())) {
|
|
E->setBase(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
Expr *visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *E) {
|
|
if (!E->getSubExpr())
|
|
return E;
|
|
|
|
if (Expr *Sub = doIt(E->getSubExpr()))
|
|
E->setSubExpr(Sub);
|
|
else
|
|
return nullptr;
|
|
|
|
for (auto &TyLoc : E->getUnresolvedParams()) {
|
|
if (doIt(TyLoc))
|
|
return nullptr;
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitTupleElementExpr(TupleElementExpr *E) {
|
|
if (Expr *E2 = doIt(E->getBase())) {
|
|
E->setBase(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitImplicitConversionExpr(ImplicitConversionExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitTupleShuffleExpr(TupleShuffleExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto &defaultArg : E->getCallerDefaultArgs()) {
|
|
if (Expr *newDefaultArg = doIt(defaultArg))
|
|
defaultArg = newDefaultArg;
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitTryExpr(TryExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitForceTryExpr(ForceTryExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitOptionalTryExpr(OptionalTryExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitInOutExpr(InOutExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitSequenceExpr(SequenceExpr *E) {
|
|
for (unsigned i = 0, e = E->getNumElements(); i != e; ++i)
|
|
if (Expr *Elt = doIt(E->getElement(i)))
|
|
E->setElement(i, Elt);
|
|
else
|
|
return nullptr;
|
|
return E;
|
|
}
|
|
|
|
Expr *visitDynamicTypeExpr(DynamicTypeExpr *E) {
|
|
Expr *base = E->getBase();
|
|
if ((base = doIt(base)))
|
|
E->setBase(base);
|
|
else
|
|
return nullptr;
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitCaptureListExpr(CaptureListExpr *expr) {
|
|
for (auto c : expr->getCaptureList()) {
|
|
if (doIt(c.Var) || doIt(c.Init))
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *body = expr->getClosureBody();
|
|
if ((body = doIt(body)))
|
|
expr->setClosureBody(body);
|
|
else
|
|
return nullptr;
|
|
return expr;
|
|
}
|
|
|
|
Expr *visitClosureExpr(ClosureExpr *expr) {
|
|
if (Pattern *Pat = doIt(expr->getParams()))
|
|
expr->setParams(Pat);
|
|
else
|
|
return nullptr;
|
|
|
|
if (expr->hasExplicitResultType())
|
|
if (doIt(expr->getExplicitResultTypeLoc()))
|
|
return nullptr;
|
|
|
|
// Handle single-expression closures.
|
|
if (expr->hasSingleExpressionBody()) {
|
|
if (Expr *body = doIt(expr->getSingleExpressionBody())) {
|
|
expr->setSingleExpressionBody(body);
|
|
return expr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Handle other closures.
|
|
if (BraceStmt *body = cast_or_null<BraceStmt>(doIt(expr->getBody()))) {
|
|
expr->setBody(body, false);
|
|
return expr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitAutoClosureExpr(AutoClosureExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSingleExpressionBody())) {
|
|
E->setBody(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitApplyExpr(ApplyExpr *E) {
|
|
if (E->getFn()) {
|
|
Expr *E2 = doIt(E->getFn());
|
|
if (E2 == nullptr) return nullptr;
|
|
E->setFn(E2);
|
|
}
|
|
|
|
if (E->getArg()) {
|
|
Expr *E2 = doIt(E->getArg());
|
|
if (E2 == nullptr) return nullptr;
|
|
|
|
// Protect against setting a non-tuple argument expression for a binop,
|
|
// which may occur as a result of error recovery.
|
|
// E.g., "print(Array<Int)"
|
|
if (!isa<BinaryExpr>(E) || isa<TupleExpr>(E2))
|
|
E->setArg(E2);
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitSelfApplyExpr(SelfApplyExpr *E) {
|
|
if (E->getBase()) {
|
|
Expr *E2 = doIt(E->getBase());
|
|
if (E2 == nullptr) return nullptr;
|
|
E->setBase(E2);
|
|
}
|
|
|
|
if (E->getFn()) {
|
|
Expr *E2 = doIt(E->getFn());
|
|
if (E2 == nullptr) return nullptr;
|
|
E->setFn(E2);
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *E) {
|
|
Expr *E2 = doIt(E->getLHS());
|
|
if (E2 == nullptr) return nullptr;
|
|
E->setLHS(E2);
|
|
|
|
E2 = doIt(E->getRHS());
|
|
if (E2 == nullptr) return nullptr;
|
|
E->setRHS(E2);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitExplicitCastExpr(ExplicitCastExpr *E) {
|
|
if (Expr *Sub = E->getSubExpr()) {
|
|
Sub = doIt(Sub);
|
|
if (!Sub) return nullptr;
|
|
E->setSubExpr(Sub);
|
|
}
|
|
|
|
if (doIt(E->getCastTypeLoc()))
|
|
return nullptr;
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) {
|
|
Expr *Sub = doIt(E->getSubExpr());
|
|
if (!Sub) return nullptr;
|
|
E->setSubExpr(Sub);
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitAssignExpr(AssignExpr *AE) {
|
|
if (Expr *Dest = AE->getDest()) {
|
|
if (!(Dest = doIt(Dest)))
|
|
return nullptr;
|
|
AE->setDest(Dest);
|
|
}
|
|
|
|
if (Expr *Src = AE->getSrc()) {
|
|
if (!(Src = doIt(AE->getSrc())))
|
|
return nullptr;
|
|
AE->setSrc(Src);
|
|
}
|
|
|
|
return AE;
|
|
}
|
|
|
|
|
|
Expr *visitIfExpr(IfExpr *E) {
|
|
if (Expr *Cond = E->getCondExpr()) {
|
|
Cond = doIt(Cond);
|
|
if (!Cond) return nullptr;
|
|
E->setCondExpr(Cond);
|
|
}
|
|
|
|
Expr *Then = doIt(E->getThenExpr());
|
|
if (!Then) return nullptr;
|
|
E->setThenExpr(Then);
|
|
|
|
if (Expr *Else = E->getElseExpr()) {
|
|
Else = doIt(Else);
|
|
if (!Else) return nullptr;
|
|
E->setElseExpr(Else);
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitDefaultValueExpr(DefaultValueExpr *E) {
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitUnresolvedPatternExpr(UnresolvedPatternExpr *E) {
|
|
Pattern *sub = doIt(E->getSubPattern());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setSubPattern(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitBindOptionalExpr(BindOptionalExpr *E) {
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitOptionalEvaluationExpr(OptionalEvaluationExpr *E) {
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitForceValueExpr(ForceValueExpr *E) {
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitOpenExistentialExpr(OpenExistentialExpr *E) {
|
|
Expr *existential = doIt(E->getExistentialValue());
|
|
if (!existential) return nullptr;
|
|
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setExistentialValue(existential);
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) {
|
|
HANDLE_SEMANTIC_EXPR(E);
|
|
return E;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/***************************** Everything Else *****************************/
|
|
/***************************************************************************/
|
|
|
|
#define STMT(Id, Parent) Stmt *visit##Id##Stmt(Id##Stmt *S);
|
|
#include "swift/AST/StmtNodes.def"
|
|
|
|
#define PATTERN(Id, Parent) Pattern *visit##Id##Pattern(Id##Pattern *P);
|
|
#include "swift/AST/PatternNodes.def"
|
|
|
|
#define TYPEREPR(Id, Parent) bool visit##Id##TypeRepr(Id##TypeRepr *T);
|
|
#include "swift/AST/TypeReprNodes.def"
|
|
|
|
public:
|
|
Traversal(ASTWalker &walker) : Walker(walker) {}
|
|
|
|
Expr *doIt(Expr *E) {
|
|
// Do the pre-order visitation. If it returns false, we just
|
|
// skip entering subnodes of this tree.
|
|
auto Pre = Walker.walkToExprPre(E);
|
|
if (!Pre.first || !Pre.second)
|
|
return Pre.second;
|
|
|
|
// Otherwise, visit the children.
|
|
E = visit(Pre.second);
|
|
|
|
// If we didn't bail out, do post-order visitation.
|
|
if (E) E = Walker.walkToExprPost(E);
|
|
|
|
return E;
|
|
}
|
|
|
|
Stmt *doIt(Stmt *S) {
|
|
// Do the pre-order visitation. If it returns false, we just
|
|
// skip entering subnodes of this tree.
|
|
auto Pre = Walker.walkToStmtPre(S);
|
|
if (!Pre.first || !Pre.second)
|
|
return Pre.second;
|
|
|
|
// Otherwise, visit the children.
|
|
S = visit(S);
|
|
|
|
// If we didn't bail out, do post-order visitation.
|
|
if (S) S = Walker.walkToStmtPost(S);
|
|
|
|
return S;
|
|
}
|
|
|
|
bool shouldSkip(Decl *D) {
|
|
if (isa<VarDecl>(D)) {
|
|
// VarDecls are walked via their NamedPattern, ignore them if we encounter
|
|
// then in the few cases where they are also pushed outside as members.
|
|
// In all those cases we can walk them via the pattern binding decl.
|
|
if (Walker.Parent.getAsModule())
|
|
return true;
|
|
if (Decl *ParentD = Walker.Parent.getAsDecl())
|
|
return (isa<NominalTypeDecl>(ParentD) || isa<ExtensionDecl>(ParentD));
|
|
if (dyn_cast_or_null<BraceStmt>(Walker.Parent.getAsStmt()))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Returns true on failure.
|
|
bool doIt(Decl *D) {
|
|
if (shouldSkip(D))
|
|
return false;
|
|
|
|
// Do the pre-order visitation. If it returns false, we just
|
|
// skip entering subnodes of this tree.
|
|
if (!Walker.walkToDeclPre(D))
|
|
return false;
|
|
|
|
if (visit(D))
|
|
return true;
|
|
|
|
return !Walker.walkToDeclPost(D);
|
|
}
|
|
|
|
Pattern *doIt(Pattern *P) {
|
|
// Do the pre-order visitation. If it returns false, we just
|
|
// skip entering subnodes of this tree.
|
|
auto Pre = Walker.walkToPatternPre(P);
|
|
if (!Pre.first || !Pre.second)
|
|
return Pre.second;
|
|
|
|
// Otherwise, visit the children.
|
|
P = visit(P);
|
|
|
|
// If we didn't bail out, do post-order visitation.
|
|
if (P) P = Walker.walkToPatternPost(P);
|
|
|
|
return P;
|
|
}
|
|
|
|
bool doIt(const StmtCondition &C) {
|
|
for (auto &elt : C) {
|
|
switch (elt.getKind()) {
|
|
case StmtConditionElement::CK_Availability: break;
|
|
case StmtConditionElement::CK_Boolean: {
|
|
auto E = elt.getBoolean();
|
|
// Walk an expression condition normally.
|
|
E = doIt(E);
|
|
if (!E)
|
|
return true;
|
|
elt.setBoolean(E);
|
|
break;
|
|
}
|
|
|
|
case StmtConditionElement::CK_PatternBinding: {
|
|
auto *P = doIt(elt.getPattern());
|
|
if (!P) return true;
|
|
elt.setPattern(P);
|
|
|
|
auto *I = doIt(elt.getInitializer());
|
|
if (!I) return true;
|
|
elt.setInitializer(I);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool doIt(TypeLoc &TL) {
|
|
if (!Walker.walkToTypeLocPre(TL))
|
|
return false;
|
|
|
|
// No "visit" since TypeLocs are not a class hierarchy. Clients can do what
|
|
// they want in walkToTypeLocPre.
|
|
|
|
if (auto typerepr = TL.getTypeRepr())
|
|
if (doIt(typerepr))
|
|
return true;
|
|
|
|
// If we didn't bail out, do post-order visitation.
|
|
return !Walker.walkToTypeLocPost(TL);
|
|
}
|
|
|
|
/// Returns true on failure.
|
|
bool doIt(TypeRepr *T) {
|
|
// Do the pre-order visitation. If it returns false, we just
|
|
// skip entering subnodes of this tree.
|
|
if (!Walker.walkToTypeReprPre(T))
|
|
return false;
|
|
|
|
// Otherwise, visit the children.
|
|
if (visit(T))
|
|
return true;
|
|
|
|
// If we didn't bail out, do post-order visitation.
|
|
return !Walker.walkToTypeReprPost(T);
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace.
|
|
|
|
#pragma mark Statement traversal
|
|
Stmt *Traversal::visitBreakStmt(BreakStmt *BS) {
|
|
return BS;
|
|
}
|
|
|
|
Stmt *Traversal::visitContinueStmt(ContinueStmt *CS) {
|
|
return CS;
|
|
}
|
|
|
|
Stmt *Traversal::visitFallthroughStmt(FallthroughStmt *CS) {
|
|
return CS;
|
|
}
|
|
|
|
Stmt *Traversal::visitFailStmt(FailStmt *FS) {
|
|
return FS;
|
|
}
|
|
Stmt *Traversal::visitThrowStmt(ThrowStmt *TS) {
|
|
if (Expr *E = doIt(TS->getSubExpr())) {
|
|
TS->setSubExpr(E);
|
|
return TS;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
Stmt *Traversal::visitBraceStmt(BraceStmt *BS) {
|
|
for (auto &Elem : BS->getElements()) {
|
|
if (Expr *SubExpr = Elem.dyn_cast<Expr*>()) {
|
|
if (Expr *E2 = doIt(SubExpr))
|
|
Elem = E2;
|
|
else
|
|
return nullptr;
|
|
continue;
|
|
}
|
|
|
|
if (Stmt *S = Elem.dyn_cast<Stmt*>()) {
|
|
if (Stmt *S2 = doIt(S))
|
|
Elem = S2;
|
|
else
|
|
return nullptr;
|
|
continue;
|
|
}
|
|
|
|
if (doIt(Elem.get<Decl*>()))
|
|
return nullptr;
|
|
}
|
|
|
|
return BS;
|
|
}
|
|
|
|
Stmt *Traversal::visitReturnStmt(ReturnStmt *RS) {
|
|
if (!RS->hasResult())
|
|
return RS;
|
|
if (Expr *E = doIt(RS->getResult()))
|
|
RS->setResult(E);
|
|
else
|
|
return nullptr;
|
|
return RS;
|
|
}
|
|
|
|
Stmt *Traversal::visitDeferStmt(DeferStmt *DS) {
|
|
if (doIt(DS->getTempDecl()))
|
|
return nullptr;
|
|
|
|
if (Expr *Call = doIt(DS->getCallExpr()))
|
|
DS->setCallExpr(Call);
|
|
else
|
|
return nullptr;
|
|
return DS;
|
|
}
|
|
|
|
Stmt *Traversal::visitIfStmt(IfStmt *IS) {
|
|
if (doIt(IS->getCond()))
|
|
return nullptr;
|
|
|
|
if (Stmt *S2 = doIt(IS->getThenStmt()))
|
|
IS->setThenStmt(S2);
|
|
else
|
|
return nullptr;
|
|
|
|
if (IS->getElseStmt()) {
|
|
if (Stmt *S2 = doIt(IS->getElseStmt()))
|
|
IS->setElseStmt(S2);
|
|
else
|
|
return nullptr;
|
|
}
|
|
return IS;
|
|
}
|
|
|
|
Stmt *Traversal::visitGuardStmt(GuardStmt *US) {
|
|
if (doIt(US->getCond()))
|
|
return nullptr;
|
|
|
|
if (Stmt *S2 = doIt(US->getBody()))
|
|
US->setBody(S2);
|
|
else
|
|
return nullptr;
|
|
return US;
|
|
}
|
|
|
|
|
|
Stmt *Traversal::visitIfConfigStmt(IfConfigStmt *ICS) {
|
|
// Active members are attached to the enclosing declaration, so there's no
|
|
// need to walk anything within.
|
|
|
|
return ICS;
|
|
}
|
|
|
|
Stmt *Traversal::visitDoStmt(DoStmt *DS) {
|
|
if (Stmt *S2 = doIt(DS->getBody()))
|
|
DS->setBody(S2);
|
|
else
|
|
return nullptr;
|
|
|
|
return DS;
|
|
}
|
|
|
|
Stmt *Traversal::visitDoCatchStmt(DoCatchStmt *stmt) {
|
|
// Transform the body of the 'do'.
|
|
if (Stmt *newBody = doIt(stmt->getBody())) {
|
|
stmt->setBody(newBody);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
// Transform each of the catch clauses:
|
|
for (CatchStmt *&clause : stmt->getMutableCatches()) {
|
|
if (auto newClause = doIt(clause)) {
|
|
clause = cast<CatchStmt>(newClause);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return stmt;
|
|
}
|
|
|
|
Stmt *Traversal::visitCatchStmt(CatchStmt *stmt) {
|
|
// Transform the error pattern.
|
|
if (Pattern *newPattern = doIt(stmt->getErrorPattern())) {
|
|
stmt->setErrorPattern(newPattern);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
// Transform the guard expression if present.
|
|
if (Expr *oldGuardExpr = stmt->getGuardExpr()) {
|
|
if (Expr *newGuardExpr = doIt(oldGuardExpr)) {
|
|
stmt->setGuardExpr(newGuardExpr);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// Transform the body of the catch clause.
|
|
if (Stmt *newCatchBody = doIt(stmt->getBody())) {
|
|
stmt->setBody(newCatchBody);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
return stmt;
|
|
}
|
|
|
|
Stmt *Traversal::visitWhileStmt(WhileStmt *WS) {
|
|
if (doIt(WS->getCond()))
|
|
return nullptr;
|
|
|
|
if (Stmt *S2 = doIt(WS->getBody()))
|
|
WS->setBody(S2);
|
|
else
|
|
return nullptr;
|
|
return WS;
|
|
}
|
|
|
|
Stmt *Traversal::visitRepeatWhileStmt(RepeatWhileStmt *RWS) {
|
|
if (Stmt *S2 = doIt(RWS->getBody()))
|
|
RWS->setBody(S2);
|
|
else
|
|
return nullptr;
|
|
|
|
if (Expr *E2 = doIt(RWS->getCond()))
|
|
RWS->setCond(E2);
|
|
else
|
|
return nullptr;
|
|
|
|
return RWS;
|
|
}
|
|
|
|
Stmt *Traversal::visitForStmt(ForStmt *FS) {
|
|
// Visit any var decls in the initializer.
|
|
for (auto D : FS->getInitializerVarDecls())
|
|
if (doIt(D))
|
|
return nullptr;
|
|
|
|
if (auto *Initializer = FS->getInitializer().getPtrOrNull()) {
|
|
if (Expr *E = doIt(Initializer))
|
|
FS->setInitializer(E);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if (auto *Cond = FS->getCond().getPtrOrNull()) {
|
|
if (Expr *E2 = doIt(Cond))
|
|
FS->setCond(E2);
|
|
else
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (auto *Increment = FS->getIncrement().getPtrOrNull()) {
|
|
if (Expr *E = doIt(Increment))
|
|
FS->setIncrement(E);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if (Stmt *S = doIt(FS->getBody()))
|
|
FS->setBody(S);
|
|
else
|
|
return nullptr;
|
|
return FS;
|
|
}
|
|
|
|
Stmt *Traversal::visitForEachStmt(ForEachStmt *S) {
|
|
if (Pattern *P = S->getPattern()) {
|
|
if ((P = doIt(P)))
|
|
assert(P == S->getPattern() && "cannot change pattern of ForEachStmt");
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if (Expr *Where = S->getWhere()) {
|
|
if ((Where = doIt(Where)))
|
|
S->setWhere(Where);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
// The generator decl is built directly on top of the sequence
|
|
// expression, so don't visit both.
|
|
if (PatternBindingDecl *Generator = S->getGenerator()) {
|
|
if (doIt(Generator))
|
|
return nullptr;
|
|
|
|
} else if (Expr *Sequence = S->getSequence()) {
|
|
if ((Sequence = doIt(Sequence)))
|
|
S->setSequence(Sequence);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if (auto GeneratorNext = S->getGeneratorNext()) {
|
|
if ((GeneratorNext = doIt(GeneratorNext)))
|
|
S->setGeneratorNext(GeneratorNext);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if (Stmt *Body = S->getBody()) {
|
|
if ((Body = doIt(Body)))
|
|
S->setBody(cast<BraceStmt>(Body));
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
return S;
|
|
}
|
|
|
|
Stmt *Traversal::visitSwitchStmt(SwitchStmt *S) {
|
|
if (Expr *newSubject = doIt(S->getSubjectExpr()))
|
|
S->setSubjectExpr(newSubject);
|
|
else
|
|
return nullptr;
|
|
|
|
for (CaseStmt *aCase : S->getCases()) {
|
|
if (Stmt *aStmt = doIt(aCase)) {
|
|
assert(aCase == aStmt && "switch case remap not supported");
|
|
(void)aStmt;
|
|
} else
|
|
return nullptr;
|
|
}
|
|
|
|
return S;
|
|
}
|
|
|
|
Stmt *Traversal::visitCaseStmt(CaseStmt *S) {
|
|
for (auto &CLI : S->getMutableCaseLabelItems()) {
|
|
if (auto *newPattern = doIt(CLI.getPattern()))
|
|
CLI.setPattern(newPattern);
|
|
else
|
|
return nullptr;
|
|
if (CLI.getGuardExpr()) {
|
|
if (auto *newGuard = doIt(CLI.getGuardExpr()))
|
|
CLI.setGuardExpr(newGuard);
|
|
else
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (Stmt *newBody = doIt(S->getBody()))
|
|
S->setBody(newBody);
|
|
else
|
|
return nullptr;
|
|
|
|
return S;
|
|
}
|
|
|
|
#pragma mark Pattern traversal
|
|
Pattern *Traversal::visitParenPattern(ParenPattern *P) {
|
|
if (Pattern *newSub = doIt(P->getSubPattern()))
|
|
P->setSubPattern(newSub);
|
|
else
|
|
return nullptr;
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitTuplePattern(TuplePattern *P) {
|
|
for (auto &element : P->getElements()) {
|
|
if (Pattern *newField = doIt(element.getPattern()))
|
|
element.setPattern(newField);
|
|
else
|
|
return nullptr;
|
|
|
|
if (auto handle = element.getInit()) {
|
|
if (auto init = doIt(handle->getExpr())) {
|
|
handle->setExpr(init, handle->alreadyChecked());
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
}
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitNamedPattern(NamedPattern *P) {
|
|
if (doIt(P->getDecl()))
|
|
return nullptr;
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitAnyPattern(AnyPattern *P) {
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitTypedPattern(TypedPattern *P) {
|
|
if (Pattern *newSub = doIt(P->getSubPattern()))
|
|
P->setSubPattern(newSub);
|
|
else
|
|
return nullptr;
|
|
if (!P->isImplicit())
|
|
if (doIt(P->getTypeLoc()))
|
|
return nullptr;
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitIsPattern(IsPattern *P) {
|
|
if (auto sub = P->getSubPattern()) {
|
|
if (Pattern *newSub = doIt(sub)) {
|
|
P->setSubPattern(newSub);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
if (!P->isImplicit())
|
|
if (doIt(P->getCastTypeLoc()))
|
|
return nullptr;
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitNominalTypePattern(NominalTypePattern *P) {
|
|
for (auto &elt : P->getMutableElements()) {
|
|
if (Pattern *newSub = doIt(elt.getSubPattern()))
|
|
elt.setSubPattern(newSub);
|
|
else
|
|
return nullptr;
|
|
}
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitEnumElementPattern(EnumElementPattern *P) {
|
|
if (!P->hasSubPattern())
|
|
return P;
|
|
|
|
if (Pattern *newSub = doIt(P->getSubPattern())) {
|
|
P->setSubPattern(newSub);
|
|
return P;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Pattern *Traversal::visitExprPattern(ExprPattern *P) {
|
|
// If the pattern has been type-checked, walk the match expression, which
|
|
// includes the explicit subexpression.
|
|
if (P->getMatchExpr()) {
|
|
if (Expr *newMatch = doIt(P->getMatchExpr())) {
|
|
P->setMatchExpr(newMatch);
|
|
return P;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
if (Expr *newSub = doIt(P->getSubExpr())) {
|
|
P->setSubExpr(newSub);
|
|
return P;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Pattern *Traversal::visitVarPattern(VarPattern *P) {
|
|
if (Pattern *newSub = doIt(P->getSubPattern())) {
|
|
P->setSubPattern(newSub);
|
|
return P;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Pattern *Traversal::visitOptionalSomePattern(OptionalSomePattern *P) {
|
|
if (Pattern *newSub = doIt(P->getSubPattern())) {
|
|
P->setSubPattern(newSub);
|
|
return P;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Pattern *Traversal::visitBoolPattern(BoolPattern *P) {
|
|
return P;
|
|
}
|
|
|
|
#pragma mark Type representation traversal
|
|
bool Traversal::visitErrorTypeRepr(ErrorTypeRepr *T) {
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitAttributedTypeRepr(AttributedTypeRepr *T) {
|
|
if (doIt(T->getTypeRepr()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitSimpleIdentTypeRepr(SimpleIdentTypeRepr *T) {
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitGenericIdentTypeRepr(GenericIdentTypeRepr *T) {
|
|
for (auto genArg : T->getGenericArgs()) {
|
|
if (doIt(genArg))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitCompoundIdentTypeRepr(CompoundIdentTypeRepr *T) {
|
|
for (auto comp : T->Components) {
|
|
if (doIt(comp))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitFunctionTypeRepr(FunctionTypeRepr *T) {
|
|
if (doIt(T->getArgsTypeRepr()))
|
|
return true;
|
|
if (doIt(T->getResultTypeRepr()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitArrayTypeRepr(ArrayTypeRepr *T) {
|
|
if (doIt(T->getBase()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitDictionaryTypeRepr(DictionaryTypeRepr *T) {
|
|
if (doIt(T->getKey()))
|
|
return true;
|
|
if (doIt(T->getValue()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitOptionalTypeRepr(OptionalTypeRepr *T) {
|
|
if (doIt(T->getBase()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitImplicitlyUnwrappedOptionalTypeRepr(ImplicitlyUnwrappedOptionalTypeRepr *T) {
|
|
if (doIt(T->getBase()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitTupleTypeRepr(TupleTypeRepr *T) {
|
|
for (auto elem : T->getElements()) {
|
|
if (doIt(elem))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitNamedTypeRepr(NamedTypeRepr *T) {
|
|
if (T->getTypeRepr()) {
|
|
if (doIt(T->getTypeRepr()))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitProtocolCompositionTypeRepr(
|
|
ProtocolCompositionTypeRepr *T) {
|
|
for (auto elem : T->getProtocols()) {
|
|
if (doIt(elem))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitMetatypeTypeRepr(MetatypeTypeRepr *T) {
|
|
if (doIt(T->getBase()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitProtocolTypeRepr(ProtocolTypeRepr *T) {
|
|
if (doIt(T->getBase()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitInOutTypeRepr(InOutTypeRepr *T) {
|
|
if (doIt(T->getBase()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitFixedTypeRepr(FixedTypeRepr *T) {
|
|
return false;
|
|
}
|
|
|
|
Expr *Expr::walk(ASTWalker &walker) {
|
|
return Traversal(walker).doIt(this);
|
|
}
|
|
|
|
Stmt *Stmt::walk(ASTWalker &walker) {
|
|
return Traversal(walker).doIt(this);
|
|
}
|
|
|
|
Pattern *Pattern::walk(ASTWalker &walker) {
|
|
return Traversal(walker).doIt(this);
|
|
}
|
|
|
|
TypeRepr *TypeRepr::walk(ASTWalker &walker) {
|
|
Traversal(walker).doIt(this);
|
|
return this;
|
|
}
|
|
|
|
StmtConditionElement *StmtConditionElement::walk(ASTWalker &walker) {
|
|
Traversal(walker).doIt(*this);
|
|
return this;
|
|
}
|
|
|
|
bool Decl::walk(ASTWalker &walker) {
|
|
return Traversal(walker).doIt(this);
|
|
}
|