mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
858 lines
27 KiB
C++
858 lines
27 KiB
C++
//===--- Pattern.cpp - Swift Language Pattern-Matching ASTs ---------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://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/ASTContext.h"
|
|
#include "swift/AST/ASTVisitor.h"
|
|
#include "swift/AST/ASTWalker.h"
|
|
#include "swift/AST/Expr.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/TypeCheckRequests.h"
|
|
#include "swift/AST/TypeLoc.h"
|
|
#include "swift/AST/TypeRepr.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/Basic/Statistic.h"
|
|
#include "llvm/ADT/APFloat.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace swift;
|
|
|
|
#define PATTERN(Id, _) \
|
|
static_assert(IsTriviallyDestructible<Id##Pattern>::value, \
|
|
"Patterns are BumpPtrAllocated; the d'tor is never called");
|
|
#include "swift/AST/PatternNodes.def"
|
|
|
|
DescriptivePatternKind Pattern::getDescriptiveKind() const {
|
|
#define TRIVIAL_PATTERN_KIND(Kind) \
|
|
case PatternKind::Kind: \
|
|
return DescriptivePatternKind::Kind
|
|
|
|
switch (getKind()) {
|
|
TRIVIAL_PATTERN_KIND(Paren);
|
|
TRIVIAL_PATTERN_KIND(Tuple);
|
|
TRIVIAL_PATTERN_KIND(Named);
|
|
TRIVIAL_PATTERN_KIND(Any);
|
|
TRIVIAL_PATTERN_KIND(Typed);
|
|
TRIVIAL_PATTERN_KIND(Is);
|
|
TRIVIAL_PATTERN_KIND(EnumElement);
|
|
TRIVIAL_PATTERN_KIND(OptionalSome);
|
|
TRIVIAL_PATTERN_KIND(Bool);
|
|
TRIVIAL_PATTERN_KIND(Expr);
|
|
|
|
case PatternKind::Binding:
|
|
switch (cast<BindingPattern>(this)->getIntroducer()) {
|
|
case VarDecl::Introducer::Let:
|
|
case VarDecl::Introducer::Borrowing:
|
|
return DescriptivePatternKind::Let;
|
|
|
|
case VarDecl::Introducer::Var:
|
|
case VarDecl::Introducer::InOut:
|
|
return DescriptivePatternKind::Var;
|
|
}
|
|
}
|
|
#undef TRIVIAL_PATTERN_KIND
|
|
llvm_unreachable("bad DescriptivePatternKind");
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
StringRef Pattern::getDescriptivePatternKindName(DescriptivePatternKind K) {
|
|
#define ENTRY(Kind, String) \
|
|
case DescriptivePatternKind::Kind: \
|
|
return String
|
|
switch (K) {
|
|
ENTRY(Paren, "parenthesized pattern");
|
|
ENTRY(Tuple, "tuple pattern");
|
|
ENTRY(Named, "pattern variable binding");
|
|
ENTRY(Any, "'_' pattern");
|
|
ENTRY(Typed, "pattern type annotation");
|
|
ENTRY(Is, "prefix 'is' pattern");
|
|
ENTRY(EnumElement, "enum case matching pattern");
|
|
ENTRY(OptionalSome, "optional pattern");
|
|
ENTRY(Bool, "bool matching pattern");
|
|
ENTRY(Expr, "expression pattern");
|
|
ENTRY(Var, "'var' binding pattern");
|
|
ENTRY(Let, "'let' binding pattern");
|
|
}
|
|
#undef ENTRY
|
|
llvm_unreachable("bad DescriptivePatternKind");
|
|
}
|
|
|
|
// 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!");
|
|
}
|
|
|
|
void Pattern::setDelayedInterfaceType(Type interfaceTy, DeclContext *dc) {
|
|
assert(interfaceTy->hasTypeParameter() && "Not an interface type");
|
|
Ty = interfaceTy;
|
|
ASTContext &ctx = interfaceTy->getASTContext();
|
|
ctx.DelayedPatternContexts[this] = dc;
|
|
Bits.Pattern.hasInterfaceType = true;
|
|
}
|
|
|
|
Type Pattern::getType() const {
|
|
assert(hasType());
|
|
|
|
// If this pattern has an interface type, map it into the context type.
|
|
if (Bits.Pattern.hasInterfaceType) {
|
|
ASTContext &ctx = Ty->getASTContext();
|
|
|
|
// Retrieve the generic environment to use for the mapping.
|
|
auto found = ctx.DelayedPatternContexts.find(this);
|
|
assert(found != ctx.DelayedPatternContexts.end());
|
|
auto dc = found->second;
|
|
|
|
if (auto genericEnv = dc->getGenericEnvironmentOfContext()) {
|
|
ctx.DelayedPatternContexts.erase(this);
|
|
Ty = genericEnv->mapTypeIntoContext(Ty);
|
|
const_cast<Pattern*>(this)->Bits.Pattern.hasInterfaceType = false;
|
|
}
|
|
}
|
|
|
|
return Ty;
|
|
}
|
|
|
|
/// 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) {}
|
|
|
|
/// Walk everything that's available; there shouldn't be macro expansions
|
|
/// that matter anyway.
|
|
MacroWalking getMacroWalkingBehavior() const override {
|
|
return MacroWalking::ArgumentsAndExpansion;
|
|
}
|
|
|
|
PostWalkResult<Pattern *> walkToPatternPost(Pattern *P) override {
|
|
// Handle vars.
|
|
if (auto *Named = dyn_cast<NamedPattern>(P))
|
|
fn(Named->getDecl());
|
|
return Action::Continue(P);
|
|
}
|
|
|
|
// Only walk into an expression insofar as it doesn't open a new scope -
|
|
// that is, don't walk into a closure body.
|
|
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
|
|
if (isa<ClosureExpr>(E)) {
|
|
return Action::SkipNode(E);
|
|
}
|
|
return Action::Continue(E);
|
|
}
|
|
|
|
// Don't walk into anything else.
|
|
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
|
|
return Action::SkipNode(S);
|
|
}
|
|
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
|
|
return Action::SkipNode();
|
|
}
|
|
PreWalkAction walkToParameterListPre(ParameterList *PL) override {
|
|
return Action::SkipNode();
|
|
}
|
|
PreWalkAction walkToDeclPre(Decl *D) override {
|
|
return Action::SkipNode();
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
|
|
/// apply the specified function to all variables referenced in this
|
|
/// pattern.
|
|
void Pattern::forEachVariable(llvm::function_ref<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::Binding:
|
|
return getSemanticsProvidingPattern()->forEachVariable(fn);
|
|
|
|
case PatternKind::Tuple:
|
|
for (auto elt : cast<TuplePattern>(this)->getElements())
|
|
elt.getPattern()->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;
|
|
}
|
|
}
|
|
|
|
/// apply the specified function to all pattern nodes recursively in
|
|
/// this pattern. This is a pre-order traversal.
|
|
void Pattern::forEachNode(llvm::function_ref<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::Binding:
|
|
return cast<BindingPattern>(this)->getSubPattern()->forEachNode(f);
|
|
|
|
case PatternKind::Tuple:
|
|
for (auto elt : cast<TuplePattern>(this)->getElements())
|
|
elt.getPattern()->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;
|
|
}
|
|
}
|
|
|
|
bool Pattern::hasStorage() const {
|
|
bool HasStorage = false;
|
|
forEachVariable([&](VarDecl *VD) {
|
|
if (VD->hasStorage())
|
|
HasStorage = true;
|
|
});
|
|
|
|
return HasStorage;
|
|
}
|
|
|
|
bool Pattern::hasAnyMutableBindings() const {
|
|
auto HasMutable = false;
|
|
forEachVariable([&](VarDecl *VD) {
|
|
if (!VD->isLet())
|
|
HasMutable = true;
|
|
});
|
|
return HasMutable;
|
|
}
|
|
|
|
BindingPattern *BindingPattern::createParsed(ASTContext &ctx, SourceLoc loc,
|
|
VarDecl::Introducer introducer,
|
|
Pattern *sub) {
|
|
// Reset the introducer of the all variables in the pattern.
|
|
sub->forEachVariable([&](VarDecl *vd) { vd->setIntroducer(introducer); });
|
|
return new (ctx) BindingPattern(loc, introducer, sub);
|
|
}
|
|
|
|
BindingPattern *BindingPattern::createImplicitCatch(DeclContext *dc,
|
|
SourceLoc loc) {
|
|
auto &ctx = dc->getASTContext();
|
|
auto var = new (ctx) VarDecl(/*IsStatic=*/false, VarDecl::Introducer::Let,
|
|
loc, ctx.Id_error, dc);
|
|
var->setImplicit();
|
|
auto namePattern = new (ctx) NamedPattern(var);
|
|
auto varPattern =
|
|
new (ctx) BindingPattern(loc, VarDecl::Introducer::Let, namePattern);
|
|
varPattern->setImplicit();
|
|
return varPattern;
|
|
}
|
|
|
|
OptionalSomePattern *OptionalSomePattern::create(ASTContext &ctx,
|
|
Pattern *subPattern,
|
|
SourceLoc questionLoc) {
|
|
return new (ctx) OptionalSomePattern(ctx, subPattern, questionLoc);
|
|
}
|
|
|
|
OptionalSomePattern *OptionalSomePattern::createImplicit(ASTContext &ctx,
|
|
Pattern *subPattern) {
|
|
auto *P = OptionalSomePattern::create(ctx, subPattern,
|
|
/*questionLoc*/ SourceLoc());
|
|
P->setImplicit();
|
|
return P;
|
|
}
|
|
|
|
EnumElementDecl *OptionalSomePattern::getElementDecl() const {
|
|
return Ctx.getOptionalSomeDecl();
|
|
}
|
|
|
|
/// Return true if this is a non-resolved ExprPattern which is syntactically
|
|
/// irrefutable.
|
|
static bool isIrrefutableExprPattern(const ExprPattern *EP) {
|
|
// If the pattern is resolved, it must be irrefutable.
|
|
if (EP->isResolved()) 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 ||
|
|
is->getCastKind() == CheckedCastKind::BridgingCoercion)
|
|
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;
|
|
}
|
|
|
|
/// 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 NamedPattern::getBoundName() const {
|
|
return Var->getName();
|
|
}
|
|
|
|
|
|
/// Allocate a new pattern that matches a tuple.
|
|
TuplePattern *TuplePattern::create(ASTContext &C, SourceLoc lp,
|
|
ArrayRef<TuplePatternElt> elts,
|
|
SourceLoc rp) {
|
|
#ifndef NDEBUG
|
|
if (elts.size() == 1)
|
|
assert(!elts[0].getLabel().empty());
|
|
#endif
|
|
|
|
unsigned n = elts.size();
|
|
void *buffer = C.Allocate(totalSizeToAlloc<TuplePatternElt>(n),
|
|
alignof(TuplePattern));
|
|
TuplePattern *pattern = ::new (buffer) TuplePattern(lp, n, rp);
|
|
std::uninitialized_copy(elts.begin(), elts.end(),
|
|
pattern->getTrailingObjects<TuplePatternElt>());
|
|
return pattern;
|
|
}
|
|
|
|
Pattern *TuplePattern::createSimple(ASTContext &C, SourceLoc lp,
|
|
ArrayRef<TuplePatternElt> elements,
|
|
SourceLoc rp) {
|
|
assert(lp.isValid() == rp.isValid());
|
|
|
|
if (elements.size() == 1 &&
|
|
elements[0].getLabel().empty()) {
|
|
auto &first = const_cast<TuplePatternElt&>(elements.front());
|
|
return new (C) ParenPattern(lp, first.getPattern(), rp);
|
|
}
|
|
|
|
return create(C, lp, elements, rp);
|
|
}
|
|
|
|
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() };
|
|
}
|
|
|
|
TypedPattern::TypedPattern(Pattern *pattern, TypeRepr *tr)
|
|
: Pattern(PatternKind::Typed), SubPattern(pattern), PatTypeRepr(tr) {
|
|
Bits.TypedPattern.IsPropagatedType = false;
|
|
}
|
|
|
|
SourceLoc TypedPattern::getLoc() const {
|
|
if (SubPattern->isImplicit() && PatTypeRepr)
|
|
return PatTypeRepr->getSourceRange().Start;
|
|
|
|
return SubPattern->getLoc();
|
|
}
|
|
|
|
SourceRange TypedPattern::getSourceRange() const {
|
|
if (isImplicit() || isPropagatedType()) {
|
|
// 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 (!PatTypeRepr)
|
|
return SourceRange();
|
|
|
|
if (SubPattern->isImplicit())
|
|
return PatTypeRepr->getSourceRange();
|
|
|
|
return { SubPattern->getSourceRange().Start,
|
|
PatTypeRepr->getSourceRange().End };
|
|
}
|
|
|
|
IsPattern::IsPattern(SourceLoc IsLoc, TypeExpr *CastTy, Pattern *SubPattern,
|
|
CheckedCastKind Kind)
|
|
: Pattern(PatternKind::Is), IsLoc(IsLoc), SubPattern(SubPattern),
|
|
CastKind(Kind), CastType(CastTy) {
|
|
assert(IsLoc.isValid() == CastTy->getLoc().isValid());
|
|
}
|
|
|
|
IsPattern *IsPattern::createImplicit(ASTContext &Ctx, Type castTy,
|
|
Pattern *SubPattern,
|
|
CheckedCastKind Kind) {
|
|
assert(castTy);
|
|
auto *CastTE = TypeExpr::createImplicit(castTy, Ctx);
|
|
auto *ip = new (Ctx) IsPattern(SourceLoc(), CastTE, SubPattern, Kind);
|
|
ip->setImplicit();
|
|
return ip;
|
|
}
|
|
|
|
SourceRange IsPattern::getSourceRange() const {
|
|
SourceLoc beginLoc = SubPattern ? SubPattern->getSourceRange().Start : IsLoc;
|
|
SourceLoc endLoc = (isImplicit() ? beginLoc : CastType->getEndLoc());
|
|
return {beginLoc, endLoc};
|
|
}
|
|
|
|
Type IsPattern::getCastType() const { return CastType->getInstanceType(); }
|
|
void IsPattern::setCastType(Type type) {
|
|
assert(type);
|
|
CastType->setType(MetatypeType::get(type));
|
|
}
|
|
|
|
TypeRepr *IsPattern::getCastTypeRepr() const { return CastType->getTypeRepr(); }
|
|
|
|
ExprPattern *ExprPattern::createParsed(ASTContext &ctx, Expr *E,
|
|
DeclContext *DC) {
|
|
return new (ctx) ExprPattern(E, DC, /*isResolved*/ false);
|
|
}
|
|
|
|
ExprPattern *ExprPattern::createResolved(ASTContext &ctx, Expr *E,
|
|
DeclContext *DC) {
|
|
return new (ctx) ExprPattern(E, DC, /*isResolved*/ true);
|
|
}
|
|
|
|
ExprPattern *ExprPattern::createImplicit(ASTContext &ctx, Expr *E,
|
|
DeclContext *DC) {
|
|
auto *EP = ExprPattern::createResolved(ctx, E, DC);
|
|
EP->setImplicit();
|
|
return EP;
|
|
}
|
|
|
|
Expr *ExprPattern::getMatchExpr() const {
|
|
auto &eval = DC->getASTContext().evaluator;
|
|
return evaluateOrDefault(eval, ExprPatternMatchRequest{this}, std::nullopt)
|
|
.getMatchExpr();
|
|
}
|
|
|
|
VarDecl *ExprPattern::getMatchVar() const {
|
|
auto &eval = DC->getASTContext().evaluator;
|
|
return evaluateOrDefault(eval, ExprPatternMatchRequest{this}, std::nullopt)
|
|
.getMatchVar();
|
|
}
|
|
|
|
void ExprPattern::updateMatchExpr(Expr *e) const {
|
|
class FindMatchOperatorDeclRef: public ASTWalker {
|
|
public:
|
|
ValueOwnership Ownership = ValueOwnership::Default;
|
|
|
|
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
|
|
// See if this is the reference to the ~= operator used.
|
|
auto declRef = dyn_cast<DeclRefExpr>(E);
|
|
if (!declRef) {
|
|
return Action::Continue(E);
|
|
}
|
|
auto decl = declRef->getDecl();
|
|
auto declName = decl->getName();
|
|
if (!declName.isOperator()) {
|
|
return Action::Continue(E);
|
|
}
|
|
|
|
if (!declName.getBaseIdentifier().is("~=")) {
|
|
return Action::Continue(E);
|
|
}
|
|
|
|
// We found a `~=` declref. Get the value ownership from the parameter.
|
|
auto fnTy = decl->getInterfaceType()->castTo<AnyFunctionType>();
|
|
if (decl->isStatic()) {
|
|
fnTy = fnTy->getResult()->castTo<AnyFunctionType>();
|
|
}
|
|
// Subject value is the right-hand operand to the operator.
|
|
assert(fnTy->getParams().size() == 2);
|
|
Ownership = fnTy->getParams()[1].getValueOwnership();
|
|
// Operators are always normal functions or methods, so their default
|
|
// parameter ownership is always borrowing.
|
|
if (Ownership == ValueOwnership::Default) {
|
|
Ownership = ValueOwnership::Shared;
|
|
}
|
|
return Action::Stop();
|
|
}
|
|
};
|
|
FindMatchOperatorDeclRef walker;
|
|
e->walk(walker);
|
|
|
|
MatchExprAndOperandOwnership = {e, walker.Ownership};
|
|
}
|
|
|
|
EnumElementPattern *
|
|
EnumElementPattern::createImplicit(Type parentTy, SourceLoc dotLoc,
|
|
DeclNameLoc nameLoc, EnumElementDecl *decl,
|
|
Pattern *subPattern, DeclContext *DC) {
|
|
auto &ctx = DC->getASTContext();
|
|
auto *parentExpr = TypeExpr::createImplicit(parentTy, ctx);
|
|
auto *P = new (ctx) EnumElementPattern(
|
|
parentExpr, dotLoc, nameLoc, decl->createNameRef(), decl, subPattern, DC);
|
|
P->setImplicit();
|
|
P->setType(parentTy);
|
|
return P;
|
|
}
|
|
|
|
SourceLoc EnumElementPattern::getStartLoc() const {
|
|
return (ParentType && !ParentType->isImplicit())
|
|
? ParentType->getSourceRange().Start
|
|
: DotLoc.isValid() ? DotLoc : NameLoc.getBaseNameLoc();
|
|
}
|
|
|
|
SourceLoc EnumElementPattern::getEndLoc() const {
|
|
if (SubPattern && SubPattern->getSourceRange().isValid()) {
|
|
return SubPattern->getSourceRange().End;
|
|
}
|
|
return NameLoc.getEndLoc();
|
|
}
|
|
|
|
TypeRepr *EnumElementPattern::getParentTypeRepr() const {
|
|
if (!ParentType)
|
|
return nullptr;
|
|
return ParentType->getTypeRepr();
|
|
}
|
|
|
|
Type EnumElementPattern::getParentType() const {
|
|
if (!ParentType)
|
|
return Type();
|
|
return ParentType->getInstanceType();
|
|
}
|
|
|
|
void EnumElementPattern::setParentType(Type type) {
|
|
assert(type);
|
|
if (ParentType) {
|
|
ParentType->setType(MetatypeType::get(type));
|
|
} else {
|
|
ParentType = TypeExpr::createImplicit(type, type->getASTContext());
|
|
}
|
|
}
|
|
|
|
SourceLoc ExprPattern::getLoc() const {
|
|
return getSubExpr()->getLoc();
|
|
}
|
|
|
|
SourceRange ExprPattern::getSourceRange() const {
|
|
return getSubExpr()->getSourceRange();
|
|
}
|
|
|
|
// See swift/Basic/Statistic.h for declaration: this enables tracing Patterns, is
|
|
// defined here to avoid too much layering violation / circular linkage
|
|
// dependency.
|
|
|
|
struct PatternTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
|
|
void traceName(const void *Entity, raw_ostream &OS) const override {
|
|
if (!Entity)
|
|
return;
|
|
const Pattern *P = static_cast<const Pattern *>(Entity);
|
|
if (const NamedPattern *NP = dyn_cast<NamedPattern>(P)) {
|
|
OS << NP->getBoundName();
|
|
}
|
|
}
|
|
void traceLoc(const void *Entity, SourceManager *SM,
|
|
clang::SourceManager *CSM, raw_ostream &OS) const override {
|
|
if (!Entity)
|
|
return;
|
|
const Pattern *P = static_cast<const Pattern *>(Entity);
|
|
P->getSourceRange().print(OS, *SM, false);
|
|
}
|
|
};
|
|
|
|
static PatternTraceFormatter TF;
|
|
|
|
template<>
|
|
const UnifiedStatsReporter::TraceFormatter*
|
|
FrontendStatsTracer::getTraceFormatter<const Pattern *>() {
|
|
return &TF;
|
|
}
|
|
|
|
|
|
ContextualPattern ContextualPattern::forPatternBindingDecl(
|
|
PatternBindingDecl *pbd, unsigned index) {
|
|
return ContextualPattern(
|
|
pbd->getPattern(index), /*isTopLevel=*/true, pbd, index);
|
|
}
|
|
|
|
DeclContext *ContextualPattern::getDeclContext() const {
|
|
if (auto pbd = getPatternBindingDecl())
|
|
return pbd->getDeclContext();
|
|
|
|
return declOrContext.get<DeclContext *>();
|
|
}
|
|
|
|
PatternBindingDecl *ContextualPattern::getPatternBindingDecl() const {
|
|
return declOrContext.dyn_cast<PatternBindingDecl *>();
|
|
}
|
|
|
|
bool ContextualPattern::allowsInference() const {
|
|
if (auto pbd = getPatternBindingDecl()) {
|
|
return pbd->isInitialized(index) ||
|
|
pbd->isDefaultInitializableViaPropertyWrapper(index);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void swift::simple_display(llvm::raw_ostream &out,
|
|
const ContextualPattern &pattern) {
|
|
simple_display(out, pattern.getPattern());
|
|
}
|
|
|
|
void swift::simple_display(llvm::raw_ostream &out, const Pattern *pattern) {
|
|
out << "(pattern @ " << pattern << ")";
|
|
}
|
|
|
|
SourceLoc swift::extractNearestSourceLoc(const Pattern *pattern) {
|
|
return pattern->getLoc();
|
|
}
|
|
|
|
ValueOwnership
|
|
Pattern::getOwnership(
|
|
SmallVectorImpl<Pattern *> *mostRestrictiveSubpatterns) const
|
|
{
|
|
class GetPatternOwnership: public PatternVisitor<GetPatternOwnership, void> {
|
|
public:
|
|
ValueOwnership Ownership = ValueOwnership::Shared;
|
|
SmallVectorImpl<Pattern *> *RestrictingPatterns = nullptr;
|
|
|
|
void increaseOwnership(ValueOwnership newOwnership, Pattern *p) {
|
|
// If the new ownership is stricter than the current ownership, then
|
|
// clear the restricting patterns we'd collected and start over with the
|
|
// new stricter ownership.
|
|
if (newOwnership > Ownership) {
|
|
Ownership = newOwnership;
|
|
if (RestrictingPatterns) {
|
|
RestrictingPatterns->clear();
|
|
}
|
|
}
|
|
|
|
if (RestrictingPatterns
|
|
&& newOwnership == Ownership
|
|
&& Ownership > ValueOwnership::Shared) {
|
|
RestrictingPatterns->push_back(p);
|
|
}
|
|
}
|
|
|
|
#define USE_SUBPATTERN(Kind) \
|
|
void visit##Kind##Pattern(Kind##Pattern *pattern) { \
|
|
return visit(pattern->getSubPattern()); \
|
|
}
|
|
|
|
USE_SUBPATTERN(Paren)
|
|
USE_SUBPATTERN(Typed)
|
|
USE_SUBPATTERN(Binding)
|
|
#undef USE_SUBPATTERN
|
|
void visitTuplePattern(TuplePattern *p) {
|
|
for (auto &element : p->getElements()) {
|
|
visit(element.getPattern());
|
|
}
|
|
}
|
|
|
|
void visitNamedPattern(NamedPattern *p) {
|
|
switch (p->getDecl()->getIntroducer()) {
|
|
case VarDecl::Introducer::Let:
|
|
// `let` defaults to the prevailing ownership of the switch.
|
|
break;
|
|
|
|
case VarDecl::Introducer::Var:
|
|
// If the subpattern type is copyable, then we can bind the variable
|
|
// by copying without requiring more than a borrow of the original.
|
|
if (!p->hasType() || !p->getType()->isNoncopyable()) {
|
|
break;
|
|
}
|
|
// TODO: An explicit `consuming` binding kind consumes regardless of
|
|
// type.
|
|
|
|
// Noncopyable `var` consumes the bound value to move it into
|
|
// a new independent variable.
|
|
increaseOwnership(ValueOwnership::Owned, p);
|
|
break;
|
|
|
|
case VarDecl::Introducer::InOut:
|
|
// `inout` bindings modify the value in-place.
|
|
increaseOwnership(ValueOwnership::InOut, p);
|
|
break;
|
|
|
|
case VarDecl::Introducer::Borrowing:
|
|
// `borrow` bindings borrow parts of the value in-place.
|
|
increaseOwnership(ValueOwnership::Shared, p);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void visitAnyPattern(AnyPattern *p) {
|
|
/* no change */
|
|
}
|
|
void visitBoolPattern(BoolPattern *p) {
|
|
/* no change */
|
|
}
|
|
|
|
void visitIsPattern(IsPattern *p) {
|
|
// Casting has to either be possible by borrowing or copying the subject,
|
|
// or can't be supported in a pattern match.
|
|
/* no change */
|
|
}
|
|
|
|
void visitEnumElementPattern(EnumElementPattern *p) {
|
|
if (p->hasSubPattern()) {
|
|
visit(p->getSubPattern());
|
|
}
|
|
}
|
|
|
|
void visitOptionalSomePattern(OptionalSomePattern *p) {
|
|
visit(p->getSubPattern());
|
|
}
|
|
|
|
void visitExprPattern(ExprPattern *p) {
|
|
// A `~=` operator has to be able to either borrow or copy the operand,
|
|
// or can't be used.
|
|
/* no change */
|
|
}
|
|
};
|
|
|
|
GetPatternOwnership visitor;
|
|
visitor.RestrictingPatterns = mostRestrictiveSubpatterns;
|
|
visitor.visit(const_cast<Pattern *>(this));
|
|
return visitor.Ownership;
|
|
}
|