blob: d467a23c2503db0473f402bb15eeac1912941cb7 [file] [log] [blame]
//===--- Pattern.cpp - Swift Language Pattern-Matching ASTs ---------------===//
//
// 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 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 << "parethesized 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 <bool fn(const Pattern*)> struct CheckClassOfPattern {
static const bool IsImplemented = true;
};
template <> struct CheckClassOfPattern<Pattern::classof> {
static const bool IsImplemented = false;
};
#define PATTERN(ID, PARENT) \
static_assert(CheckClassOfPattern<ID##Pattern::classof>::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<typename Class>
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<ID##Pattern>(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<ID##Pattern>(this)->getLoc(); \
break;
#include "swift/AST/PatternNodes.def"
}
return getStartLoc();
}
void Pattern::collectVariables(SmallVectorImpl<VarDecl *> &variables) const {
forEachVariable([&](VarDecl *VD) { variables.push_back(VD); });
}
VarDecl *Pattern::getSingleVar() const {
auto pattern = getSemanticsProvidingPattern();
if (auto named = dyn_cast<NamedPattern>(pattern))
return named->getDecl();
return nullptr;
}
namespace {
class WalkToVarDecls : public ASTWalker {
const std::function<void(VarDecl*)> &fn;
public:
WalkToVarDecls(const std::function<void(VarDecl*)> &fn)
: fn(fn) {}
Pattern *walkToPatternPost(Pattern *P) override {
// Handle vars.
if (auto *Named = dyn_cast<NamedPattern>(P))
fn(Named->getDecl());
return P;
}
};
}
/// \brief apply the specified function to all variables referenced in this
/// pattern.
void Pattern::forEachVariable(const std::function<void(VarDecl*)> &fn) const {
switch (getKind()) {
case PatternKind::Any:
case PatternKind::Bool:
return;
case PatternKind::Is:
if (auto SP = cast<IsPattern>(this)->getSubPattern())
SP->forEachVariable(fn);
return;
case PatternKind::Named:
fn(cast<NamedPattern>(this)->getDecl());
return;
case PatternKind::Paren:
case PatternKind::Typed:
case PatternKind::Var:
return getSemanticsProvidingPattern()->forEachVariable(fn);
case PatternKind::Tuple:
for (auto elt : cast<TuplePattern>(this)->getElements())
elt.getPattern()->forEachVariable(fn);
return;
case PatternKind::NominalType:
for (auto elt : cast<NominalTypePattern>(this)->getElements())
elt.getSubPattern()->forEachVariable(fn);
return;
case PatternKind::EnumElement:
if (auto SP = cast<EnumElementPattern>(this)->getSubPattern())
SP->forEachVariable(fn);
return;
case PatternKind::OptionalSome:
cast<OptionalSomePattern>(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<Pattern*>(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<void(Pattern*)> &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<IsPattern>(this)->getSubPattern())
SP->forEachNode(f);
return;
case PatternKind::Paren:
return cast<ParenPattern>(this)->getSubPattern()->forEachNode(f);
case PatternKind::Typed:
return cast<TypedPattern>(this)->getSubPattern()->forEachNode(f);
case PatternKind::Var:
return cast<VarPattern>(this)->getSubPattern()->forEachNode(f);
case PatternKind::Tuple:
for (auto elt : cast<TuplePattern>(this)->getElements())
elt.getPattern()->forEachNode(f);
return;
case PatternKind::NominalType:
for (auto elt : cast<NominalTypePattern>(this)->getElements())
elt.getSubPattern()->forEachNode(f);
return;
case PatternKind::EnumElement: {
auto *OP = cast<EnumElementPattern>(this);
if (OP->hasSubPattern())
OP->getSubPattern()->forEachNode(f);
return;
}
case PatternKind::OptionalSome:
cast<OptionalSomePattern>(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<ParenExpr>(expr)) {
expr = parens->getSubExpr();
continue;
}
// A '_' is an untranslated AnyPattern.
if (isa<DiscardAssignmentExpr>(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<Pattern*>(this)->forEachNode([&](Pattern *Node) {
// If this is an always matching 'is' pattern, then it isn't refutable.
if (auto *is = dyn_cast<IsPattern>(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<ExprPattern>(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;
}
unsigned Pattern::numTopLevelVariables() const {
auto pattern = getSemanticsProvidingPattern();
if (auto tuple = dyn_cast<TuplePattern>(pattern))
return tuple->getNumElements();
return 1;
}
static Pattern *buildImplicitLetParameter(ASTContext &ctx, Identifier name,
SourceLoc loc, TypeLoc tyLoc,
DeclContext *DC) {
auto *paramDecl = new (ctx) ParamDecl(/*IsLet*/ true, SourceLoc(),
Identifier(), loc, name,
tyLoc.getType(), DC);
paramDecl->setImplicit();
Pattern *P = new (ctx) NamedPattern(paramDecl, /*Implicit=*/true);
P->setType(tyLoc.getType());
P = new (ctx) TypedPattern(P, tyLoc, /*Implicit=*/true);
P->setType(tyLoc.getType());
paramDecl->setParamParentPattern(P);
return P;
}
Pattern *Pattern::buildImplicitSelfParameter(SourceLoc loc, TypeLoc tyLoc,
DeclContext *DC) {
ASTContext &ctx = DC->getASTContext();
return ::buildImplicitLetParameter(ctx, ctx.Id_self, loc, tyLoc, DC);
}
Pattern *Pattern::buildImplicitLetParameter(SourceLoc loc, StringRef name,
TypeLoc tyLoc, DeclContext *DC) {
ASTContext &ctx = DC->getASTContext();
Identifier ident = (name.empty() ? Identifier() : ctx.getIdentifier(name));
return ::buildImplicitLetParameter(ctx, ident, loc, tyLoc, DC);
}
Pattern *Pattern::clone(ASTContext &context,
OptionSet<CloneFlags> options) const {
Pattern *result;
switch (getKind()) {
case PatternKind::Any: {
result = new (context) AnyPattern(cast<AnyPattern>(this)->getLoc());
break;
}
case PatternKind::Named: {
auto named = cast<NamedPattern>(this);
VarDecl *var;
if (auto param = dyn_cast<ParamDecl>(named->getDecl())) {
auto name = param->getName();
// If the argument isn't named, and we're cloning for an inherited
// constructor, give the parameter a name so that silgen will produce a
// value for it.
if (name.empty() && (options & Inherited))
name = context.getIdentifier("argument");
var = new (context) ParamDecl(param->isLet(),
param->getArgumentNameLoc(),
param->getArgumentName(),
param->getLoc(), name,
param->hasType()
? param->getType()
: Type(),
param->getDeclContext());
} else {
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 ((options & Implicit) || var->isImplicit())
var->setImplicit();
result = new (context) NamedPattern(var);
break;
}
case PatternKind::Paren: {
auto paren = cast<ParenPattern>(this);
result = new (context) ParenPattern(paren->getLParenLoc(),
paren->getSubPattern()->clone(context,
options),
paren->getRParenLoc());
break;
}
case PatternKind::Tuple: {
auto tuple = cast<TuplePattern>(this);
SmallVector<TuplePatternElt, 2> elts;
elts.reserve(tuple->getNumElements());
for (const auto &elt : tuple->getElements()) {
auto eltPattern = elt.getPattern()->clone(context, options);
// If we're inheriting a default argument, mark it as such.
if (elt.getDefaultArgKind() != DefaultArgumentKind::None &&
(options & Inherited)) {
elts.push_back(TuplePatternElt(elt.getLabel(), elt.getLabelLoc(),
eltPattern, elt.hasEllipsis(),
elt.getEllipsisLoc(), nullptr,
DefaultArgumentKind::Inherited));
} else {
elts.push_back(TuplePatternElt(elt.getLabel(), elt.getLabelLoc(),
eltPattern, elt.hasEllipsis(),
elt.getEllipsisLoc(), elt.getInit(),
elt.getDefaultArgKind()));
}
}
result = TuplePattern::create(context, tuple->getLParenLoc(), elts,
tuple->getRParenLoc());
break;
}
case PatternKind::Typed: {
auto typed = cast<TypedPattern>(this);
result = new(context) TypedPattern(typed->getSubPattern()->clone(context,
options),
typed->getTypeLoc().clone(context));
break;
}
case PatternKind::Is: {
auto isa = cast<IsPattern>(this);
result = new(context) IsPattern(isa->getLoc(),
isa->getCastTypeLoc().clone(context),
isa->getSubPattern()->clone(context,
options),
isa->getCastKind());
break;
}
case PatternKind::NominalType: {
auto nom = cast<NominalTypePattern>(this);
SmallVector<NominalTypePattern::Element, 4> elts;
for (const auto &elt : nom->getElements()) {
elts.push_back(NominalTypePattern::Element(elt.getPropertyLoc(),
elt.getPropertyName(),
elt.getProperty(),
elt.getColonLoc(),
elt.getSubPattern()->clone(context,
options)));
}
result = NominalTypePattern::create(nom->getCastTypeLoc().clone(context),
nom->getLParenLoc(),
elts,
nom->getRParenLoc(), context);
break;
}
case PatternKind::EnumElement: {
auto oof = cast<EnumElementPattern>(this);
Pattern *sub = nullptr;
if (oof->hasSubPattern())
sub = oof->getSubPattern()->clone(context, options);
result = new (context) EnumElementPattern(oof->getParentType()
.clone(context),
oof->getLoc(),
oof->getNameLoc(),
oof->getName(),
oof->getElementDecl(),
sub);
break;
}
case PatternKind::OptionalSome: {
auto osp = cast<OptionalSomePattern>(this);
auto *sub = osp->getSubPattern()->clone(context, options);
auto *r = new (context) OptionalSomePattern(sub, osp->getQuestionLoc());
r->setElementDecl(osp->getElementDecl());
result = r;
break;
}
case PatternKind::Bool: {
auto bp = cast<BoolPattern>(this);
result = new (context) BoolPattern(bp->getNameLoc(), bp->getValue());
break;
}
case PatternKind::Expr: {
auto expr = cast<ExprPattern>(this);
result = new(context) ExprPattern(expr->getSubExpr(),
expr->isResolved(),
expr->getMatchExpr(),
expr->getMatchVar());
break;
}
case PatternKind::Var: {
auto var = cast<VarPattern>(this);
result = new(context) VarPattern(var->getLoc(), var->isLet(),
var->getSubPattern()->clone(
context,
options|IsVar));
}
}
if (hasType())
result->setType(getType());
if ((options & Implicit) || isImplicit())
result->setImplicit();
return result;
}
Pattern *Pattern::cloneForwardable(ASTContext &context, DeclContext *DC,
OptionSet<CloneFlags> options) const {
Pattern *result;
switch (getKind()) {
case PatternKind::Any:
case PatternKind::Is:
case PatternKind::NominalType:
case PatternKind::EnumElement:
case PatternKind::OptionalSome:
case PatternKind::Bool:
case PatternKind::Expr:
llvm_unreachable("cannot forward this kind of pattern");
case PatternKind::Named:
return clone(context, options);
case PatternKind::Paren: {
auto paren = cast<ParenPattern>(this);
auto sub = paren->getSubPattern()->cloneForwardable(context, DC, options);
result = new (context) ParenPattern(paren->getLParenLoc(),
sub,
paren->getRParenLoc());
break;
}
case PatternKind::Var: {
auto var = cast<VarPattern>(this);
result = new(context) VarPattern(var->getLoc(), var->isLet(),
var->getSubPattern()->cloneForwardable(
context, DC, options|IsVar));
break;
}
case PatternKind::Tuple: {
auto tuple = cast<TuplePattern>(this);
SmallVector<TuplePatternElt, 2> elts;
elts.reserve(tuple->getNumElements());
for (const auto &elt : tuple->getElements()) {
auto eltPattern = elt.getPattern()->cloneForwardable(context, DC, options);
// If we're inheriting a default argument, mark it as such.
if (elt.getDefaultArgKind() != DefaultArgumentKind::None &&
(options & Inherited)) {
elts.push_back(TuplePatternElt(elt.getLabel(), elt.getLabelLoc(),
eltPattern, elt.hasEllipsis(),
elt.getEllipsisLoc(), nullptr,
DefaultArgumentKind::Inherited));
} else {
elts.push_back(TuplePatternElt(elt.getLabel(), elt.getLabelLoc(),
eltPattern, elt.hasEllipsis(),
elt.getEllipsisLoc(), elt.getInit(),
elt.getDefaultArgKind()));
}
}
result = TuplePattern::create(context, tuple->getLParenLoc(), elts,
tuple->getRParenLoc());
break;
}
case PatternKind::Typed: {
auto typed = cast<TypedPattern>(this);
TypeLoc tyLoc = typed->getTypeLoc().clone(context);
const Pattern *origSub = typed->getSubPattern();
// If the original sub-pattern is a single named variable, go
// ahead and clone it.
if (origSub->getSingleVar()) {
Pattern *cloneSub = origSub->cloneForwardable(context, DC, options);
result = new (context) TypedPattern(cloneSub, tyLoc);
// Otherwise, create a new bound variable.
} else {
result = buildImplicitLetParameter(origSub->getLoc(), "", tyLoc, DC);
}
break;
}
}
if (hasType())
result->setType(getType());
if ((options & Implicit) || isImplicit())
result->setImplicit();
return result;
}
Expr *Pattern::buildForwardingRefExpr(ASTContext &context) const {
switch (getKind()) {
case PatternKind::Any:
case PatternKind::Is:
case PatternKind::NominalType:
case PatternKind::EnumElement:
case PatternKind::OptionalSome:
case PatternKind::Bool:
case PatternKind::Expr:
llvm_unreachable("cannot forward this kind of pattern");
case PatternKind::Named: {
auto np = cast<NamedPattern>(this);
Expr *ref = new (context) DeclRefExpr(np->getDecl(), SourceLoc(),
/*implicit*/ true);
if (np->getDecl()->getType()->is<InOutType>())
ref = new (context) InOutExpr(SourceLoc(), ref, Type(),
/*implicit=*/true);
return ref;
}
case PatternKind::Paren: {
auto paren = cast<ParenPattern>(this);
return paren->getSubPattern()->buildForwardingRefExpr(context);
}
case PatternKind::Var: {
auto var = cast<VarPattern>(this);
return var->getSubPattern()->buildForwardingRefExpr(context);
}
case PatternKind::Typed: {
auto typed = cast<TypedPattern>(this);
return typed->getSubPattern()->buildForwardingRefExpr(context);
}
case PatternKind::Tuple: {
auto tuple = cast<TuplePattern>(this);
SmallVector<Expr*, 2> elts;
SmallVector<Identifier, 2> labels;
SmallVector<SourceLoc, 2> labelLocs;
elts.reserve(tuple->getNumElements());
labels.reserve(tuple->getNumElements());
labelLocs.reserve(tuple->getNumElements());
for (const auto &elt : tuple->getElements()) {
elts.push_back(elt.getPattern()->buildForwardingRefExpr(context));
labels.push_back(Identifier()); // FIXME?
labelLocs.push_back(SourceLoc());
}
return TupleExpr::create(context, SourceLoc(), elts, labels, labelLocs,
SourceLoc(), /*trailing closure*/ false,
/*implicit*/ true);
}
}
llvm_unreachable("bad pattern kind");
}
/// 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<NamedPattern>(getSemanticsProvidingPattern()))
return NP->getBoundName();
return Identifier();
}
Identifier Pattern::getBodyName() const {
if (auto *NP = dyn_cast<NamedPattern>(getSemanticsProvidingPattern()))
return NP->getBodyName();
return Identifier();
}
Identifier NamedPattern::getBoundName() const {
if (auto param = dyn_cast<ParamDecl>(Var))
return param->getArgumentName();
return Var->getName();
}
Identifier NamedPattern::getBodyName() const {
return Var->getName();
}
/// Allocate a new pattern that matches a tuple.
TuplePattern *TuplePattern::create(ASTContext &C, SourceLoc lp,
ArrayRef<TuplePatternElt> elts, SourceLoc rp,
Optional<bool> 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<TuplePatternElt> elements,
SourceLoc rp,
Optional<bool> implicit) {
assert(lp.isValid() == rp.isValid());
if (elements.size() == 1 &&
!elements[0].hasEllipsis() &&
elements[0].getInit() == nullptr &&
elements[0].getPattern()->getBoundName().empty() &&
elements[0].getPattern()->getBodyName().empty()) {
auto &first = const_cast<TuplePatternElt&>(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() };
}
bool TuplePattern::hasAnyEllipsis() const {
for (const auto elt : getElements()) {
if (elt.hasEllipsis())
return true;
}
return false;
}
SourceLoc TuplePattern::getAnyEllipsisLoc() const {
for (const auto elt : getElements()) {
if (elt.hasEllipsis())
return elt.getEllipsisLoc();
}
return SourceLoc();
}
SourceRange TypedPattern::getSourceRange() const {
if (isImplicit()) {
// If a TypedPattern is implicit, then its type is definitely implicit, se
// 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<Element> Elements,
SourceLoc RParenLoc,
ASTContext &C,
Optional<bool> implicit) {
void *buf = C.Allocate(sizeof(NominalTypePattern)
+ sizeof(Element) * Elements.size(),
alignof(Element));
return ::new (buf) NominalTypePattern(CastTy, LParenLoc, Elements, RParenLoc,
implicit);
}