Convert generic-requirement-list to SyntaxCollection, implement function-declaration

This mostly wraps up the first cut of function-declaration.

https://bugs.swift.org/browse/SR-4043
This commit is contained in:
David Farler
2017-03-02 17:01:18 -08:00
parent ceb3babbc6
commit bb4253e3d3
8 changed files with 234 additions and 102 deletions

View File

@@ -19,6 +19,7 @@
#define SWIFT_SYNTAX_GENERICSYNTAX_H
#include "swift/Syntax/References.h"
#include "swift/Syntax/SyntaxCollection.h"
#include "swift/Syntax/SyntaxData.h"
#include "swift/Syntax/TokenSyntax.h"
@@ -30,10 +31,50 @@ class TypeSyntaxData;
class TypeIdentifierSyntax;
class TypeIdentifierSyntaxData;
#pragma mark - generic-requirement Data
class GenericRequirementSyntaxData : public SyntaxData {
friend class GenericRequirementSyntax;
friend class SyntaxData;
protected:
GenericRequirementSyntaxData(const RC<RawSyntax> Raw,
const SyntaxData *Parent = nullptr,
const CursorIndex IndexInParent = 0)
: SyntaxData(Raw, Parent, IndexInParent) {}
public:
static bool classof(const SyntaxData *SD) {
return SD->getKind() == SyntaxKind::ConformanceRequirement ||
SD->getKind() == SyntaxKind::SameTypeRequirement;
}
};
#pragma mark - generic-requirement API
class GenericRequirementSyntax : public Syntax {
friend class Syntax;
friend class SyntaxData;
friend class GenericRequirementSyntaxData;
public:
using DataType = GenericRequirementSyntaxData;
GenericRequirementSyntax(const RC<SyntaxData> Root, const DataType *Data)
: Syntax(Root, Data) {}
static bool classof(const Syntax *S) {
return S->getKind() == SyntaxKind::ConformanceRequirement ||
S->getKind() == SyntaxKind::SameTypeRequirement;
}
};
#pragma mark - conformance-requirement Data
class ConformanceRequirementSyntaxData final : public SyntaxData {
class ConformanceRequirementSyntaxData final
: public GenericRequirementSyntaxData {
friend class SyntaxData;
RC<TypeIdentifierSyntaxData> CachedConformingTypeIdentifier;
RC<TypeSyntaxData> InheritedType;
@@ -44,18 +85,24 @@ class ConformanceRequirementSyntaxData final : public SyntaxData {
make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
CursorIndex IndexInParent = 0);
static RC<ConformanceRequirementSyntaxData> makeBlank();
public:
static bool classof(const SyntaxData *S) {
return S->getKind() == SyntaxKind::ConformanceRequirement;
}
static bool classof(const GenericRequirementSyntaxData *SD) {
return SD->getKind() == SyntaxKind::ConformanceRequirement;
}
};
#pragma mark - conformance-requirement API
/// conformance-requirement -> type-identifier : type-identifier
class ConformanceRequirementSyntax final : public Syntax {
class ConformanceRequirementSyntax final : public GenericRequirementSyntax {
friend class ConformanceRequirementSyntaxData;
friend class SyntaxData;
friend class Syntax;
enum Cursor : CursorIndex {
LeftTypeIdentifier,
@@ -73,6 +120,8 @@ class ConformanceRequirementSyntax final : public Syntax {
static ConformanceRequirementSyntax makeBlank();
public:
using DataType = ConformanceRequirementSyntaxData;
/// Return the conforming "left-hand" type identifier in the
/// conformance requirement.
TypeIdentifierSyntax getConformingTypeIdentifier() const;
@@ -99,13 +148,18 @@ public:
static bool classof(const Syntax *S) {
return S->getKind() == SyntaxKind::ConformanceRequirement;
}
static bool classof(const GenericRequirementSyntax *S) {
return S->getKind() == SyntaxKind::ConformanceRequirement;
}
};
#pragma mark - same-type-requirement Data
class SameTypeRequirementSyntaxData final : public SyntaxData {
class SameTypeRequirementSyntaxData final
: public GenericRequirementSyntaxData {
friend struct SyntaxFactory;
friend class SyntaxData;
RC<TypeIdentifierSyntaxData> CachedLeftTypeIdentifier;
RC<TypeSyntaxData> CachedRightType;
@@ -129,8 +183,9 @@ static bool classof(const SyntaxData *S) {
/// same-type-requirement -> type-identifier == type
class SameTypeRequirementSyntax final : public Syntax {
friend struct SyntaxFactory;
friend class Syntax;
friend class SyntaxData;
friend class SameTypeRequirementSyntaxData;
enum Cursor : CursorIndex {
LeftTypeIdentifier,
EqualityToken,
@@ -141,6 +196,7 @@ class SameTypeRequirementSyntax final : public Syntax {
const SameTypeRequirementSyntaxData *Data);
public:
using DataType = SameTypeRequirementSyntaxData;
/// Return the type identifier on the left side of the same-type requirement.
TypeIdentifierSyntax getLeftTypeIdentifier() const;
@@ -480,6 +536,35 @@ public:
}
};
#pragma mark - generic-requirement-list Data
using GenericRequirementListSyntaxData =
SyntaxCollectionData<SyntaxKind::GenericRequirementList,
GenericRequirementSyntax>;
#pragma mark - generic-requirement-list API
/// requirement-list -> requirement | requirement ',' requirement-list
///
/// requirement -> conformance-requirement | same-type-requirement
class GenericRequirementListSyntax final
: public SyntaxCollection<SyntaxKind::GenericRequirementList,
GenericRequirementSyntax> {
friend struct SyntaxFactory;
friend class Syntax;
friend class SyntaxData;
using DataType = GenericRequirementListSyntaxData;
GenericRequirementListSyntax(const RC<SyntaxData> Root,
const DataType *Data)
: SyntaxCollection(Root, Data) {}
public:
static bool classof(const Syntax *S) {
return S->getKind() == SyntaxKind::GenericRequirementList;
}
};
#pragma mark - generic-argument-clause Builder
class GenericArgumentClauseBuilder {
@@ -502,47 +587,6 @@ public:
GenericArgumentClauseSyntax build() const;
};
#pragma mark - generic-requirement-list Data
class GenericRequirementListSyntaxData final : public SyntaxData {
friend class SyntaxData;
GenericRequirementListSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent = nullptr,
CursorIndex IndexInParent = 0);
static RC<GenericRequirementListSyntaxData>
make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
CursorIndex IndexInParent = 0);
static RC<GenericRequirementListSyntaxData> makeBlank();
public:
static bool classof(const SyntaxData *S) {
return S->getKind() == SyntaxKind::GenericRequirementList;
}
};
#pragma mark - generic-requirement-list API
/// requirement-list -> requirement | requirement ',' requirement-list
///
/// requirement -> conformance-requirement | same-type-requirement
class GenericRequirementListSyntax final : public Syntax {
friend struct SyntaxFactory;
GenericRequirementListSyntax(RC<SyntaxData> Root,
GenericRequirementListSyntaxData *Data);
static GenericRequirementListSyntax make(RC<RawSyntax> Raw);
static GenericRequirementListSyntax makeBlank();
public:
// TODO: getRequirement(unsigned n) const;
// TODO: withAddedRequirement(llvm::Optional<RC<TokenSyntax>> MaybeComma,
// GenericRequirementSyntax NewRequirement) const;
static bool classof(const Syntax *S) {
return S->getKind() == SyntaxKind::GenericRequirementList;
}
};
#pragma mark - generic-where-clause Data
class GenericWhereClauseSyntaxData final : public SyntaxData {
@@ -551,12 +595,12 @@ class GenericWhereClauseSyntaxData final : public SyntaxData {
RC<GenericRequirementListSyntaxData> CachedRequirementList;
GenericWhereClauseSyntaxData(RC<RawSyntax> Raw,
GenericWhereClauseSyntaxData(const RC<RawSyntax> Raw,
const SyntaxData *Parent = nullptr,
CursorIndex IndexInParent = 0);
static RC<GenericWhereClauseSyntaxData> make(RC<RawSyntax> Raw,
const SyntaxData *Parent = nullptr,
CursorIndex IndexInParent = 0);
const CursorIndex IndexInParent = 0);
static RC<GenericWhereClauseSyntaxData>
make(const RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
const CursorIndex IndexInParent = 0);
static RC<GenericWhereClauseSyntaxData> makeBlank();
public:
@@ -570,12 +614,16 @@ public:
/// generic-where-clause -> 'where' requirement-list
class GenericWhereClauseSyntax final : public Syntax {
friend struct SyntaxFactory;
friend class Syntax;
friend class SyntaxData;
friend class GenericWhereClauseSyntaxData;
enum class Cursor : CursorIndex {
WhereToken,
WhereKeyword,
RequirementList,
};
using DataType = GenericWhereClauseSyntaxData;
GenericWhereClauseSyntax(RC<SyntaxData> Root,
const GenericWhereClauseSyntaxData *Data);

View File

@@ -52,7 +52,6 @@ class Syntax {
friend class SyntaxData;
friend class LegacyASTTransformer;
friend class sema::Semantics;
using DataType = SyntaxData;
#define SYNTAX(Id, Parent) friend class Id##Syntax;
#include "swift/Syntax/SyntaxKinds.def"
@@ -75,6 +74,8 @@ protected:
}
public:
using DataType = SyntaxData;
Syntax(const RC<SyntaxData> Root, const SyntaxData *Data);
/// Get the kind of syntax.

View File

@@ -101,6 +101,7 @@ struct SyntaxFactory {
RC<TokenSyntax> Identifier,
llvm::Optional<GenericParameterClauseSyntax> GenericParams,
FunctionSignatureSyntax Signature,
llvm::Optional<GenericWhereClauseSyntax> GenericWhereClause,
llvm::Optional<CodeBlockStmtSyntax> Body);
/// Make a function declaration with all missing elements.
@@ -594,6 +595,14 @@ struct SyntaxFactory {
makeSameTypeRequirement(TypeIdentifierSyntax LeftTypeIdentifier,
RC<TokenSyntax> EqualityToken, TypeSyntax RightType);
/// Make a list of generic requirements with the given loosely collected
/// requirements/
static GenericRequirementListSyntax makeGenericRequirementList(
std::vector<GenericRequirementSyntax> &Requirements);
/// Make an empty list of generic requirements.
static GenericRequirementListSyntax makeBlankGenericRequirementList();
/// Make a same-type requirement with all elements marked as missing.
static SameTypeRequirementSyntax makeBlankSameTypeRequirement();

View File

@@ -53,8 +53,9 @@ SYNTAX(GenericWhereClause, Syntax)
SYNTAX(GenericRequirementList, Syntax)
SYNTAX(GenericArgumentClause, Syntax)
SYNTAX(GenericArgumentList, Syntax)
SYNTAX(ConformanceRequirement, Syntax)
SYNTAX(SameTypeRequirement, Syntax)
ABSTRACT_SYNTAX(GenericRequirementSyntax, Syntax)
SYNTAX(ConformanceRequirement, GenericRequirementSyntax)
SYNTAX(SameTypeRequirement, GenericRequirementSyntax)
SYNTAX(TypeArgumentList, Syntax)
// Types

View File

@@ -44,8 +44,18 @@ DeclModifierSyntaxData(const RC<RawSyntax> Raw,
: SyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::DeclModifier);
assert(Raw->Layout.size() == 4);
syntax_assert_child_token(Raw, DeclModifierSyntax::Cursor::Name,
tok::identifier);
#ifndef NDEBUG
auto Name =
cast<TokenSyntax>(Raw->getChild(DeclModifierSyntax::Cursor::Name));
auto Kind = Name->getTokenKind();
assert(Kind == tok::kw_class ||
Kind == tok::kw_static ||
Kind == tok::identifier ||
Kind == tok::kw_public ||
Kind == tok::kw_private ||
Kind == tok::kw_fileprivate ||
Kind == tok::kw_internal);
#endif
syntax_assert_child_token_text(Raw, DeclModifierSyntax::Cursor::LeftParen,
tok::l_paren, "(");
syntax_assert_child_token(Raw, DeclModifierSyntax::Cursor::Argument,

View File

@@ -27,7 +27,7 @@ ConformanceRequirementSyntaxData::
ConformanceRequirementSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: SyntaxData(Raw, Parent, IndexInParent) {
: GenericRequirementSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::ConformanceRequirement);
syntax_assert_child_kind(Raw,
ConformanceRequirementSyntax::Cursor::LeftTypeIdentifier,
@@ -226,52 +226,24 @@ GenericParameterClauseSyntax GenericParameterClauseBuilder::build() const {
return { Data, Data.get() };
}
#pragma mark - generic-requirement-list Data
GenericRequirementListSyntaxData::
GenericRequirementListSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent,
CursorIndex IndexInParent)
: SyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::GenericRequirementList);
}
RC<GenericRequirementListSyntaxData>
GenericRequirementListSyntaxData::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<GenericRequirementListSyntaxData> {
new GenericRequirementListSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<GenericRequirementListSyntaxData>
GenericRequirementListSyntaxData::makeBlank() {
auto Raw = RawSyntax::make(SyntaxKind::GenericRequirementList,
{},
SourcePresence::Present);
return make(Raw);
}
#pragma mark - generic-where-clause Data
GenericWhereClauseSyntaxData::
GenericWhereClauseSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent,
CursorIndex IndexInParent)
GenericWhereClauseSyntaxData(const RC<RawSyntax> Raw, const SyntaxData *Parent,
const CursorIndex IndexInParent)
: SyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::GenericWhereClause);
syntax_assert_child_token_text(Raw,
GenericWhereClauseSyntax::Cursor::WhereToken, tok::kw_where, "where");
GenericWhereClauseSyntax::Cursor::WhereKeyword, tok::kw_where, "where");
syntax_assert_child_kind(Raw,
GenericWhereClauseSyntax::Cursor::RequirementList,
SyntaxKind::GenericRequirementList);
}
RC<GenericWhereClauseSyntaxData>
GenericWhereClauseSyntaxData::make(RC<RawSyntax> Raw,
GenericWhereClauseSyntaxData::make(const RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
const CursorIndex IndexInParent) {
return RC<GenericWhereClauseSyntaxData> {
new GenericWhereClauseSyntaxData { Raw, Parent, IndexInParent }
};
@@ -293,20 +265,34 @@ GenericWhereClauseSyntax(RC<SyntaxData> Root,
const GenericWhereClauseSyntaxData *Data)
: Syntax(Root, Data) {}
GenericWhereClauseSyntax GenericWhereClauseSyntax::
withWhereKeyword(RC<TokenSyntax> NewWhereKeyword) const {
syntax_assert_token_is(NewWhereKeyword, tok::kw_where, "where");
return Data->replaceChild<GenericWhereClauseSyntax>(NewWhereKeyword,
Cursor::WhereKeyword);
}
GenericWhereClauseSyntax GenericWhereClauseSyntax::
withRequirementList(GenericRequirementListSyntax NewRequirements) const {
return Data->replaceChild<GenericWhereClauseSyntax>(NewRequirements.getRaw(),
Cursor::RequirementList);
}
#pragma mark - same-type-requirement Data
SameTypeRequirementSyntaxData::
SameTypeRequirementSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: SyntaxData(Raw, Parent, IndexInParent) {
: GenericRequirementSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::SameTypeRequirement);
assert(Raw->Layout.size() == 3);
syntax_assert_child_kind(Raw,
SameTypeRequirementSyntax::Cursor::LeftTypeIdentifier,
SyntaxKind::TypeIdentifier);
syntax_assert_child_token_text(Raw,
SameTypeRequirementSyntax::Cursor::EqualityToken, tok::identifier, "==");
SameTypeRequirementSyntax::Cursor::EqualityToken,
tok::oper_binary_spaced, "==");
assert(Raw->getChild(SameTypeRequirementSyntax::Cursor::RightType)->isType());
}

View File

@@ -221,6 +221,44 @@ FunctionSignatureSyntax SyntaxFactory::makeBlankFunctionSignature() {
return { Data, Data.get() };
}
#pragma mark - function-declaration
FunctionDeclSyntax SyntaxFactory::
makeFunctionDecl(TypeAttributesSyntax Attributes,
DeclModifierListSyntax Modifiers,
RC<TokenSyntax> FuncKeyword,
RC<TokenSyntax> Identifier,
llvm::Optional<GenericParameterClauseSyntax> GenericParams,
FunctionSignatureSyntax Signature,
llvm::Optional<GenericWhereClauseSyntax> GenericWhereClause,
llvm::Optional<CodeBlockStmtSyntax> Body) {
auto Raw = RawSyntax::make(SyntaxKind::FunctionDecl,
{
Attributes.getRaw(),
Modifiers.getRaw(),
FuncKeyword,
Identifier,
GenericParams.hasValue()
? GenericParams.getValue().getRaw()
: SyntaxFactory::makeBlankGenericParameterClause().getRaw(),
Signature.getRaw(),
GenericWhereClause.hasValue()
? GenericWhereClause.getValue().getRaw()
: SyntaxFactory::makeBlankGenericWhereClause().getRaw(),
Body.hasValue()
? Body.getValue().getRaw()
: SyntaxFactory::makeBlankCodeBlock().getRaw()
},
SourcePresence::Present);
auto Data = FunctionDeclSyntaxData::make(Raw);
return { Data, Data.get() };
}
FunctionDeclSyntax SyntaxFactory::makeBlankFunctionDecl() {
auto Data = FunctionDeclSyntaxData::makeBlank();
return { Data, Data.get() };
}
#pragma mark - Statements
CodeBlockStmtSyntax
@@ -851,6 +889,23 @@ SameTypeRequirementSyntax SyntaxFactory::makeBlankSameTypeRequirement() {
return SameTypeRequirementSyntax { Data, Data.get() };
}
GenericRequirementListSyntax SyntaxFactory::
makeGenericRequirementList(std::vector<GenericRequirementSyntax> &Requirements){
RawSyntax::LayoutList Layout;
for (auto Req : Requirements) {
Layout.push_back(Req.getRaw());
}
auto Raw = RawSyntax::make(SyntaxKind::GenericRequirementList, Layout,
SourcePresence::Present);
auto Data = GenericRequirementListSyntaxData::make(Raw);
return { Data, Data.get() };
}
GenericRequirementListSyntax SyntaxFactory::makeBlankGenericRequirementList() {
auto Data = GenericRequirementListSyntaxData::makeBlank();
return { Data, Data.get() };
}
#pragma mark - Operators
/// Make a prefix operator with the given text.

View File

@@ -84,8 +84,7 @@ TEST(DeclSyntaxTests, TypealiasMakeAPIs) {
auto ElementParam =
SyntaxFactory::makeGenericParameter("Element", {}, {});
auto LeftAngle = SyntaxFactory::makeLeftAngleToken({}, {});
auto RightAngle =
SyntaxFactory::makeRightAngleToken({}, { Trivia::spaces(1) });
auto RightAngle = SyntaxFactory::makeRightAngleToken({}, Trivia::spaces(1));
auto GenericParams = GenericParameterClauseBuilder()
.useLeftAngleBracket(LeftAngle)
.useRightAngleBracket(RightAngle)
@@ -352,7 +351,7 @@ FunctionSignatureSyntax getCannedFunctionSignature() {
auto Throws = SyntaxFactory::makeThrowsKeyword({}, Trivia::spaces(1));
auto Arrow = SyntaxFactory::makeArrow({}, Trivia::spaces(1));
auto NoAttributes = SyntaxFactory::makeBlankTypeAttributes();
auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, {});
auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, Trivia::spaces(1));
return SyntaxFactory::makeFunctionSignature(LParen, List, RParen, Throws,
Arrow, NoAttributes, Int);
@@ -372,7 +371,7 @@ TEST(DeclSyntaxTests, FunctionSignatureMakeAPIs) {
ASSERT_EQ(OS.str().str(),
"(with radius: Int = -1, "
"with radius: Int = -1, "
"with radius: Int = -1, ) throws -> Int");
"with radius: Int = -1, ) throws -> Int ");
}
}
@@ -488,7 +487,7 @@ GenericParameterClauseSyntax getCannedGenericParams() {
GenericParameterClauseBuilder GB;
auto LAngle = SyntaxFactory::makeLeftAngleToken({}, {});
auto RAngle = SyntaxFactory::makeLeftAngleToken({}, Trivia::spaces(1));
auto RAngle = SyntaxFactory::makeRightAngleToken({}, {});
auto T = SyntaxFactory::makeGenericParameter("T", {}, {});
auto U = SyntaxFactory::makeGenericParameter("U", {}, {});
@@ -498,7 +497,7 @@ GenericParameterClauseSyntax getCannedGenericParams() {
GB.addParameter(llvm::None, T);
GB.addParameter(Comma, U);
GB.useLeftAngleBracket(LAngle);
GB.useLeftAngleBracket(RAngle);
GB.useRightAngleBracket(RAngle);
return GB.build();
}
@@ -508,7 +507,7 @@ CodeBlockStmtSyntax getCannedBody() {
auto OneDigits = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
auto One = SyntaxFactory::makeIntegerLiteralExpr(NoSign, OneDigits);
auto ReturnKW =
SyntaxFactory::makeReturnKeyword(Trivia::newlines(1) + Trivia::spaces(1),
SyntaxFactory::makeReturnKeyword(Trivia::newlines(1) + Trivia::spaces(2),
{});
auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, One);
@@ -522,17 +521,35 @@ CodeBlockStmtSyntax getCannedBody() {
return SyntaxFactory::makeCodeBlock(LBrace, Stmts, RBrace);
}
GenericWhereClauseSyntax getCannedWhereClause() {
auto WhereKW = SyntaxFactory::makeWhereKeyword({}, Trivia::spaces(1));
auto T = SyntaxFactory::makeTypeIdentifier("T", {}, Trivia::spaces(1));
auto EqualEqual = SyntaxFactory::makeEqualityOperator({}, Trivia::spaces(1));
auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, Trivia::spaces(1));
auto SameType = SyntaxFactory::makeSameTypeRequirement(T, EqualEqual, Int);
auto Requirements = SyntaxFactory::makeBlankGenericRequirementList()
.appending(SameType.castTo<GenericRequirementSyntax>())
.castTo<GenericRequirementListSyntax>();
return SyntaxFactory::makeBlankGenericWhereClause()
.withWhereKeyword(WhereKW)
.withRequirementList(Requirements);
}
FunctionDeclSyntax getCannedFunctionDecl() {
auto NoAttributes = SyntaxFactory::makeBlankTypeAttributes();
auto Foo = SyntaxFactory::makeIdentifier("foo", {}, {});
auto FuncKW = SyntaxFactory::makeFuncKeyword({}, Trivia::spaces(1));
auto Modifiers = getCannedModifiers();
auto GenericParams = getCannedGenericParams();
auto GenericWhere = getCannedWhereClause();
auto Signature = getCannedFunctionSignature();
auto Body = getCannedBody();
return SyntaxFactory::makeFunctionDecl(NoAttributes, Modifiers, FuncKW, Foo,
GenericParams, Signature, Body);
GenericParams, Signature, GenericWhere,
Body);
}
TEST(DeclSyntaxTests, FunctionDeclMakeAPIs) {
@@ -547,8 +564,13 @@ TEST(DeclSyntaxTests, FunctionDeclMakeAPIs) {
llvm::raw_svector_ostream OS(Scratch);
getCannedFunctionDecl().print(OS);
ASSERT_EQ(OS.str().str(),
"public static func foo(x: Int, y: Int) throws -> Int {\n"
" return 1\n"
"public static func foo<T, U>"
"(with radius: Int = -1, "
"with radius: Int = -1, "
"with radius: Int = -1, ) "
"throws -> Int "
"where T == Int {\n"
" return1\n"
"}");
}
}