mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This commit implements closure syntax that places the (optional)
parameter list in pipes within the curly braces of a closure. This
syntax "slides" well from very simple closures with anonymous
arguments, e.g.,
sort(array, {$1 > $0})
to naming the arguments
sort(array, {|x, y| x > y})
to adding a return type and/or parameter types
sort(array, {|x : String, y : String| -> Bool x > y})
and with multiple statements in the body:
sort(array, {|x, y|
print("Comparing \(x) and \(y)\n")
return x > y
})
When the body contains only a single expression, that expression
participates in type inference with its enclosing expression, which
allows one to type-check, e.g.,
map(strings, {|x| x.toUpper()})
without context. If one has multiple statements, however, one will
need to provide additional type information either with context
strings = map(strings, {
return $0.toUpper()
})
or via annotations
map(strings, {|x| -> String
return x.toUpper()
}
because we don't perform inter-statement type inference.
The new closure expressions are only available with the new type
checker, where they completely displace the existing { $0 + $1 }
anonymous closures. 'func' expressions remain unchanged.
The tiny test changes (in SIL output and the constraint-checker test)
are due to the PipeClosureExpr AST storing anonymous closure arguments
($0, $1, etc.) within a pattern in the AST. It's far cleaner to
implement this way.
The testing here is still fairly light. In particular, we need better
testing of parser recovery, name lookup for closures with local types,
more deduction scenarios, and multi-statement closures (which don't
get exercised beyond the unit tests).
Swift SVN r5169
284 lines
8.5 KiB
C++
284 lines
8.5 KiB
C++
//===--- Pattern.h - Swift Language Pattern-Matching ASTs -------*- C++ -*-===//
|
|
//
|
|
// 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 defines the Pattern class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_PATTERN_H
|
|
#define SWIFT_PATTERN_H
|
|
|
|
#include "swift/Basic/SourceLoc.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "swift/AST/Type.h"
|
|
#include "swift/AST/TypeLoc.h"
|
|
|
|
namespace swift {
|
|
class ASTContext;
|
|
class ExprHandle;
|
|
|
|
/// PatternKind - The classification of different kinds of
|
|
/// value-matching pattern.
|
|
enum class PatternKind {
|
|
#define PATTERN(ID, PARENT) ID,
|
|
#include "PatternNodes.def"
|
|
};
|
|
|
|
/// Pattern - Base class for all patterns in Swift.
|
|
class alignas(8) Pattern {
|
|
class PatternBitfields {
|
|
friend class Pattern;
|
|
unsigned Kind : 8;
|
|
};
|
|
enum { NumPatternBits = 8 };
|
|
enum { NumBitsAllocated = 32 };
|
|
|
|
class TuplePatternBitfields {
|
|
friend class TuplePattern;
|
|
unsigned : NumPatternBits;
|
|
unsigned NumFields : NumBitsAllocated - NumPatternBits;
|
|
};
|
|
|
|
protected:
|
|
union {
|
|
PatternBitfields PatternBits;
|
|
TuplePatternBitfields TuplePatternBits;
|
|
};
|
|
|
|
Pattern(PatternKind kind) {
|
|
PatternBits.Kind = unsigned(kind);
|
|
}
|
|
|
|
private:
|
|
/// The checked type of the pattern.
|
|
Type Ty;
|
|
|
|
public:
|
|
PatternKind getKind() const { return PatternKind(PatternBits.Kind); }
|
|
|
|
Pattern *getSemanticsProvidingPattern();
|
|
const Pattern *getSemanticsProvidingPattern() const {
|
|
return const_cast<Pattern*>(this)->getSemanticsProvidingPattern();
|
|
}
|
|
|
|
/// Returns whether this pattern has been type-checked yet.
|
|
bool hasType() const { return !Ty.isNull(); }
|
|
|
|
/// If thie pattern has been type-checked, return the type it
|
|
/// matches.
|
|
Type getType() const { assert(hasType()); return Ty; }
|
|
|
|
/// Set the type of this pattern, given that it was previously not
|
|
/// type-checked.
|
|
void setType(Type ty);
|
|
|
|
/// Overwrite the type of this pattern.
|
|
void overwriteType(Type ty) { assert(hasType()); Ty = ty; }
|
|
|
|
/// Returns the name directly bound by this pattern, or the null
|
|
/// identifier if the pattern does not bind a name directly.
|
|
Identifier getBoundName() const;
|
|
|
|
SourceRange getSourceRange() const;
|
|
SourceLoc getStartLoc() const { return getSourceRange().Start; }
|
|
SourceLoc getEndLoc() const { return getSourceRange().End; }
|
|
SourceLoc getLoc() const;
|
|
|
|
/// \brief Collect the set of variables referenced in the given pattern.
|
|
void collectVariables(SmallVectorImpl<VarDecl *> &variables) const;
|
|
|
|
Pattern *clone(ASTContext &context) const;
|
|
|
|
static bool classof(const Pattern *P) { return true; }
|
|
|
|
//*** Allocation Routines ************************************************/
|
|
|
|
void *operator new(size_t bytes, ASTContext &C);
|
|
|
|
// Make placement new and vanilla new/delete illegal for Patterns.
|
|
void *operator new(size_t bytes) = delete;
|
|
void operator delete(void *data) = delete;
|
|
void *operator new(size_t bytes, void *data) = delete;
|
|
|
|
void print(llvm::raw_ostream &OS) const;
|
|
void dump() const;
|
|
};
|
|
|
|
/// A pattern consisting solely of grouping parentheses around a
|
|
/// different pattern.
|
|
class ParenPattern : public Pattern {
|
|
SourceLoc LPLoc, RPLoc;
|
|
Pattern *SubPattern;
|
|
public:
|
|
ParenPattern(SourceLoc lp, Pattern *sub, SourceLoc rp)
|
|
: Pattern(PatternKind::Paren),
|
|
LPLoc(lp), RPLoc(rp), SubPattern(sub) {}
|
|
|
|
Pattern *getSubPattern() const { return SubPattern; }
|
|
|
|
SourceLoc getLParenLoc() const { return LPLoc; }
|
|
SourceLoc getRParenLoc() const { return RPLoc; }
|
|
SourceRange getSourceRange() const { return SourceRange(LPLoc, RPLoc); }
|
|
SourceLoc getLoc() const { return SubPattern->getLoc(); }
|
|
|
|
static bool classof(const Pattern *P) {
|
|
return P->getKind() == PatternKind::Paren;
|
|
}
|
|
};
|
|
|
|
/// An element of a tuple pattern.
|
|
class TuplePatternElt {
|
|
Pattern *ThePattern;
|
|
|
|
// FIXME: Init and VarargBaseType can be collapsed into one field.
|
|
ExprHandle *Init;
|
|
Type VarargBaseType;
|
|
|
|
public:
|
|
TuplePatternElt() = default;
|
|
explicit TuplePatternElt(Pattern *P, ExprHandle *init = nullptr,
|
|
Type varargBaseType = Type())
|
|
: ThePattern(P), Init(init), VarargBaseType(varargBaseType) {}
|
|
|
|
Pattern *getPattern() const { return ThePattern; }
|
|
ExprHandle *getInit() const { return Init; }
|
|
bool isVararg() const { return !VarargBaseType.isNull(); }
|
|
Type getVarargBaseType() const { return VarargBaseType; }
|
|
void setVarargBaseType(Type ty) { VarargBaseType = ty; }
|
|
|
|
/// \brief Revert this variadic tuple pattern element to a
|
|
/// non-variadic version.
|
|
///
|
|
/// Used for error recovery, when we've detected that the element
|
|
/// is not the last one.
|
|
void revertToNonVariadic();
|
|
};
|
|
|
|
/// A pattern consisting of a tuple of patterns.
|
|
class TuplePattern : public Pattern {
|
|
SourceLoc LPLoc, RPLoc;
|
|
// TuplePatternBits.NumFields
|
|
|
|
TuplePatternElt *getFieldsBuffer() {
|
|
return reinterpret_cast<TuplePatternElt *>(this+1);
|
|
}
|
|
const TuplePatternElt *getFieldsBuffer() const {
|
|
return reinterpret_cast<const TuplePatternElt *>(this + 1);
|
|
}
|
|
|
|
TuplePattern(SourceLoc lp, unsigned numFields, SourceLoc rp)
|
|
: Pattern(PatternKind::Tuple), LPLoc(lp), RPLoc(rp) {
|
|
TuplePatternBits.NumFields = numFields;
|
|
}
|
|
|
|
public:
|
|
static TuplePattern *create(ASTContext &C, SourceLoc lp,
|
|
ArrayRef<TuplePatternElt> elements,
|
|
SourceLoc rp);
|
|
|
|
/// \brief Create either a tuple pattern or a paren pattern, depending
|
|
/// on the elements.
|
|
static Pattern *createSimple(ASTContext &C, SourceLoc lp,
|
|
ArrayRef<TuplePatternElt> elements,
|
|
SourceLoc rp);
|
|
|
|
unsigned getNumFields() const {
|
|
return TuplePatternBits.NumFields;
|
|
}
|
|
|
|
MutableArrayRef<TuplePatternElt> getFields() {
|
|
return MutableArrayRef<TuplePatternElt>(getFieldsBuffer(),
|
|
getNumFields());
|
|
}
|
|
ArrayRef<TuplePatternElt> getFields() const {
|
|
return ArrayRef<TuplePatternElt>(getFieldsBuffer(), getNumFields());
|
|
}
|
|
|
|
SourceLoc getLParenLoc() const { return LPLoc; }
|
|
SourceLoc getRParenLoc() const { return RPLoc; }
|
|
SourceRange getSourceRange() const { return SourceRange(LPLoc, RPLoc); }
|
|
SourceLoc getLoc() const { return LPLoc; }
|
|
|
|
static bool classof(const Pattern *P) {
|
|
return P->getKind() == PatternKind::Tuple;
|
|
}
|
|
};
|
|
|
|
/// A pattern which binds a name to an arbitrary value of its type.
|
|
class NamedPattern : public Pattern {
|
|
VarDecl *const Var;
|
|
|
|
public:
|
|
NamedPattern(VarDecl *var) : Pattern(PatternKind::Named), Var(var) {}
|
|
|
|
VarDecl *getDecl() const { return Var; }
|
|
Identifier getBoundName() const { return Var->getName(); }
|
|
|
|
SourceLoc getLoc() const { return Var->getLoc(); }
|
|
SourceRange getSourceRange() const { return getLoc(); }
|
|
|
|
static bool classof(const Pattern *P) {
|
|
return P->getKind() == PatternKind::Named;
|
|
}
|
|
};
|
|
|
|
/// A pattern which matches an arbitrary value of a type, but does not
|
|
/// bind a name to it. This is spelled "_".
|
|
class AnyPattern : public Pattern {
|
|
SourceLoc Loc;
|
|
|
|
public:
|
|
AnyPattern(SourceLoc loc) : Pattern(PatternKind::Any), Loc(loc) {}
|
|
|
|
SourceLoc getLoc() const { return Loc; }
|
|
SourceRange getSourceRange() const { return Loc; }
|
|
|
|
static bool classof(const Pattern *P) {
|
|
return P->getKind() == PatternKind::Any;
|
|
}
|
|
};
|
|
|
|
/// A pattern which matches a sub-pattern and annotates it with a
|
|
/// type.
|
|
class TypedPattern : public Pattern {
|
|
Pattern *SubPattern;
|
|
TypeLoc PatType;
|
|
|
|
public:
|
|
TypedPattern(Pattern *pattern, TypeLoc tl)
|
|
: Pattern(PatternKind::Typed), SubPattern(pattern), PatType(tl) {}
|
|
|
|
Pattern *getSubPattern() const { return SubPattern; }
|
|
TypeLoc &getTypeLoc() { return PatType; }
|
|
TypeLoc getTypeLoc() const { return PatType; }
|
|
|
|
SourceLoc getLoc() const { return SubPattern->getLoc(); }
|
|
SourceRange getSourceRange() const;
|
|
|
|
static bool classof(const Pattern *P) {
|
|
return P->getKind() == PatternKind::Typed;
|
|
}
|
|
};
|
|
|
|
inline Pattern *Pattern::getSemanticsProvidingPattern() {
|
|
if (ParenPattern *pp = dyn_cast<ParenPattern>(this))
|
|
return pp->getSubPattern()->getSemanticsProvidingPattern();
|
|
if (TypedPattern *tp = dyn_cast<TypedPattern>(this))
|
|
return tp->getSubPattern()->getSemanticsProvidingPattern();
|
|
return this;
|
|
}
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|