Revise the language design for function argument clause syntax.

A function argument clause is now one or more patterns (which
must be parenthesized and explicitly type all positions) not
separated by arrows;  the first arrow then separates off the
return type.

Revisions to language reference forthcoming.



Swift SVN r1099
This commit is contained in:
John McCall
2012-01-26 01:25:26 +00:00
parent d93cd143c5
commit 16f8b2e656
19 changed files with 532 additions and 195 deletions

View File

@@ -22,6 +22,7 @@
#include "Decl.h"
#include "Expr.h"
#include "Module.h"
#include "Pattern.h"
#include "Stmt.h"
#include "Types.h"

View File

@@ -195,6 +195,17 @@ ERROR(expected_lbrace_protocol_type,type_parsing,none,
ERROR(expected_protocol_member,type_parsing,none,
"expected a function or variable declaration in protocol", ())
//------------------------------------------------------------------------------
// Pattern parsing diagnostics
//------------------------------------------------------------------------------
ERROR(expected_pattern,pattern_parsing,none,
"expected pattern", ())
ERROR(untyped_pattern_in_function_signature,pattern_parsing,none,
"function parameter must have an explicit type", ())
ERROR(expected_rparen_tuple_pattern_list,pattern_parsing,non,
"expected ')' at end of tuple pattern", ())
//------------------------------------------------------------------------------
// Statement parsing diagnostics
//------------------------------------------------------------------------------
@@ -496,6 +507,21 @@ ERROR(expression_unresolved_function,sema_tcs,none,
ERROR(assignment_lhs_not_lvalue,sema_tcs,none,
"cannot assign to the result of this expression", ())
//------------------------------------------------------------------------------
// Type Check Patterns
//------------------------------------------------------------------------------
ERROR(cannot_infer_type_for_pattern,sema_tcp,none,
"cannot infer a type for this pattern", ())
ERROR(pattern_type_mismatch_context,sema_tcp,none,
"type annotation does not match contextual type %0", (Type))
ERROR(tuple_pattern_in_non_tuple_context,sema_tcp,none,
"tuple pattern cannot match values of the non-tuple type %0", (Type))
ERROR(tuple_pattern_length_mismatch,sema_tcp,none,
"tuple pattern has the wrong length for tuple type %0", (Type))
ERROR(coerced_tuple_pattern_has_init,sema_tcp,none,
"tuple element in pattern cannot have a default initializer", ())
//==============================================================================
// IR Generation Diagnostics
//==============================================================================

View File

@@ -32,6 +32,7 @@ namespace swift {
class ArgDecl;
class ValueDecl;
class Decl;
class Pattern;
class Stmt;
class BraceStmt;
class TypeAliasDecl;
@@ -646,18 +647,34 @@ public:
/// e.g. func(a : int) -> int { return a+1 }
class FuncExpr : public Expr, public DeclContext {
SourceLoc FuncLoc;
unsigned NumPatterns;
BraceStmt *Body;
public:
FuncExpr(SourceLoc FuncLoc, Type FnType, BraceStmt *Body, DeclContext *Parent)
Pattern **getParamsBuffer() {
return reinterpret_cast<Pattern**>(this+1);
}
Pattern * const *getParamsBuffer() const {
return reinterpret_cast<Pattern*const*>(this+1);
}
FuncExpr(SourceLoc FuncLoc, unsigned NumPatterns, Type FnType,
BraceStmt *Body, DeclContext *Parent)
: Expr(ExprKind::Func, TypeJudgement(FnType, ValueKind::RValue)),
DeclContext(DeclContextKind::FuncExpr, Parent),
FuncLoc(FuncLoc), Body(Body) {}
FuncLoc(FuncLoc), NumPatterns(NumPatterns), Body(Body) {}
public:
static FuncExpr *create(ASTContext &Context, SourceLoc FuncLoc,
ArrayRef<Pattern*> Params, Type FnType,
BraceStmt *Body, DeclContext *Parent);
SourceRange getSourceRange() const;
SourceLoc getLoc() const { return FuncLoc; }
ArrayRef<Pattern*> getParamPatterns() const {
return ArrayRef<Pattern*>(getParamsBuffer(), NumPatterns);
}
/// Returns the location of the 'func' keyword.
SourceLoc getFuncLoc() const { return FuncLoc; }

View File

@@ -44,7 +44,7 @@ class Pattern {
class TuplePatternBitfields {
friend class TuplePattern;
unsigned : NumPatternBits;
unsigned NumElements : NumBitsAllocated - NumPatternBits;
unsigned NumFields : NumBitsAllocated - NumPatternBits;
};
protected:
@@ -75,6 +75,10 @@ public:
/// type-checked.
void setType(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; }
@@ -104,12 +108,12 @@ public:
: Pattern(PatternKind::Paren, type),
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 LPLoc; }
Pattern *getSubPattern() const { return SubPattern; }
SourceLoc getLoc() const { return SubPattern->getLoc(); }
static bool classof(const Pattern *P) {
return P->getKind() == PatternKind::Paren;
@@ -117,84 +121,124 @@ public:
static bool classof(const ParenPattern *P) { return true; }
};
/// An element of a tuple pattern.
class TuplePatternElt {
Pattern *ThePattern;
Expr *Init;
public:
TuplePatternElt() = default;
explicit TuplePatternElt(Pattern *P, Expr *init = nullptr)
: ThePattern(P), Init(init) {}
Pattern *getPattern() const { return ThePattern; }
Expr *getInit() const { return Init; }
void setInit(Expr *E) { Init = E; }
};
/// A pattern consisting of a tuple of patterns.
class TuplePattern : public Pattern {
SourceLoc LPLoc, RPLoc;
// TuplePatternBits.NumElements
// TuplePatternBits.NumFields
Pattern **getElementsBuffer() {
return reinterpret_cast<Pattern**>(this+1);
TuplePatternElt *getFieldsBuffer() {
return reinterpret_cast<TuplePatternElt *>(this+1);
}
Pattern * const *getElementsBuffer() const {
return reinterpret_cast<Pattern * const *>(this + 1);
const TuplePatternElt *getFieldsBuffer() const {
return reinterpret_cast<const TuplePatternElt *>(this + 1);
}
TuplePattern(SourceLoc lp, unsigned numElements, SourceLoc rp)
TuplePattern(SourceLoc lp, unsigned numFields, SourceLoc rp)
: Pattern(PatternKind::Tuple), LPLoc(lp), RPLoc(rp) {
TuplePatternBits.NumElements = numElements;
TuplePatternBits.NumFields = numFields;
}
public:
TuplePattern *create(ASTContext &C, SourceLoc lp,
ArrayRef<Pattern*> elements, SourceLoc rp);
static TuplePattern *create(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; }
unsigned getNumElements() const {
return TuplePatternBits.NumElements;
}
ArrayRef<Pattern*> getElements() const {
return ArrayRef<Pattern*>(getElementsBuffer(), getNumElements());
}
static bool classof(const Pattern *P) {
return P->getKind() == PatternKind::Tuple;
}
static bool classof(const TuplePattern *P) { return true; }
};
/// A pattern which binds a top-level name. That is, this pattern
/// binds a name and is not contained within a pattern that also binds
/// a name. It may still be contained within a pattern that does not
/// bind a name.
class VarPattern : public Pattern {
VarDecl *const Var;
/// A pattern which binds a name to an arbitrary value of its type.
class NamedPattern : public Pattern {
ValueDecl *const TheDecl;
public:
VarPattern(VarDecl *var) : Pattern(PatternKind::Var), Var(var) {}
NamedPattern(ValueDecl *D)
: Pattern(PatternKind::Named), TheDecl(D) {}
SourceLoc getLoc() const { return Var->getLocStart(); }
ValueDecl *getDecl() const { return TheDecl; }
Identifier getBoundName() const { return TheDecl->getName(); }
SourceLoc getLoc() const { return TheDecl->getLocStart(); }
SourceRange getSourceRange() const { return getLoc(); }
VarDecl *getDecl() const { return Var; }
static bool classof(const Pattern *P) {
return P->getKind() == PatternKind::Var;
return P->getKind() == PatternKind::Named;
}
static bool classof(const VarPattern *P) { return true; }
static bool classof(const NamedPattern *P) { return true; }
};
/// A pattern which binds a name other than at the top-level.
class ElementRefPattern : public Pattern {
ElementRefDecl *const ElementRef;
/// A pattern which matches an arbitrary value of a type, but does not
/// bind a name to it.
class AnyPattern : public Pattern {
SourceLoc Loc;
public:
ElementRefPattern(ElementRefDecl *elementRef)
: Pattern(PatternKind::ElementRef), ElementRef(elementRef) {}
AnyPattern(SourceLoc loc) : Pattern(PatternKind::Any), Loc(loc) {}
SourceLoc getLoc() const { return ElementRef->getLocStart(); }
SourceRange getSourceRange() const { return getLoc(); }
ElementRefDecl *getDecl() const { return ElementRef; }
SourceLoc getLoc() const { return Loc; }
SourceRange getSourceRange() const { return Loc; }
static bool classof(const Pattern *P) {
return P->getKind() == PatternKind::ElementRef;
return P->getKind() == PatternKind::Any;
}
static bool classof(const ElementRefPattern *P) { return true; }
static bool classof(const AnyPattern *P) { return true; }
};
/// A pattern which matches a sub-pattern and annotates it with a
/// type.
class TypedPattern : public Pattern {
Pattern *SubPattern;
public:
TypedPattern(Pattern *pattern, Type type)
: Pattern(PatternKind::Typed, type), SubPattern(pattern) {}
Pattern *getSubPattern() const { return SubPattern; }
SourceLoc getLoc() const { return SubPattern->getLoc(); }
SourceRange getSourceRange() const {
// FIXME: end location for type!
return SubPattern->getSourceRange();
}
static bool classof(const Pattern *P) {
return P->getKind() == PatternKind::Typed;
}
static bool classof(const TypedPattern *P) { return true; }
};
} // end namespace swift

View File

@@ -23,7 +23,8 @@
PATTERN(Paren, Pattern)
PATTERN(Tuple, Pattern)
PATTERN(Var, Pattern)
PATTERN(ElementRef, Pattern)
PATTERN(Named, Pattern)
PATTERN(Any, Pattern)
PATTERN(Typed, Pattern)
#undef PATTERN

View File

@@ -343,14 +343,10 @@ class TupleTypeElt {
/// value is not specified.
Expr *Init;
/// Arg - The argument declaration formed from this tuple element.
/// This is only meaningful in the parameter clause of a function type.
ArgDecl *Arg;
public:
TupleTypeElt() = default;
TupleTypeElt(Type ty, Identifier name, Expr *init = nullptr)
: Name(name), Ty(ty), Init(init), Arg(nullptr) { }
: Name(name), Ty(ty), Init(init) { }
bool hasName() const { return !Name.empty(); }
Identifier getName() const { return Name; }
@@ -360,9 +356,6 @@ public:
bool hasInit() const { return Init != nullptr; }
Expr *getInit() const { return Init; }
void setInit(Expr *E) { Init = E; }
ArgDecl *getArgDecl() const { return Arg; }
void setArgDecl(ArgDecl *arg) { Arg = arg; }
};
/// TupleType - A tuple is a parenthesized list of types where each name has an

View File

@@ -159,6 +159,18 @@ SourceRange TupleExpr::getSourceRange() const {
return SourceRange(Start, End);
}
FuncExpr *FuncExpr::create(ASTContext &C, SourceLoc funcLoc,
ArrayRef<Pattern*> params, Type fnType,
BraceStmt *body, DeclContext *parent) {
unsigned nParams = params.size();
void *buf = C.Allocate(sizeof(FuncExpr) + nParams * sizeof(Pattern*),
Expr::Alignment);
FuncExpr *fn = ::new(buf) FuncExpr(funcLoc, nParams, fnType, body, parent);
for (unsigned i = 0; i != nParams; ++i)
fn->getParamsBuffer()[i] = params[i];
return fn;
}
SourceRange FuncExpr::getSourceRange() const {
return SourceRange(FuncLoc, Body->getEndLoc());
}
@@ -174,10 +186,11 @@ SourceRange FuncExpr::getSourceRange() const {
/// func(x : int) -> (y : int) -> (int -> int)
/// The body result type is '(int -> int)'.
Type FuncExpr::getBodyResultType() const {
Type ty = cast<FunctionType>(getType())->Result;
while (FunctionType *fn = dyn_cast<FunctionType>(ty)) {
ty = fn->Result;
}
unsigned n = getParamPatterns().size();
Type ty = getType();
do {
ty = cast<FunctionType>(ty)->Result;
} while (--n);
return ty;
}

View File

@@ -74,14 +74,27 @@ void *Pattern::operator new(size_t numBytes, ASTContext &C) throw() {
return C.Allocate(numBytes, Pattern::Alignment);
}
/// 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 {
const Pattern *P = this;
if (const TypedPattern *TP = dyn_cast<TypedPattern>(P))
P = TP->getSubPattern();
if (const NamedPattern *NP = dyn_cast<NamedPattern>(P))
return NP->getBoundName();
return Identifier();
}
/// Allocate a new pattern that matches a tuple.
TuplePattern *TuplePattern::create(ASTContext &C, SourceLoc lp,
ArrayRef<Pattern*> patterns, SourceLoc rp) {
unsigned n = patterns.size();
void *buffer = C.Allocate(sizeof(TuplePattern) + n * sizeof(Pattern*),
ArrayRef<TuplePatternElt> elts,
SourceLoc rp) {
unsigned n = elts.size();
void *buffer = C.Allocate(sizeof(TuplePattern) + n * sizeof(TuplePatternElt),
Pattern::Alignment);
TuplePattern *pattern = ::new(buffer) TuplePattern(lp, n, rp);
for (unsigned i = 0; i != n; ++i)
pattern->getElementsBuffer()[i] = patterns[i];
memcpy(pattern->getFieldsBuffer(), elts.data(), n * sizeof(TuplePatternElt));
return pattern;
}

View File

@@ -52,6 +52,7 @@
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Module.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Optional.h"
@@ -87,6 +88,9 @@ static unsigned getNumCurries(FunctionType *type) {
/// is the number of additional parameter clauses that are uncurried
/// in the function body.
static unsigned getNaturalUncurryLevel(FuncDecl *func) {
if (func->getBody())
return func->getBody()->getParamPatterns().size() - 1;
FunctionType *type = func->getType()->castTo<FunctionType>();
unsigned count = 0;
do {
@@ -805,54 +809,54 @@ static void emitParameter(IRGenFunction &IGF, ArgDecl *param,
/// Emit a specific parameter clause by walking into any literal tuple
/// types and matching
static void emitParameterClause(IRGenFunction &IGF, Type paramType,
static void emitParameterClause(IRGenFunction &IGF, Pattern *param,
Explosion &paramValues) {
// Walk into tuple types.
if (TupleType *tuple = dyn_cast<TupleType>(paramType)) {
for (const TupleTypeElt &field : tuple->Fields) {
// If this element is bound to a name (i.e. has an ArgDecl), load it
// into a variable and map that as as local declaration.
if (ArgDecl *param = field.getArgDecl()) {
emitParameter(IGF, param, paramValues);
// TODO: bind sub-elements when necessary.
switch (param->getKind()) {
// Explode tuple patterns.
case PatternKind::Tuple:
for (auto &field : cast<TuplePattern>(param)->getFields())
emitParameterClause(IGF, field.getPattern(), paramValues);
return;
// Otherwise, recurse on the type in case it's a tuple and
// provides its own ArgDecls.
} else {
emitParameterClause(IGF, field.getType(), paramValues);
}
}
// Look through a couple kinds of patterns.
case PatternKind::Paren:
return emitParameterClause(IGF, cast<ParenPattern>(param)->getSubPattern(),
paramValues);
case PatternKind::Typed:
return emitParameterClause(IGF, cast<TypedPattern>(param)->getSubPattern(),
paramValues);
// Bind names.
case PatternKind::Named:
emitParameter(IGF, cast<ArgDecl>(cast<NamedPattern>(param)->getDecl()),
paramValues);
return;
// Ignore ignored parameters by consuming the right number of values.
case PatternKind::Any: {
ExplosionSchema paramSchema(paramValues.getKind());
IGF.IGM.getExplosionSchema(param->getType(), paramSchema);
paramValues.claim(paramSchema.size());
return;
}
// Look through paren types.
if (ParenType *paren = dyn_cast<ParenType>(paramType)) {
return emitParameterClause(IGF, paren->getUnderlyingType(), paramValues);
}
// Otherwise, we're ignoring this argument, but we still need to
// consume the right number of values.
ExplosionSchema paramSchema(paramValues.getKind());
IGF.IGM.getExplosionSchema(paramType, paramSchema);
paramValues.claim(paramSchema.size());
llvm_unreachable("bad pattern kind!");
}
/// Emit all the parameter clauses of the given function type. This
/// is basically making sure that we have mappings for all the
/// ArgDecls.
static void emitParameterClauses(IRGenFunction &IGF, Type fnType,
unsigned uncurryLevel,
static void emitParameterClauses(IRGenFunction &IGF,
llvm::ArrayRef<Pattern*> params,
Explosion &paramValues) {
// We never uncurry into something that's not written immediately as
// a function type.
FunctionType *fn = cast<FunctionType>(fnType);
assert(!params.empty());
// When uncurrying, later argument clauses are emitted first.
if (uncurryLevel)
emitParameterClauses(IGF, fn->Result, uncurryLevel - 1, paramValues);
if (params.size() != 1)
emitParameterClauses(IGF, params.slice(1), paramValues);
// Finally, emit this clause.
emitParameterClause(IGF, fn->Input, paramValues);
emitParameterClause(IGF, params[0], paramValues);
}
/// Emit the prologue for the function.
@@ -899,7 +903,8 @@ void IRGenFunction::emitPrologue() {
}
// Set up the parameters.
emitParameterClauses(*this, CurFuncExpr->getType(), CurUncurryLevel, values);
auto params = CurFuncExpr->getParamPatterns().slice(0, CurUncurryLevel + 1);
emitParameterClauses(*this, params, values);
// TODO: set up the data pointer.

View File

@@ -17,6 +17,7 @@
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Module.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/Types.h"
#include "llvm/Module.h"
@@ -62,10 +63,15 @@ static bool isTrivialGlobalInit(llvm::Function *fn) {
void IRGenModule::emitTranslationUnit(TranslationUnit *tunit) {
Type emptyTuple = TupleType::getEmpty(Context);
FunctionType *unitToUnit = FunctionType::get(emptyTuple, emptyTuple, Context);
FuncExpr func(SourceLoc(), unitToUnit, nullptr, tunit);
Pattern *params[] = {
TuplePattern::create(Context, SourceLoc(),
llvm::ArrayRef<TuplePatternElt>(), SourceLoc())
};
FuncExpr *func = FuncExpr::create(Context, SourceLoc(), params,
unitToUnit, nullptr, tunit);
llvm::Function *fn = createGlobalInitFunction(*this, tunit);
IRGenFunction(*this, &func, ExplosionKind::Minimal, /*uncurry*/ 0, fn)
IRGenFunction(*this, func, ExplosionKind::Minimal, /*uncurry*/ 0, fn)
.emitGlobalTopLevel(tunit->Body);
// Not all translation units need a global initialization function.

View File

@@ -4,6 +4,7 @@ add_swift_library(swiftParse
Parser.h
ParseDecl.cpp
ParseExpr.cpp
ParsePattern.cpp
ParseResult.h
ParseStmt.cpp
ParseType.cpp

View File

@@ -587,24 +587,26 @@ FuncDecl *Parser::parseDeclFunc(Type ReceiverTy) {
return 0;
}
Type FuncTy;
if (parseType(FuncTy))
return 0;
SmallVector<Pattern*, 8> Params;
// If the parsed type is not spelled as a function type (i.e., has no '->' in
// it), then it is implicitly a function that returns ().
if (!isa<FunctionType>(FuncTy.getPointer()))
FuncTy = FunctionType::get(FuncTy, TupleType::getEmpty(Context), Context);
// If a receiver type was specified and this isn't a plus method, install the
// first type as the receiver, as a tuple with element named 'this'. This
// turns "int->int" on FooTy into "(this : FooTy)->(int->int)".
// If a receiver type was specified and this isn't a plus method,
// add an implicit first pattern to match the receiver type as an
// element named 'this'. This turns "int->int" on FooTy into
// "(this : FooTy)->(int->int)".
if (!ReceiverTy.isNull() && !PlusLoc.isValid()) {
TupleTypeElt ReceiverElt(ReceiverTy, Context.getIdentifier("this"));
FuncTy = FunctionType::get(TupleType::get(ReceiverElt, Context),
FuncTy, Context);
ArgDecl *D =
new (Context) ArgDecl(SourceLoc(), Context.getIdentifier("this"),
ReceiverTy, CurDeclContext);
Pattern *P = new (Context) NamedPattern(D);
P = new (Context) TypedPattern(P, ReceiverTy);
Params.push_back(P);
}
Type FuncTy;
if (parseFunctionSignature(Params, FuncTy))
return 0;
// Enter the arguments for the function into a new function-body scope. We
// need this even if there is no function body to detect argument name
// duplication.
@@ -612,7 +614,7 @@ FuncDecl *Parser::parseDeclFunc(Type ReceiverTy) {
{
Scope FnBodyScope(this);
FE = actOnFuncExprStart(FuncLoc, FuncTy);
FE = actOnFuncExprStart(FuncLoc, FuncTy, Params);
// Establish the new context.
ContextChange CC(*this, FE);
@@ -620,7 +622,7 @@ FuncDecl *Parser::parseDeclFunc(Type ReceiverTy) {
// Then parse the expression.
NullablePtr<Stmt> Body;
// Check to see if we have a "{" which is a brace expr.
// Check to see if we have a "{" to start a brace statement.
if (Tok.is(tok::l_brace)) {
ParseResult<BraceStmt> Body = parseStmtBrace(diag::invalid_diagnostic);
if (Body.isSuccess())
@@ -636,8 +638,8 @@ FuncDecl *Parser::parseDeclFunc(Type ReceiverTy) {
}
// Create the decl for the func and add it to the parent scope.
FuncDecl *FD = new (Context) FuncDecl(PlusLoc, FuncLoc, Name, FuncTy, FE,
CurDeclContext);
FuncDecl *FD = new (Context) FuncDecl(PlusLoc, FuncLoc, Name,
FuncTy, FE, CurDeclContext);
if (Attributes.isValid()) FD->getMutableAttrs() = Attributes;
ScopeInfo.addToScope(FD);
return FD;

View File

@@ -397,24 +397,24 @@ ParseResult<Expr> Parser::parseExprParen() {
ParseResult<Expr> Parser::parseExprFunc() {
SourceLoc FuncLoc = consumeToken(tok::kw_func);
SmallVector<Pattern*, 4> Params;
Type Ty;
if (Tok.is(tok::l_brace)) {
Params.push_back(TuplePattern::create(Context, SourceLoc(),
llvm::ArrayRef<TuplePatternElt>(),
SourceLoc()));
Ty = TupleType::getEmpty(Context);
Ty = FunctionType::get(Ty, Ty, Context);
} else if (!Tok.is(tok::l_paren) && !Tok.is(tok::l_paren_space)) {
diagnose(Tok, diag::func_decl_without_paren);
return true;
} else if (parseType(Ty)) {
} else if (parseFunctionSignature(Params, Ty)) {
return true;
}
// If the parsed type is not spelled as a function type (i.e., has no '->' in
// it), then it is implicitly a function that returns ().
if (!isa<FunctionType>(Ty.getPointer()))
Ty = FunctionType::get(Ty, TupleType::getEmpty(Context), Context);
// The arguments to the func are defined in their own scope.
Scope FuncBodyScope(this);
FuncExpr *FE = actOnFuncExprStart(FuncLoc, Ty);
FuncExpr *FE = actOnFuncExprStart(FuncLoc, Ty, Params);
// Establish the new context.
ContextChange CC(*this, FE);
@@ -431,79 +431,46 @@ ParseResult<Expr> Parser::parseExprFunc() {
}
/// FuncTypePiece - This little enum is used by AddFuncArgumentsToScope to keep
/// track of where in a function type it is currently looking. This affects how
/// the decls are processed and created.
enum class FuncTypePiece {
Function, // Looking at the initial functiontype itself.
Input, // Looking at the input to the function type
Output // Looking at the output to the function type.
};
/// AddFuncArgumentsToScope - Walk the type specified for a Func object (which
/// is known to be a FunctionType on the outer level) creating and adding named
/// arguments to the current scope. This causes redefinition errors to be
/// emitted.
static void AddFuncArgumentsToScope(Type Ty,
FuncTypePiece Mode,
FuncExpr *FE,
Parser &P) {
// Handle the function case first.
if (Mode == FuncTypePiece::Function) {
FunctionType *FT = cast<FunctionType>(Ty);
AddFuncArgumentsToScope(FT->Input, FuncTypePiece::Input, FE, P);
// If this is a->b->c then we treat b as an input, not (b->c) as an output.
if (isa<FunctionType>(FT->Result.getPointer()))
AddFuncArgumentsToScope(FT->Result, FuncTypePiece::Function, FE, P);
else
AddFuncArgumentsToScope(FT->Result, FuncTypePiece::Output, FE, P);
static void AddFuncArgumentsToScope(Pattern *pat, FuncExpr *FE, Parser &P) {
switch (pat->getKind()) {
case PatternKind::Named: {
// Reparent the decl and add it to the scope.
ArgDecl *AD = cast<ArgDecl>(cast<NamedPattern>(pat)->getDecl());
AD->setDeclContext(FE);
P.ScopeInfo.addToScope(AD);
return;
}
// Otherwise, we're looking at an input or output to the func. The only type
// we currently dive into is the humble tuple, which can be recursive. This
// should dive in syntactically.
///
/// Note that we really *do* want dyn_cast here, not getAs, because we do not
/// want to look through type aliases or other sugar, we want to see what the
/// user wrote in the func declaration.
TupleType *TT = dyn_cast<TupleType>(Ty.getPointer());
if (TT == 0) return;
case PatternKind::Any:
return;
// For tuples, recursively processes their elements (to handle cases like:
// (x : (a : int, b : int), y : int) -> ...
// and create decls for any named elements.
for (const TupleTypeElt &Field : TT->Fields) {
AddFuncArgumentsToScope(Field.getType(), Mode, FE, P);
case PatternKind::Paren:
AddFuncArgumentsToScope(cast<ParenPattern>(pat)->getSubPattern(), FE, P);
return;
// If this field is named, create the argument decl for it.
// Otherwise, ignore unnamed fields.
if (!Field.hasName()) continue;
case PatternKind::Typed:
AddFuncArgumentsToScope(cast<TypedPattern>(pat)->getSubPattern(), FE, P);
return;
// Create the argument decl for this named argument.
ArgDecl *AD = new (P.Context) ArgDecl(FE->getFuncLoc(), Field.getName(),
Field.getType(), FE);
// Modify the TupleType in-place. This is okay, as we're
// essentially still processing it.
const_cast<TupleTypeElt&>(Field).setArgDecl(AD);
// Eventually we should mark the input/outputs as readonly vs writeonly.
//bool isInput = Mode == FuncTypePiece::Input;
P.ScopeInfo.addToScope(AD);
case PatternKind::Tuple:
for (const TuplePatternElt &field : cast<TuplePattern>(pat)->getFields())
AddFuncArgumentsToScope(field.getPattern(), FE, P);
return;
}
llvm_unreachable("bad pattern kind!");
}
FuncExpr *Parser::actOnFuncExprStart(SourceLoc FuncLoc, Type FuncTy,
ArrayRef<Pattern*> Params) {
FuncExpr *FE = FuncExpr::create(Context, FuncLoc, Params, FuncTy, 0,
CurDeclContext);
FuncExpr *Parser::actOnFuncExprStart(SourceLoc FuncLoc, Type FuncTy) {
FuncExpr *FE = new (Context) FuncExpr(FuncLoc, FuncTy, 0, CurDeclContext);
AddFuncArgumentsToScope(FuncTy, FuncTypePiece::Function, FE, *this);
for (Pattern *P : Params)
AddFuncArgumentsToScope(P, FE, *this);
return FE;
}

224
lib/Parse/ParsePattern.cpp Normal file
View File

@@ -0,0 +1,224 @@
//===--- ParsePattern.cpp - Swift Language Parser for Patterns ------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Pattern Parsing and AST Building
//
//===----------------------------------------------------------------------===//
#include "Parser.h"
using namespace swift;
/// Check that the given pattern is fully-typed.
static bool checkFullyTyped(Parser &P, Pattern *pattern) {
switch (pattern->getKind()) {
// Any type with an explicit annotation is okay.
case PatternKind::Typed:
return false;
// Paren types depend on their parenthesized pattern.
case PatternKind::Paren: {
Pattern *sub = cast<ParenPattern>(pattern)->getSubPattern();
if (checkFullyTyped(P, sub)) return true;
pattern->setType(sub->getType());
return false;
}
// Tuple types can be built up from their components.
case PatternKind::Tuple: {
TuplePattern *tuple = cast<TuplePattern>(pattern);
SmallVector<TupleTypeElt, 8> typeElts;
typeElts.reserve(tuple->getNumFields());
for (const TuplePatternElt &elt : tuple->getFields()) {
Pattern *subpattern = elt.getPattern();
if (checkFullyTyped(P, subpattern))
return true;
typeElts.push_back(TupleTypeElt(subpattern->getType(),
subpattern->getBoundName(),
elt.getInit()));
}
tuple->setType(TupleType::get(typeElts, P.Context));
return false;
}
// Everything else is uninferrable.
case PatternKind::Named:
case PatternKind::Any:
P.diagnose(pattern->getLoc(), diag::untyped_pattern_in_function_signature)
<< pattern->getSourceRange();
return true;
}
llvm_unreachable("bad pattern kind");
}
/// Parse a function definition signature.
bool Parser::parseFunctionSignature(SmallVectorImpl<Pattern*> &params,
Type &type) {
// Parse curried function argument clauses as long as we can.
bool hasSemaError = false;
do {
ParseResult<Pattern> pattern = parsePatternTuple();
if (pattern.isParseError()) {
return true;
} else if (pattern.isSemaError()) {
hasSemaError = true;
} else {
params.push_back(pattern.get());
}
} while (Tok.is(tok::l_paren) || Tok.is(tok::l_paren_space));
// If there's a trailing arrow, parse the rest as the result type.
if (consumeIf(tok::arrow)) {
if (parseType(type))
return true;
// Otherwise, we implicitly return ().
} else {
type = TupleType::getEmpty(Context);
}
// Now build up the function type. We require all function
// signatures to be fully-typed: that is, all top-down paths to a
// leaf pattern must pass through a TypedPattern.
for (unsigned i = params.size(); i != 0; --i) {
Pattern *param = params[i - 1];
Type paramType;
if (checkFullyTyped(*this, param)) {
// Recover by ignoring everything.
paramType = TupleType::getEmpty(Context);
} else {
paramType = param->getType();
}
type = FunctionType::get(paramType, type, Context);
}
return false;
}
/// Parse a pattern.
/// pattern ::= pattern-atom
/// pattern ::= pattern-atom ':' type
ParseResult<Pattern> Parser::parsePattern() {
// First, parse the pattern atom.
ParseResult<Pattern> pattern = parsePatternAtom();
if (pattern.isParseError()) return true;
// Now parse an optional type annotation.
if (consumeIf(tok::colon)) {
Type type;
if (parseType(type))
return true;
if (!pattern.isSemaError())
pattern = new (Context) TypedPattern(pattern.get(), type);
}
return pattern;
}
/// Parse a pattern "atom", meaning the part that precedes the
/// optional type annotation.
///
/// pattern-atom ::= identifier
/// pattern-atom ::= pattern-tuple
ParseResult<Pattern> Parser::parsePatternAtom() {
switch (Tok.getKind()) {
case tok::l_paren:
case tok::l_paren_space:
return parsePatternTuple();
case tok::identifier: {
SourceLoc loc = Tok.getLoc();
StringRef text = Tok.getText();
consumeToken(tok::identifier);
// '_' is a special case which means 'ignore this'.
if (text == "_") {
return new (Context) AnyPattern(loc);
} else {
Identifier ident = Context.getIdentifier(text);
ArgDecl *arg = new (Context) ArgDecl(loc, ident, Type(), CurDeclContext);
return new (Context) NamedPattern(arg);
}
}
default:
diagnose(Tok, diag::expected_pattern);
return true;
}
}
/// Parse a tuple pattern.
///
/// pattern-tuple:
//// '(' pattern-tuple-body? ')'
/// pattern-tuple-body:
/// pattern-tuple-element (',' pattern-tuple-body)*
/// pattern-tuple-element:
/// pattern ('=' expr)?
ParseResult<Pattern> Parser::parsePatternTuple() {
assert(Tok.is(tok::l_paren) || Tok.is(tok::l_paren_space));
// We're looking at the left parenthesis; consume it.
SourceLoc lp = consumeToken();
// Parse all the elements.
SmallVector<TuplePatternElt, 8> elts;
bool hasSemaError = false;
if (Tok.isNot(tok::r_paren)) {
do {
ParseResult<Pattern> pattern = parsePattern();
Expr *init = nullptr;
if (pattern.isParseError()) {
skipUntil(tok::r_paren);
return true;
} else if (consumeIf(tok::equal)) {
ParseResult<Expr> initR = parseExpr(diag::expected_initializer_expr);
if (initR.isParseError()) {
skipUntil(tok::r_paren);
return true;
} else if (initR.isSemaError()) {
hasSemaError = true;
} else {
init = initR.get();
}
}
if (pattern.isSemaError()) {
hasSemaError = true;
} else {
elts.push_back(TuplePatternElt(pattern.get(), init));
}
} while (consumeIf(tok::comma));
if (Tok.isNot(tok::r_paren)) {
diagnose(Tok, diag::expected_rparen_tuple_pattern_list);
skipUntil(tok::r_paren);
return true;
}
}
// Consume the right parenthesis.
SourceLoc rp = consumeToken(tok::r_paren);
if (hasSemaError)
return ParseResult<Pattern>::getSemaError();
// A pattern which wraps a single anonymous pattern is not a tuple.
if (elts.size() == 1 &&
elts[0].getInit() == nullptr &&
elts[0].getPattern()->getBoundName().empty())
return new (Context) ParenPattern(lp, elts[0].getPattern(), rp);
return TuplePattern::create(Context, lp, elts, rp);
}

View File

@@ -223,6 +223,14 @@ public:
bool parseTypeArray(SourceLoc LSquareLoc, Type &Result);
//===--------------------------------------------------------------------===//
// Pattern Parsing
bool parseFunctionSignature(SmallVectorImpl<Pattern*> &params, Type &type);
ParseResult<Pattern> parsePattern();
ParseResult<Pattern> parsePatternTuple();
ParseResult<Pattern> parsePatternAtom();
//===--------------------------------------------------------------------===//
// Expression Parsing
@@ -238,7 +246,8 @@ public:
ParseResult<Expr> parseExprFunc();
Expr *actOnIdentifierExpr(Identifier Text, SourceLoc Loc);
FuncExpr *actOnFuncExprStart(SourceLoc FuncLoc, Type FuncTy);
FuncExpr *actOnFuncExprStart(SourceLoc FuncLoc, Type FuncTy,
ArrayRef<Pattern*> Patterns);
//===--------------------------------------------------------------------===//
// Statement Parsing

View File

@@ -5,6 +5,7 @@ add_swift_library(swiftSema
TypeCheckCoercion.cpp
TypeCheckExpr.cpp
TypeCheckDecl.cpp
TypeCheckPattern.cpp
TypeCheckStmt.cpp
TypeCheckType.cpp
DEPENDS swiftAST swiftParse)

View File

@@ -1051,3 +1051,15 @@ bool TypeChecker::typeCheckExpression(Expr *&E, Type ConvertType) {
E = 0;
return true;
}
bool TypeChecker::semaFunctionSignature(FuncExpr *FE) {
bool hadError = false;
for (unsigned i = FE->getParamPatterns().size(); i != 0; --i) {
Pattern *pattern = FE->getParamPatterns()[i - 1];
if (typeCheckPattern(pattern)) {
hadError = true;
continue;
}
}
return hadError;
}

View File

@@ -193,7 +193,7 @@ void swift::performTypeChecking(TranslationUnit *TU) {
// Type check the body of each of the FuncExpr in turn.
for (FuncExpr *FE : FuncExprs) {
if (!FE->getBody()) continue;
TC.semaFunctionSignature(FE);
PrettyStackTraceExpr StackEntry(TC.Context, "type-checking", FE);

View File

@@ -36,12 +36,14 @@ public:
bool validateType(ValueDecl *VD);
bool validateType(Type T);
bool semaFunctionSignature(FuncExpr *FE);
bool semaTupleExpr(TupleExpr *TE);
Expr *semaApplyExpr(ApplyExpr *E);
bool typeCheckExpression(Expr *&E, Type ConvertType = Type());
void typeCheckDecl(Decl *D);
bool typeCheckPattern(Pattern *P);
bool convertToType(Pattern *P, Type Ty);
bool bindAndValidateClosureArgs(Expr *Body, Type FuncInput);