mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Parse a generic parameter list within a function declaration, and
introduce the generic type parameters (which are simply type aliases
for a to-be-determined archetype type) into scope for name
lookup. We can now parse something like
func f<T, U : Range>(x : T, y : U) { }
but there is no semantic analysis or even basic safety checking (yet).
Swift SVN r2197
This commit is contained in:
@@ -47,6 +47,7 @@ namespace swift {
|
|||||||
class Stmt;
|
class Stmt;
|
||||||
class StructType;
|
class StructType;
|
||||||
class TupleType;
|
class TupleType;
|
||||||
|
class ValueDecl;
|
||||||
|
|
||||||
enum class DeclKind {
|
enum class DeclKind {
|
||||||
#define DECL(Id, Parent) Id,
|
#define DECL(Id, Parent) Id,
|
||||||
@@ -142,6 +143,32 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// GenericParam - A parameter to a generic function or type, as declared in
|
||||||
|
/// the list of generic parameters, e.g., the T and U in:
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// func f<T : Range, U>(t : T, u : U) { /* ... */ }
|
||||||
|
/// \endcode
|
||||||
|
class GenericParam {
|
||||||
|
TypeAliasDecl *TypeParam;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Construct a generic parameter from a type parameter.
|
||||||
|
GenericParam(TypeAliasDecl *TypeParam) : TypeParam(TypeParam) { }
|
||||||
|
|
||||||
|
/// getDecl - Retrieve the generic parameter declaration.
|
||||||
|
ValueDecl *getDecl() const {
|
||||||
|
return reinterpret_cast<ValueDecl *>(TypeParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// getAsTypeParam - Retrieve the generic parameter as a type parameter.
|
||||||
|
TypeAliasDecl *getAsTypeParam() const { return TypeParam; }
|
||||||
|
|
||||||
|
/// setDeclContext - Set the declaration context for the generic parameter,
|
||||||
|
/// once it is known.
|
||||||
|
void setDeclContext(DeclContext *DC);
|
||||||
|
};
|
||||||
|
|
||||||
/// ImportDecl - This represents a single import declaration, e.g.:
|
/// ImportDecl - This represents a single import declaration, e.g.:
|
||||||
/// import swift
|
/// import swift
|
||||||
/// import swift.int
|
/// import swift.int
|
||||||
@@ -948,6 +975,9 @@ public:
|
|||||||
static bool classof(const ConstructorDecl *D) { return true; }
|
static bool classof(const ConstructorDecl *D) { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void GenericParam::setDeclContext(DeclContext *DC) {
|
||||||
|
TypeParam->setDeclContext(DC);
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace swift
|
} // end namespace swift
|
||||||
|
|
||||||
|
|||||||
@@ -538,6 +538,17 @@ ERROR(asmname_expected_string_literal,attribute_parsing,none,
|
|||||||
ERROR(asmname_interpolated_string,attribute_parsing,none,
|
ERROR(asmname_interpolated_string,attribute_parsing,none,
|
||||||
"asmname cannot be an interpolated string literal", ())
|
"asmname cannot be an interpolated string literal", ())
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Generics parsing diagnostics
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
ERROR(expected_rangle_generics_param,parsing,none,
|
||||||
|
"expected '>' to complete generic parameter list", ())
|
||||||
|
ERROR(expected_generics_parameter_name,parsing,none,
|
||||||
|
"expected an identifier to name generic parameter", ())
|
||||||
|
ERROR(expected_generics_type_restriction,parsing,none,
|
||||||
|
"expected a type name or protocol composition restricting %0",
|
||||||
|
(Identifier))
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
// Semantic Analysis Diagnostics
|
// Semantic Analysis Diagnostics
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
@@ -107,7 +107,15 @@ namespace swift {
|
|||||||
}
|
}
|
||||||
|
|
||||||
~Optional() { reset(); }
|
~Optional() { reset(); }
|
||||||
|
|
||||||
|
// Create a new object by constructing it in place with the given arguments.
|
||||||
|
template<typename ...ArgTypes>
|
||||||
|
void emplace(ArgTypes &&...Args) {
|
||||||
|
reset();
|
||||||
|
HasValue = true;
|
||||||
|
new (getPointer()) T(std::forward<ArgTypes>(Args)...);
|
||||||
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
if (!HasValue)
|
if (!HasValue)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ add_swift_library(swiftParse
|
|||||||
Parser.h
|
Parser.h
|
||||||
ParseDecl.cpp
|
ParseDecl.cpp
|
||||||
ParseExpr.cpp
|
ParseExpr.cpp
|
||||||
|
ParseGeneric.cpp
|
||||||
ParsePattern.cpp
|
ParsePattern.cpp
|
||||||
ParseStmt.cpp
|
ParseStmt.cpp
|
||||||
ParseType.cpp
|
ParseType.cpp
|
||||||
|
|||||||
@@ -1107,8 +1107,8 @@ Pattern *Parser::buildImplicitThisParameter() {
|
|||||||
/// is true, we parse both productions.
|
/// is true, we parse both productions.
|
||||||
///
|
///
|
||||||
/// decl-func:
|
/// decl-func:
|
||||||
/// 'static'? 'func' attribute-list any-identifier func-signature
|
/// 'static'? 'func' attribute-list any-identifier generic-params?
|
||||||
/// stmt-brace?
|
/// func-signature stmt-brace?
|
||||||
///
|
///
|
||||||
/// NOTE: The caller of this method must ensure that the token sequence is
|
/// NOTE: The caller of this method must ensure that the token sequence is
|
||||||
/// either 'func' or 'static' 'func'.
|
/// either 'func' or 'static' 'func'.
|
||||||
@@ -1136,6 +1136,26 @@ FuncDecl *Parser::parseDeclFunc(bool hasContainerType) {
|
|||||||
if (parseAnyIdentifier(Name, diag::expected_identifier_in_decl, "func"))
|
if (parseAnyIdentifier(Name, diag::expected_identifier_in_decl, "func"))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// Placeholder that may hold a new scope containing the generic parameters,
|
||||||
|
// if there are any.
|
||||||
|
Optional<Scope> GenericsScope(this, /*AllowLookup=*/true);
|
||||||
|
|
||||||
|
// Parse the generic-params, if present.
|
||||||
|
SmallVector<GenericParam, 4> GenericParams;
|
||||||
|
if (startsWithLess(Tok)) {
|
||||||
|
parseGenericParameters(GenericParams);
|
||||||
|
|
||||||
|
// If there were any generic parameters, introduce the new scope to
|
||||||
|
// hold those generic parameters.
|
||||||
|
if (!GenericParams.empty()) {
|
||||||
|
GenericsScope.emplace(this, /*AllowLookup=*/true);
|
||||||
|
|
||||||
|
for (auto Param : GenericParams) {
|
||||||
|
ScopeInfo.addToScope(Param.getDecl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We force first type of a func declaration to be a tuple for consistency.
|
// We force first type of a func declaration to be a tuple for consistency.
|
||||||
if (Tok.isNotAnyLParen()) {
|
if (Tok.isNotAnyLParen()) {
|
||||||
diagnose(Tok, diag::func_decl_without_paren);
|
diagnose(Tok, diag::func_decl_without_paren);
|
||||||
@@ -1143,7 +1163,7 @@ FuncDecl *Parser::parseDeclFunc(bool hasContainerType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SmallVector<Pattern*, 8> Params;
|
SmallVector<Pattern*, 8> Params;
|
||||||
|
|
||||||
// If we're within a container and this isn't a static method, add an
|
// If we're within a container and this isn't a static method, add an
|
||||||
// implicit first pattern to match the container type as an element
|
// implicit first pattern to match the container type as an element
|
||||||
// named 'this'. This turns "(int)->int" on FooTy into "(this :
|
// named 'this'. This turns "(int)->int" on FooTy into "(this :
|
||||||
@@ -1163,9 +1183,15 @@ FuncDecl *Parser::parseDeclFunc(bool hasContainerType) {
|
|||||||
FuncExpr *FE = 0;
|
FuncExpr *FE = 0;
|
||||||
{
|
{
|
||||||
Scope FnBodyScope(this, /*AllowLookup=*/true);
|
Scope FnBodyScope(this, /*AllowLookup=*/true);
|
||||||
|
|
||||||
FE = actOnFuncExprStart(FuncLoc, FuncTy, Params);
|
FE = actOnFuncExprStart(FuncLoc, FuncTy, Params);
|
||||||
|
|
||||||
|
// Now that we have a context, update the generic parameters with that
|
||||||
|
// context.
|
||||||
|
for (auto Param : GenericParams) {
|
||||||
|
Param.setDeclContext(FE);
|
||||||
|
}
|
||||||
|
|
||||||
// Establish the new context.
|
// Establish the new context.
|
||||||
ContextChange CC(*this, FE);
|
ContextChange CC(*this, FE);
|
||||||
|
|
||||||
@@ -1179,10 +1205,10 @@ FuncDecl *Parser::parseDeclFunc(bool hasContainerType) {
|
|||||||
FE = 0; // FIXME: Should do some sort of error recovery here.
|
FE = 0; // FIXME: Should do some sort of error recovery here.
|
||||||
} else {
|
} else {
|
||||||
FE->setBody(Body.get());
|
FE->setBody(Body.get());
|
||||||
|
|
||||||
auto& Captures = ValCaptures.back();
|
auto& Captures = ValCaptures.back();
|
||||||
ValueDecl** CaptureCopy =
|
ValueDecl** CaptureCopy =
|
||||||
Context.AllocateCopy<ValueDecl*>(Captures.begin(), Captures.end());
|
Context.AllocateCopy<ValueDecl*>(Captures.begin(), Captures.end());
|
||||||
FE->setCaptures(llvm::makeArrayRef(CaptureCopy, Captures.size()));
|
FE->setCaptures(llvm::makeArrayRef(CaptureCopy, Captures.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1192,7 +1218,10 @@ FuncDecl *Parser::parseDeclFunc(bool hasContainerType) {
|
|||||||
FE = 0;
|
FE = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exit the scope introduced for the generic parameters, if we're in one.
|
||||||
|
GenericsScope.reset();
|
||||||
|
|
||||||
// Create the decl for the func and add it to the parent scope.
|
// Create the decl for the func and add it to the parent scope.
|
||||||
FuncDecl *FD = new (Context) FuncDecl(StaticLoc, FuncLoc, Name, NameLoc,
|
FuncDecl *FD = new (Context) FuncDecl(StaticLoc, FuncLoc, Name, NameLoc,
|
||||||
FuncTy, FE, CurDeclContext);
|
FuncTy, FE, CurDeclContext);
|
||||||
|
|||||||
104
lib/Parse/ParseGeneric.cpp
Normal file
104
lib/Parse/ParseGeneric.cpp
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
//===--- ParseGeneric.cpp - Swift Language Parser for Generics ------------===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Generic Parsing and AST Building
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#include "Parser.h"
|
||||||
|
#include "swift/AST/Diagnostics.h"
|
||||||
|
#include "swift/Parse/Lexer.h"
|
||||||
|
using namespace swift;
|
||||||
|
|
||||||
|
/// parseGenericParameters - Parse a sequence of generic parameters, e.g.,
|
||||||
|
/// < T : Comparable, U : Container>
|
||||||
|
///
|
||||||
|
/// generic-params:
|
||||||
|
/// '<' generic-param (',' generic-param)? '>'
|
||||||
|
///
|
||||||
|
/// generic-param:
|
||||||
|
/// identifier
|
||||||
|
/// identifier ':' type-identifier
|
||||||
|
/// identifier ':' type-composition
|
||||||
|
bool
|
||||||
|
Parser::parseGenericParameters(SmallVectorImpl<GenericParam> &GenericParams) {
|
||||||
|
// Parse the opening '<'.
|
||||||
|
assert(startsWithLess(Tok) && "Generic parameter list must start with '<'");
|
||||||
|
SourceLoc LAngleLoc = consumeStartingLess();
|
||||||
|
|
||||||
|
// Parse the generic parameter list.
|
||||||
|
bool Invalid = false;
|
||||||
|
while (true) {
|
||||||
|
// Parse the name of the parameter.
|
||||||
|
Identifier Name;
|
||||||
|
SourceLoc NameLoc = Tok.getLoc();
|
||||||
|
if (parseIdentifier(Name, diag::expected_generics_parameter_name)) {
|
||||||
|
Invalid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the ':' followed by a type.
|
||||||
|
SmallVector<Type, 1> Inherited;
|
||||||
|
if (Tok.is(tok::colon)) {
|
||||||
|
(void)consumeToken();
|
||||||
|
Type Ty;
|
||||||
|
TypeLoc *TyLoc = nullptr;
|
||||||
|
if (Tok.getKind() == tok::identifier) {
|
||||||
|
parseTypeIdentifier(Ty, TyLoc);
|
||||||
|
} else if (Tok.getKind() == tok::kw_protocol) {
|
||||||
|
parseTypeComposition(Ty, TyLoc);
|
||||||
|
} else {
|
||||||
|
diagnose(Tok.getLoc(), diag::expected_generics_type_restriction, Name);
|
||||||
|
Invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Ty)
|
||||||
|
Inherited.push_back(Ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Bad location info here
|
||||||
|
TypeAliasDecl *Param
|
||||||
|
= new (Context) TypeAliasDecl(NameLoc, Name, NameLoc, Type(),
|
||||||
|
CurDeclContext,
|
||||||
|
Context.AllocateCopy(Inherited));
|
||||||
|
GenericParams.push_back(Param);
|
||||||
|
|
||||||
|
// Parse the comma, if the list continues.
|
||||||
|
if (Tok.is(tok::comma)) {
|
||||||
|
consumeToken();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the closing '>'.
|
||||||
|
SourceLoc RAngleLoc;
|
||||||
|
if (!startsWithGreater(Tok)) {
|
||||||
|
if (!Invalid) {
|
||||||
|
diagnose(Tok.getLoc(), diag::expected_rangle_generics_param);
|
||||||
|
diagnose(LAngleLoc, diag::opening_angle);
|
||||||
|
|
||||||
|
Invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip until we hit the '>'.
|
||||||
|
skipUntilAnyOperator();
|
||||||
|
if (startsWithGreater(Tok))
|
||||||
|
RAngleLoc = consumeStartingGreater();
|
||||||
|
else
|
||||||
|
RAngleLoc = Tok.getLoc();
|
||||||
|
} else {
|
||||||
|
RAngleLoc = consumeStartingGreater();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Invalid;
|
||||||
|
}
|
||||||
@@ -247,8 +247,7 @@ bool Parser::parseTypeComposition(Type &Result, TypeLoc *&ResultLoc) {
|
|||||||
// Skip until we hit the '>'.
|
// Skip until we hit the '>'.
|
||||||
skipUntilAnyOperator();
|
skipUntilAnyOperator();
|
||||||
if (startsWithGreater(Tok))
|
if (startsWithGreater(Tok))
|
||||||
EndLoc = consumeStartingGreater();
|
EndLoc = consumeStartingGreater();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
EndLoc = consumeStartingGreater();
|
EndLoc = consumeStartingGreater();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,6 +327,10 @@ public:
|
|||||||
NullablePtr<Stmt> parseStmtFor();
|
NullablePtr<Stmt> parseStmtFor();
|
||||||
NullablePtr<Stmt> parseStmtForCStyle(SourceLoc ForLoc);
|
NullablePtr<Stmt> parseStmtForCStyle(SourceLoc ForLoc);
|
||||||
NullablePtr<Stmt> parseStmtForEach(SourceLoc ForLoc);
|
NullablePtr<Stmt> parseStmtForEach(SourceLoc ForLoc);
|
||||||
|
|
||||||
|
//===--------------------------------------------------------------------===//
|
||||||
|
// Generics Parsing
|
||||||
|
bool parseGenericParameters(SmallVectorImpl<GenericParam> &GenericParams);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace swift
|
} // end namespace swift
|
||||||
|
|||||||
11
test/Generics/function_decls.swift
Normal file
11
test/Generics/function_decls.swift
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// RUN: %swift %s -verify
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Generic function declarations
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
func f0<T>(x : Int, y : Int) { }
|
||||||
|
func f1<T : Any>(x : Int, y : Int) { }
|
||||||
|
func f2<T : protocol<Range,Any>>(x : Int, y : Int) { }
|
||||||
|
func f3<T : () -> ()>(x : Int, y : Int) { } // expected-error{{expected a type name or protocol composition restricting 'T'}}
|
||||||
|
func f4<T>(x : T, y : T) { }
|
||||||
Reference in New Issue
Block a user