//===--- Pattern.cpp - Swift Language Pattern-Matching ASTs ---------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 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 the Pattern class and subclasses. // //===----------------------------------------------------------------------===// #include "swift/AST/Pattern.h" #include "swift/AST/AST.h" #include "swift/AST/TypeLoc.h" #include "llvm/ADT/APFloat.h" #include "llvm/Support/raw_ostream.h" using namespace swift; /// Diagnostic printing of PatternKinds. llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS, PatternKind kind) { switch (kind) { case PatternKind::Paren: return OS << "parenthesized pattern"; case PatternKind::Tuple: return OS << "tuple pattern"; case PatternKind::Named: return OS << "pattern variable binding"; case PatternKind::Any: return OS << "'_' pattern"; case PatternKind::Typed: return OS << "pattern type annotation"; case PatternKind::Is: return OS << "prefix 'is' pattern"; case PatternKind::NominalType: return OS << "type destructuring pattern"; case PatternKind::Expr: return OS << "expression pattern"; case PatternKind::Var: return OS << "'var' binding pattern"; case PatternKind::EnumElement: return OS << "enum case matching pattern"; case PatternKind::OptionalSome: return OS << "optional .Some matching pattern"; case PatternKind::Bool: return OS << "bool matching pattern"; } llvm_unreachable("bad PatternKind"); } StringRef Pattern::getKindName(PatternKind K) { switch (K) { #define PATTERN(Id, Parent) case PatternKind::Id: return #Id; #include "swift/AST/PatternNodes.def" } llvm_unreachable("bad PatternKind"); } // Metaprogram to verify that every concrete class implements // a 'static bool classof(const Pattern*)'. template struct CheckClassOfPattern { static const bool IsImplemented = true; }; template <> struct CheckClassOfPattern { static const bool IsImplemented = false; }; #define PATTERN(ID, PARENT) \ static_assert(CheckClassOfPattern::IsImplemented, \ #ID "Pattern is missing classof(const Pattern*)"); #include "swift/AST/PatternNodes.def" // Metaprogram to verify that every concrete class implements // 'SourceRange getSourceRange()'. typedef const char (&TwoChars)[2]; template inline char checkSourceRangeType(SourceRange (Class::*)() const); inline TwoChars checkSourceRangeType(SourceRange (Pattern::*)() const); /// getSourceRange - Return the full source range of the pattern. SourceRange Pattern::getSourceRange() const { switch (getKind()) { #define PATTERN(ID, PARENT) \ case PatternKind::ID: \ static_assert(sizeof(checkSourceRangeType(&ID##Pattern::getSourceRange)) == 1, \ #ID "Pattern is missing getSourceRange()"); \ return cast(this)->getSourceRange(); #include "swift/AST/PatternNodes.def" } llvm_unreachable("pattern type not handled!"); } /// getLoc - Return the caret location of the pattern. SourceLoc Pattern::getLoc() const { switch (getKind()) { #define PATTERN(ID, PARENT) \ case PatternKind::ID: \ if (&Pattern::getLoc != &ID##Pattern::getLoc) \ return cast(this)->getLoc(); \ break; #include "swift/AST/PatternNodes.def" } return getStartLoc(); } void Pattern::collectVariables(SmallVectorImpl &variables) const { forEachVariable([&](VarDecl *VD) { variables.push_back(VD); }); } VarDecl *Pattern::getSingleVar() const { auto pattern = getSemanticsProvidingPattern(); if (auto named = dyn_cast(pattern)) return named->getDecl(); return nullptr; } namespace { class WalkToVarDecls : public ASTWalker { const std::function &fn; public: WalkToVarDecls(const std::function &fn) : fn(fn) {} Pattern *walkToPatternPost(Pattern *P) override { // Handle vars. if (auto *Named = dyn_cast(P)) fn(Named->getDecl()); return P; } }; } /// \brief apply the specified function to all variables referenced in this /// pattern. void Pattern::forEachVariable(const std::function &fn) const { switch (getKind()) { case PatternKind::Any: case PatternKind::Bool: return; case PatternKind::Is: if (auto SP = cast(this)->getSubPattern()) SP->forEachVariable(fn); return; case PatternKind::Named: fn(cast(this)->getDecl()); return; case PatternKind::Paren: case PatternKind::Typed: case PatternKind::Var: return getSemanticsProvidingPattern()->forEachVariable(fn); case PatternKind::Tuple: for (auto elt : cast(this)->getElements()) elt.getPattern()->forEachVariable(fn); return; case PatternKind::NominalType: for (auto elt : cast(this)->getElements()) elt.getSubPattern()->forEachVariable(fn); return; case PatternKind::EnumElement: if (auto SP = cast(this)->getSubPattern()) SP->forEachVariable(fn); return; case PatternKind::OptionalSome: cast(this)->getSubPattern()->forEachVariable(fn); return; case PatternKind::Expr: // An ExprPattern only exists before sema has resolved a refutable pattern // into a concrete pattern. We have to use an AST Walker to find the // VarDecls buried down inside of it. const_cast(this)->walk(WalkToVarDecls(fn)); return; } } /// \brief apply the specified function to all pattern nodes recursively in /// this pattern. This is a pre-order traversal. void Pattern::forEachNode(const std::function &f) { f(this); switch (getKind()) { // Leaf patterns have no recursion. case PatternKind::Any: case PatternKind::Named: case PatternKind::Expr:// FIXME: expr nodes are not modeled right in general. case PatternKind::Bool: return; case PatternKind::Is: if (auto SP = cast(this)->getSubPattern()) SP->forEachNode(f); return; case PatternKind::Paren: return cast(this)->getSubPattern()->forEachNode(f); case PatternKind::Typed: return cast(this)->getSubPattern()->forEachNode(f); case PatternKind::Var: return cast(this)->getSubPattern()->forEachNode(f); case PatternKind::Tuple: for (auto elt : cast(this)->getElements()) elt.getPattern()->forEachNode(f); return; case PatternKind::NominalType: for (auto elt : cast(this)->getElements()) elt.getSubPattern()->forEachNode(f); return; case PatternKind::EnumElement: { auto *OP = cast(this); if (OP->hasSubPattern()) OP->getSubPattern()->forEachNode(f); return; } case PatternKind::OptionalSome: cast(this)->getSubPattern()->forEachNode(f); return; } } /// Return true if this is a non-resolved ExprPattern which is syntactically /// irrefutable. static bool isIrrefutableExprPattern(const ExprPattern *EP) { // If the pattern has a registered match expression, it's // a type-checked ExprPattern. if (EP->getMatchExpr()) return false; auto expr = EP->getSubExpr(); while (true) { // Drill into parens. if (auto parens = dyn_cast(expr)) { expr = parens->getSubExpr(); continue; } // A '_' is an untranslated AnyPattern. if (isa(expr)) return true; // Everything else is non-exhaustive. return false; } } /// Return true if this pattern (or a subpattern) is refutable. bool Pattern::isRefutablePattern() const { bool foundRefutablePattern = false; const_cast(this)->forEachNode([&](Pattern *Node) { // If this is an always matching 'is' pattern, then it isn't refutable. if (auto *is = dyn_cast(Node)) if (is->getCastKind() == CheckedCastKind::Coercion) return; // If this is an ExprPattern that isn't resolved yet, do some simple // syntactic checks. // FIXME: This is unsound, since type checking will turn other more // complicated patterns into non-refutable forms. if (auto *ep = dyn_cast(Node)) if (isIrrefutableExprPattern(ep)) return; switch (Node->getKind()) { #define PATTERN(ID, PARENT) case PatternKind::ID: break; #define REFUTABLE_PATTERN(ID, PARENT) \ case PatternKind::ID: foundRefutablePattern = true; break; #include "swift/AST/PatternNodes.def" } }); return foundRefutablePattern; } Pattern *Pattern::clone(ASTContext &context) const { Pattern *result; switch (getKind()) { case PatternKind::Any: { result = new (context) AnyPattern(cast(this)->getLoc()); break; } case PatternKind::Named: { auto named = cast(this); VarDecl *var = new (context) VarDecl(!named->getDecl()->isInstanceMember(), named->getDecl()->isLet(), named->getLoc(), named->getBoundName(), named->getDecl()->hasType() ? named->getDecl()->getType() : Type(), named->getDecl()->getDeclContext()); if (var->isImplicit()) var->setImplicit(); result = new (context) NamedPattern(var); break; } case PatternKind::Paren: { auto paren = cast(this); result = new (context) ParenPattern(paren->getLParenLoc(), paren->getSubPattern()->clone(context), paren->getRParenLoc()); break; } case PatternKind::Tuple: { auto tuple = cast(this); SmallVector elts; elts.reserve(tuple->getNumElements()); for (const auto &elt : tuple->getElements()) { auto eltPattern = elt.getPattern()->clone(context); elts.push_back(TuplePatternElt(elt.getLabel(), elt.getLabelLoc(), eltPattern)); } result = TuplePattern::create(context, tuple->getLParenLoc(), elts, tuple->getRParenLoc()); break; } case PatternKind::Typed: { auto typed = cast(this); auto subP = typed->getSubPattern()->clone(context); result = new(context) TypedPattern(subP, typed->getTypeLoc().clone(context)); break; } case PatternKind::Is: { auto isa = cast(this); result = new(context) IsPattern(isa->getLoc(), isa->getCastTypeLoc().clone(context), isa->getSubPattern()->clone(context), isa->getCastKind()); break; } case PatternKind::NominalType: { auto nom = cast(this); SmallVector elts; for (const auto &elt : nom->getElements()) { elts.push_back(NominalTypePattern::Element(elt.getPropertyLoc(), elt.getPropertyName(), elt.getProperty(), elt.getColonLoc(), elt.getSubPattern()->clone(context))); } result = NominalTypePattern::create(nom->getCastTypeLoc().clone(context), nom->getLParenLoc(), elts, nom->getRParenLoc(), context); break; } case PatternKind::EnumElement: { auto oof = cast(this); Pattern *sub = nullptr; if (oof->hasSubPattern()) sub = oof->getSubPattern()->clone(context); result = new (context) EnumElementPattern(oof->getParentType() .clone(context), oof->getLoc(), oof->getNameLoc(), oof->getName(), oof->getElementDecl(), sub); break; } case PatternKind::OptionalSome: { auto osp = cast(this); auto *sub = osp->getSubPattern()->clone(context); auto *r = new (context) OptionalSomePattern(sub, osp->getQuestionLoc()); r->setElementDecl(osp->getElementDecl()); result = r; break; } case PatternKind::Bool: { auto bp = cast(this); result = new (context) BoolPattern(bp->getNameLoc(), bp->getValue()); break; } case PatternKind::Expr: { auto expr = cast(this); result = new(context) ExprPattern(expr->getSubExpr(), expr->isResolved(), expr->getMatchExpr(), expr->getMatchVar()); break; } case PatternKind::Var: { auto var = cast(this); auto subP = var->getSubPattern()->clone(context); result = new(context) VarPattern(var->getLoc(), var->isLet(), subP); } } if (hasType()) result->setType(getType()); if (isImplicit()) result->setImplicit(); return result; } /// Standard allocator for Patterns. void *Pattern::operator new(size_t numBytes, ASTContext &C) { return C.Allocate(numBytes, alignof(Pattern)); } /// Find the name directly bound by this pattern. When used as a /// tuple element in a function signature, such names become part of /// the type. Identifier Pattern::getBoundName() const { if (auto *NP = dyn_cast(getSemanticsProvidingPattern())) return NP->getBoundName(); return Identifier(); } Identifier NamedPattern::getBoundName() const { return Var->getName(); } /// Allocate a new pattern that matches a tuple. TuplePattern *TuplePattern::create(ASTContext &C, SourceLoc lp, ArrayRef elts, SourceLoc rp, Optional implicit) { if (!implicit.hasValue()) implicit = !lp.isValid(); unsigned n = elts.size(); void *buffer = C.Allocate(sizeof(TuplePattern) + n * sizeof(TuplePatternElt), alignof(TuplePattern)); TuplePattern *pattern = ::new (buffer) TuplePattern(lp, n, rp, *implicit); memcpy(pattern->getElementsBuffer(), elts.data(), n * sizeof(TuplePatternElt)); return pattern; } Pattern *TuplePattern::createSimple(ASTContext &C, SourceLoc lp, ArrayRef elements, SourceLoc rp, Optional implicit) { assert(lp.isValid() == rp.isValid()); if (elements.size() == 1 && elements[0].getPattern()->getBoundName().empty()) { auto &first = const_cast(elements.front()); return new (C) ParenPattern(lp, first.getPattern(), rp, implicit); } return create(C, lp, elements, rp, implicit); } SourceRange TuplePattern::getSourceRange() const { if (LPLoc.isValid()) return { LPLoc, RPLoc }; auto Fields = getElements(); if (Fields.empty()) return {}; return { Fields.front().getPattern()->getStartLoc(), Fields.back().getPattern()->getEndLoc() }; } SourceRange TypedPattern::getSourceRange() const { if (isImplicit()) { // If a TypedPattern is implicit, then its type is definitely implicit, so // we should ignore its location. On the other hand, the sub-pattern can // be explicit or implicit. return SubPattern->getSourceRange(); } if (SubPattern->isImplicit()) return PatType.getSourceRange(); return { SubPattern->getSourceRange().Start, PatType.getSourceRange().End }; } NominalTypePattern *NominalTypePattern::create(TypeLoc CastTy, SourceLoc LParenLoc, ArrayRef Elements, SourceLoc RParenLoc, ASTContext &C, Optional implicit) { void *buf = C.Allocate(sizeof(NominalTypePattern) + sizeof(Element) * Elements.size(), alignof(Element)); return ::new (buf) NominalTypePattern(CastTy, LParenLoc, Elements, RParenLoc, implicit); }