From a08e68e0ec8f4fa9861e162a9aeee88ff11c41a0 Mon Sep 17 00:00:00 2001 From: emlai Date: Tue, 24 Oct 2017 02:45:03 +0300 Subject: [PATCH] Implement lambda with explicit param types and single-expr body Change llvm::StringMap to std::unordered_map and llvm::SmallVector to std::vector for better debuggability. --- src/ast/ast-printer.cpp | 25 ++++-- src/ast/expr.cpp | 111 ++++++++++++++++++++------- src/ast/expr.h | 26 ++++++- src/irgen/irgen-expr.cpp | 19 +++++ src/irgen/irgen.cpp | 2 + src/irgen/irgen.h | 10 ++- src/parser/parse.cpp | 49 +++++++++--- src/sema/typecheck-expr.cpp | 15 +++- src/sema/typecheck.cpp | 17 ++-- src/sema/typecheck.h | 2 + test/irgen/lambda-noncapturing.delta | 17 ++++ test/stdlib/array/array-tests.delta | 14 +--- 12 files changed, 236 insertions(+), 71 deletions(-) create mode 100644 test/irgen/lambda-noncapturing.delta diff --git a/src/ast/ast-printer.cpp b/src/ast/ast-printer.cpp index d1aad524..95562bc8 100644 --- a/src/ast/ast-printer.cpp +++ b/src/ast/ast-printer.cpp @@ -26,6 +26,17 @@ std::ostream& operator<<(std::ostream& out, const Expr& expr); std::ostream& operator<<(std::ostream& out, const Stmt& stmt); std::ostream& operator<<(std::ostream& out, const Decl& decl); +std::ostream& operator<<(std::ostream& out, llvm::ArrayRef params) { + out << "("; + + for (const ParamDecl& param : params) { + out << param; + if (¶m != ¶ms.back()) out << " "; + } + + return out << ")"; +} + std::ostream& operator<<(std::ostream& out, const VarExpr& expr) { return out << expr.getIdentifier(); } @@ -102,6 +113,10 @@ std::ostream& operator<<(std::ostream& out, const UnwrapExpr& expr) { return out << "(unwrap " << expr.getOperand() << ")"; } +std::ostream& operator<<(std::ostream& out, const LambdaExpr& expr) { + return out << "(lambda " << expr.getParams() << " " << *expr.getBody() << ")"; +} + std::ostream& operator<<(std::ostream& out, const Expr& expr) { switch (expr.getKind()) { case ExprKind::VarExpr: return out << llvm::cast(expr); @@ -121,6 +136,7 @@ std::ostream& operator<<(std::ostream& out, const Expr& expr) { case ExprKind::MemberExpr: return out << llvm::cast(expr); case ExprKind::SubscriptExpr: return out << llvm::cast(expr); case ExprKind::UnwrapExpr: return out << llvm::cast(expr); + case ExprKind::LambdaExpr: return out << llvm::cast(expr); } llvm_unreachable("all cases handled"); } @@ -243,14 +259,7 @@ std::ostream& operator<<(std::ostream& out, const ParamDecl& decl) { std::ostream& operator<<(std::ostream& out, const FunctionDecl& decl) { out << br << (decl.isExtern() ? "(extern-function-decl " : "(function-decl "); delta::operator<<(out, decl.getName()); - - out << " ("; - for (const ParamDecl& param : decl.getParams()) { - out << param; - if (¶m != &decl.getParams().back()) out << " "; - } - out << ") " << decl.getReturnType(); - + out << " " << decl.getParams() << " " << decl.getReturnType(); if (!decl.isExtern()) out << decl.getBody(); return out << ")"; } diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp index bb9b605c..7bc3f697 100644 --- a/src/ast/expr.cpp +++ b/src/ast/expr.cpp @@ -15,6 +15,7 @@ bool Expr::isLvalue() const { case ExprKind::IntLiteralExpr: case ExprKind::FloatLiteralExpr: case ExprKind::SizeofExpr: case ExprKind::BoolLiteralExpr: case ExprKind::CastExpr: case ExprKind::UnwrapExpr: case ExprKind::NullLiteralExpr: case ExprKind::BinaryExpr: case ExprKind::CallExpr: + case ExprKind::LambdaExpr: return false; case ExprKind::PrefixExpr: return llvm::cast(this)->getOperator() == STAR; @@ -38,6 +39,8 @@ void Expr::setMoved(bool moved) { } std::unique_ptr Expr::instantiate(const llvm::StringMap& genericArgs) const { + std::unique_ptr instantiation; + switch (getKind()) { case ExprKind::VarExpr: { auto* varExpr = llvm::cast(this); @@ -50,60 +53,72 @@ std::unique_ptr Expr::instantiate(const llvm::StringMap& genericArgs identifier = varExpr->getIdentifier(); } - return llvm::make_unique(std::move(identifier), varExpr->getLocation()); + instantiation = llvm::make_unique(std::move(identifier), varExpr->getLocation()); + llvm::cast(*instantiation).setDecl(varExpr->getDecl()); + break; } case ExprKind::StringLiteralExpr: { auto* stringLiteralExpr = llvm::cast(this); - return llvm::make_unique(stringLiteralExpr->getValue(), - stringLiteralExpr->getLocation()); + instantiation = llvm::make_unique(stringLiteralExpr->getValue(), + stringLiteralExpr->getLocation()); + break; } case ExprKind::CharacterLiteralExpr: { auto* characterLiteralExpr = llvm::cast(this); - return llvm::make_unique(characterLiteralExpr->getValue(), - characterLiteralExpr->getLocation()); + instantiation = llvm::make_unique(characterLiteralExpr->getValue(), + characterLiteralExpr->getLocation()); + break; } case ExprKind::IntLiteralExpr: { auto* intLiteralExpr = llvm::cast(this); - return llvm::make_unique(intLiteralExpr->getValue(), - intLiteralExpr->getLocation()); + instantiation = llvm::make_unique(intLiteralExpr->getValue(), + intLiteralExpr->getLocation()); + break; } case ExprKind::FloatLiteralExpr: { auto* floatLiteralExpr = llvm::cast(this); - return llvm::make_unique(floatLiteralExpr->getValue(), - floatLiteralExpr->getLocation()); + instantiation = llvm::make_unique(floatLiteralExpr->getValue(), + floatLiteralExpr->getLocation()); + break; } case ExprKind::BoolLiteralExpr: { auto* boolLiteralExpr = llvm::cast(this); - return llvm::make_unique(boolLiteralExpr->getValue(), - boolLiteralExpr->getLocation()); + instantiation = llvm::make_unique(boolLiteralExpr->getValue(), + boolLiteralExpr->getLocation()); + break; } case ExprKind::NullLiteralExpr: { auto* nullLiteralExpr = llvm::cast(this); - return llvm::make_unique(nullLiteralExpr->getLocation()); + instantiation = llvm::make_unique(nullLiteralExpr->getLocation()); + break; } case ExprKind::ArrayLiteralExpr: { auto* arrayLiteralExpr = llvm::cast(this); auto elements = ::instantiate(arrayLiteralExpr->getElements(), genericArgs); - return llvm::make_unique(std::move(elements), - arrayLiteralExpr->getLocation()); + instantiation = llvm::make_unique(std::move(elements), + arrayLiteralExpr->getLocation()); + break; } case ExprKind::TupleExpr: { auto* tupleExpr = llvm::cast(this); auto elements = ::instantiate(tupleExpr->getElements(), genericArgs); - return llvm::make_unique(std::move(elements), tupleExpr->getLocation()); + instantiation = llvm::make_unique(std::move(elements), tupleExpr->getLocation()); + break; } case ExprKind::PrefixExpr: { auto* prefixExpr = llvm::cast(this); auto operand = prefixExpr->getOperand().instantiate(genericArgs); - return llvm::make_unique(prefixExpr->getOperator(), std::move(operand), - prefixExpr->getLocation()); + instantiation = llvm::make_unique(prefixExpr->getOperator(), std::move(operand), + prefixExpr->getLocation()); + break; } case ExprKind::BinaryExpr: { auto* binaryExpr = llvm::cast(this); auto lhs = binaryExpr->getLHS().instantiate(genericArgs); auto rhs = binaryExpr->getRHS().instantiate(genericArgs); - return llvm::make_unique(binaryExpr->getOperator(), std::move(lhs), - std::move(rhs), binaryExpr->getLocation()); + instantiation = llvm::make_unique(binaryExpr->getOperator(), std::move(lhs), + std::move(rhs), binaryExpr->getLocation()); + break; } case ExprKind::CallExpr: { auto* callExpr = llvm::cast(this); @@ -114,40 +129,64 @@ std::unique_ptr Expr::instantiate(const llvm::StringMap& genericArgs auto callGenericArgs = map(callExpr->getGenericArgs(), [&](Type type) { return type.resolve(genericArgs); }); - return llvm::make_unique(std::move(callee), std::move(args), - std::move(callGenericArgs), callExpr->getLocation()); + instantiation = llvm::make_unique(std::move(callee), std::move(args), + std::move(callGenericArgs), + callExpr->getLocation()); + llvm::cast(*instantiation).setCalleeDecl(callExpr->getCalleeDecl()); + break; } case ExprKind::CastExpr: { auto* castExpr = llvm::cast(this); auto targetType = castExpr->getTargetType().resolve(genericArgs); auto expr = castExpr->getExpr().instantiate(genericArgs); - return llvm::make_unique(targetType, std::move(expr), castExpr->getLocation()); + instantiation = llvm::make_unique(targetType, std::move(expr), + castExpr->getLocation()); + break; } case ExprKind::SizeofExpr: { auto* sizeofExpr = llvm::cast(this); auto type = sizeofExpr->getType().resolve(genericArgs); - return llvm::make_unique(type, sizeofExpr->getLocation()); + instantiation = llvm::make_unique(type, sizeofExpr->getLocation()); + break; } case ExprKind::MemberExpr: { auto* memberExpr = llvm::cast(this); auto base = memberExpr->getBaseExpr()->instantiate(genericArgs); - return llvm::make_unique(std::move(base), memberExpr->getMemberName(), - memberExpr->getLocation()); + instantiation = llvm::make_unique(std::move(base), memberExpr->getMemberName(), + memberExpr->getLocation()); + break; } case ExprKind::SubscriptExpr: { auto* subscriptExpr = llvm::cast(this); auto base = subscriptExpr->getBaseExpr()->instantiate(genericArgs); auto index = subscriptExpr->getIndexExpr()->instantiate(genericArgs); - return llvm::make_unique(std::move(base), std::move(index), - subscriptExpr->getLocation()); + instantiation = llvm::make_unique(std::move(base), std::move(index), + subscriptExpr->getLocation()); + break; } case ExprKind::UnwrapExpr: { auto* unwrapExpr = llvm::cast(this); auto operand = unwrapExpr->getOperand().instantiate(genericArgs); - return llvm::make_unique(std::move(operand), unwrapExpr->getLocation()); + instantiation = llvm::make_unique(std::move(operand), unwrapExpr->getLocation()); + break; + } + case ExprKind::LambdaExpr: { + auto* lambdaExpr = llvm::cast(this); + auto params = map(lambdaExpr->getParams(), [&](const ParamDecl& p) { + return ParamDecl(p.getType().resolve(genericArgs), p.getName(), p.getLocation()); + }); + auto body = lambdaExpr->getBody()->instantiate(genericArgs); + instantiation = llvm::make_unique(std::move(params), std::move(body), + lambdaExpr->getLocation()); + break; } } - llvm_unreachable("all cases handled"); + + if (hasType()) { + instantiation->setType(getType()); + } + + return instantiation; } llvm::StringRef CallExpr::getFunctionName() const { @@ -177,3 +216,17 @@ bool BinaryExpr::isBuiltinOp() const { if (op == DOTDOT || op == DOTDOTDOT) return false; return getLHS().getType().isBuiltinType() && getRHS().getType().isBuiltinType(); } + +std::unique_ptr LambdaExpr::lower(Module& module) const { + static uint64_t nameCounter = 0; + + FunctionProto proto("__lambda" + std::to_string(nameCounter++), std::vector(params), + body->getType(), false, false); + auto functionDecl = llvm::make_unique(std::move(proto), std::vector(), + module, getLocation()); + std::vector> body; + auto returnValue = getBody()->instantiate({}); + body.push_back(llvm::make_unique(std::move(returnValue), getBody()->getLocation())); + functionDecl->setBody(std::move(body)); + return functionDecl; +} diff --git a/src/ast/expr.h b/src/ast/expr.h index ee98b0a6..5f863d9f 100644 --- a/src/ast/expr.h +++ b/src/ast/expr.h @@ -12,6 +12,8 @@ namespace delta { class Decl; +class FunctionDecl; +class Module; enum class ExprKind { VarExpr, @@ -31,6 +33,7 @@ enum class ExprKind { MemberExpr, SubscriptExpr, UnwrapExpr, + LambdaExpr }; class Expr { @@ -54,9 +57,11 @@ class Expr { bool isMemberExpr() const { return getKind() == ExprKind::MemberExpr; } bool isSubscriptExpr() const { return getKind() == ExprKind::SubscriptExpr; } bool isUnwrapExpr() const { return getKind() == ExprKind::UnwrapExpr; } + bool isLambdaExpr() const { return getKind() == ExprKind::LambdaExpr; } ExprKind getKind() const { return kind; } - Type getType() const { return type; } + bool hasType() const { return type.get() != nullptr; } + Type getType() const { ASSERT(type); return type; } void setType(Type type) { ASSERT(type); this->type = type; } bool isLvalue() const; bool isRvalue() const { return !isLvalue(); } @@ -326,7 +331,7 @@ class SubscriptExpr : public CallExpr { }; /// A postfix expression that unwraps an optional (nullable) value, yielding the value wrapped by -// the optional, for example 'foo!'. If the optional is null, the operation triggers an assertion +/// the optional, for example 'foo!'. If the optional is null, the operation triggers an assertion /// error (by default), or causes undefined behavior (in unchecked mode). class UnwrapExpr : public Expr { public: @@ -339,4 +344,21 @@ class UnwrapExpr : public Expr { std::unique_ptr operand; }; +class LambdaExpr : public Expr { +public: + LambdaExpr(std::vector&& params, std::unique_ptr body, + SourceLocation location) + : Expr(ExprKind::LambdaExpr, location), params(std::move(params)), + body(std::move(body)) {} + llvm::ArrayRef getParams() const { return params; } + llvm::MutableArrayRef getParams() { return params; } + Expr* getBody() const { return body.get(); } + std::unique_ptr lower(Module& module) const; + static bool classof(const Expr* e) { return e->getKind() == ExprKind::LambdaExpr; } + +private: + std::vector params; + std::unique_ptr body; +}; + } diff --git a/src/irgen/irgen-expr.cpp b/src/irgen/irgen-expr.cpp index 6bf98f9e..c5ee4fd7 100644 --- a/src/irgen/irgen-expr.cpp +++ b/src/irgen/irgen-expr.cpp @@ -475,6 +475,23 @@ llvm::Value* IRGenerator::codegenUnwrapExpr(const UnwrapExpr& expr) { return codegenExpr(expr.getOperand()); } +llvm::Value* IRGenerator::codegenLambdaExpr(const LambdaExpr& expr) { + auto functionDecl = expr.lower(*currentDecl->getModule()); + + auto insertBlockBackup = builder.GetInsertBlock(); + auto insertPointBackup = builder.GetInsertPoint(); + auto scopesBackup = std::move(scopes); + + codegenFunctionDecl(*functionDecl); + + scopes = std::move(scopesBackup); + if (insertBlockBackup) builder.SetInsertPoint(insertBlockBackup, insertPointBackup); + + VarExpr varExpr(functionDecl->getName(), functionDecl->getLocation()); + varExpr.setDecl(functionDecl.get()); + return codegenVarExpr(varExpr); +} + llvm::Value* IRGenerator::codegenExpr(const Expr& expr) { switch (expr.getKind()) { case ExprKind::VarExpr: return codegenVarExpr(llvm::cast(expr)); @@ -494,6 +511,7 @@ llvm::Value* IRGenerator::codegenExpr(const Expr& expr) { case ExprKind::MemberExpr: return codegenMemberExpr(llvm::cast(expr)); case ExprKind::SubscriptExpr: return codegenSubscriptExpr(llvm::cast(expr)); case ExprKind::UnwrapExpr: return codegenUnwrapExpr(llvm::cast(expr)); + case ExprKind::LambdaExpr: return codegenLambdaExpr(llvm::cast(expr)); } llvm_unreachable("all cases handled"); } @@ -517,6 +535,7 @@ llvm::Value* IRGenerator::codegenLvalueExpr(const Expr& expr) { case ExprKind::MemberExpr: return codegenLvalueMemberExpr(llvm::cast(expr)); case ExprKind::SubscriptExpr: return codegenLvalueSubscriptExpr(llvm::cast(expr)); case ExprKind::UnwrapExpr: return codegenUnwrapExpr(llvm::cast(expr)); + case ExprKind::LambdaExpr: return codegenLambdaExpr(llvm::cast(expr)); } llvm_unreachable("all cases handled"); } diff --git a/src/irgen/irgen.cpp b/src/irgen/irgen.cpp index 7109f697..d6d976ba 100644 --- a/src/irgen/irgen.cpp +++ b/src/irgen/irgen.cpp @@ -110,6 +110,8 @@ llvm::Value* IRGenerator::findValue(llvm::StringRef name, const Decl* decl) { return value; } + ASSERT(decl); + switch (decl->getKind()) { case DeclKind::VarDecl: return codegenVarDecl(*llvm::cast(decl)); diff --git a/src/irgen/irgen.h b/src/irgen/irgen.h index a0a26afb..969f099e 100644 --- a/src/irgen/irgen.h +++ b/src/irgen/irgen.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -27,10 +28,10 @@ struct Scope { deinitsToCall.emplace_back(DeferredDeinit{deinit, value, type, decl}); } void addLocalValue(std::string&& name, llvm::Value* value) { - bool didInsert = localValues.try_emplace(std::move(name), value).second; + bool didInsert = localValues.emplace(std::move(name), value).second; ASSERT(didInsert); } - const llvm::StringMap& getLocalValues() const { return localValues; } + const std::unordered_map& getLocalValues() const { return localValues; } void onScopeEnd(); void clear(); @@ -44,7 +45,7 @@ struct Scope { llvm::SmallVector deferredExprs; llvm::SmallVector deinitsToCall; - llvm::StringMap localValues; + std::unordered_map localValues; IRGenerator* irGenerator; }; @@ -108,6 +109,7 @@ class IRGenerator { llvm::Value* codegenLvalueSubscriptExpr(const SubscriptExpr& expr); llvm::Value* codegenSubscriptExpr(const SubscriptExpr& expr); llvm::Value* codegenUnwrapExpr(const UnwrapExpr& expr); + llvm::Value* codegenLambdaExpr(const LambdaExpr& expr); llvm::Value* codegenLvalueExpr(const Expr& expr); void codegenDeferredExprsAndDeinitCallsForReturn(); @@ -162,7 +164,7 @@ class IRGenerator { private: llvm::Optional currentTypeChecker; - llvm::SmallVector scopes; + std::vector scopes; llvm::IRBuilder<> builder; llvm::Module module; diff --git a/src/parser/parse.cpp b/src/parser/parse.cpp index 48d7fe80..137aa8bd 100644 --- a/src/parser/parse.cpp +++ b/src/parser/parse.cpp @@ -137,6 +137,8 @@ std::vector> parseStmtsUntil(Token end, Decl* parent); std::vector> parseStmtsUntilOneOf(Token end1, Token end2, Token end3, Decl* parent); Type parseType(); std::unique_ptr parseTypeDecl(std::vector* genericParams); +std::vector parseParamList(bool* isVariadic, bool withTypes); +ParamDecl parseParam(bool withType); /// argument-list ::= '(' ')' | '(' nonempty-argument-list ')' /// nonempty-argument-list ::= argument | nonempty-argument-list ',' argument @@ -458,6 +460,22 @@ std::unique_ptr parseCallExpr(std::unique_ptr callee) { std::move(genericArgs), location); } +std::unique_ptr parseLambdaExpr() { + ASSERT(currentToken().is(LPAREN, IDENTIFIER)); + auto location = getCurrentLocation(); + std::vector params; + + if (currentToken() == IDENTIFIER) { + params.push_back(parseParam(true)); + } else { + params = parseParamList(nullptr, true); + } + + parse(RARROW); + auto body = parseExpr(); + return llvm::make_unique(std::move(params), std::move(body), location); +} + /// paren-expr ::= '(' expr ')' std::unique_ptr parseParenExpr() { ASSERT(currentToken() == LPAREN); @@ -478,7 +496,7 @@ bool shouldParseGenericArgumentList() { /// postfix-expr ::= postfix-expr postfix-op | call-expr | variable-expr | string-literal | /// int-literal | float-literal | bool-literal | null-literal | /// paren-expr | array-literal | cast-expr | subscript-expr | member-expr -/// unwrap-expr +/// unwrap-expr | lambda-expr std::unique_ptr parsePostfixExpr() { std::unique_ptr expr; switch (currentToken()) { @@ -501,7 +519,15 @@ std::unique_ptr parsePostfixExpr() { case TRUE: case FALSE: expr = parseBoolLiteral(); break; case NULL_LITERAL: expr = parseNullLiteral(); break; case THIS: expr = parseThis(); break; - case LPAREN: expr = parseParenExpr(); break; + case LPAREN: + if (lookAhead(1) == RPAREN && lookAhead(2) == RARROW) { + expr = parseLambdaExpr(); + } else if (lookAhead(1) == IDENTIFIER && lookAhead(2) == COLON) { + expr = parseLambdaExpr(); + } else { + expr = parseParenExpr(); + } + break; case LBRACKET: expr = parseArrayLiteral(); break; case CAST: expr = parseCastExpr(); break; case SIZEOF: expr = parseSizeofExpr(); break; @@ -865,17 +891,22 @@ std::vector> parseStmtsUntilOneOf(Token end1, Token end2, } /// param-decl ::= id ':' type -ParamDecl parseParam() { +ParamDecl parseParam(bool withType) { auto name = parse(IDENTIFIER); - parse(COLON); - auto type = parseType(); + Type type; + + if (withType) { + parse(COLON); + type = parseType(); + } + return ParamDecl(std::move(type), std::move(name.getString()), name.getLocation()); } /// param-list ::= '(' params ')' /// params ::= '' | non-empty-params /// non-empty-params ::= param-decl | param-decl ',' non-empty-params -std::vector parseParamList(bool* isVariadic) { +std::vector parseParamList(bool* isVariadic, bool withTypes) { parse(LPAREN); std::vector params; while (currentToken() != RPAREN) { @@ -884,7 +915,7 @@ std::vector parseParamList(bool* isVariadic) { *isVariadic = true; break; } - params.emplace_back(parseParam()); + params.emplace_back(parseParam(withTypes)); if (currentToken() != RPAREN) parse(COMMA); } parse(RPAREN); @@ -942,7 +973,7 @@ std::unique_ptr parseFunctionProto(bool isExtern, TypeDecl* receiv } bool isVariadic = false; - auto params = parseParamList(isExtern ? &isVariadic : nullptr); + auto params = parseParamList(isExtern ? &isVariadic : nullptr, true); Type returnType = Type::getVoid(); if (currentToken() == RARROW) { @@ -1012,7 +1043,7 @@ std::unique_ptr parseExternFunctionDecl() { /// init-decl ::= 'init' param-list '{' stmt* '}' std::unique_ptr parseInitDecl(TypeDecl& receiverTypeDecl) { auto initLocation = parse(INIT).getLocation(); - auto params = parseParamList(nullptr); + auto params = parseParamList(nullptr, true); auto decl = llvm::make_unique(receiverTypeDecl, std::move(params), initLocation); parse(LBRACE); decl->setBody(parseStmtsUntil(RBRACE, decl.get())); diff --git a/src/sema/typecheck-expr.cpp b/src/sema/typecheck-expr.cpp index 4340394f..17c2b7bc 100644 --- a/src/sema/typecheck-expr.cpp +++ b/src/sema/typecheck-expr.cpp @@ -29,7 +29,7 @@ static void checkNotMoved(const Decl& decl, const VarExpr& expr) { if (movable->isMoved()) { std::string typeInfo; - if (expr.getType()) { + if (expr.hasType()) { typeInfo = " of type '" + expr.getType().toString() + "'"; } @@ -1166,6 +1166,18 @@ Type TypeChecker::typecheckUnwrapExpr(UnwrapExpr& expr) const { return type.getWrappedType(); } +Type TypeChecker::typecheckLambdaExpr(LambdaExpr& expr) const { + getCurrentModule()->getSymbolTable().pushScope(); + + typecheckParams(expr.getParams()); + auto returnType = typecheckExpr(*expr.getBody()); + + getCurrentModule()->getSymbolTable().popScope(); + + auto paramTypes = map(expr.getParams(), [](const ParamDecl& p) { return p.getType(); }); + return FunctionType::get(returnType, std::move(paramTypes)); +} + Type TypeChecker::typecheckExpr(Expr& expr, bool useIsWriteOnly) const { llvm::Optional type; @@ -1187,6 +1199,7 @@ Type TypeChecker::typecheckExpr(Expr& expr, bool useIsWriteOnly) const { case ExprKind::MemberExpr: type = typecheckMemberExpr(llvm::cast(expr)); break; case ExprKind::SubscriptExpr: type = typecheckSubscriptExpr(llvm::cast(expr)); break; case ExprKind::UnwrapExpr: type = typecheckUnwrapExpr(llvm::cast(expr)); break; + case ExprKind::LambdaExpr: type = typecheckLambdaExpr(llvm::cast(expr)); break; } expr.setType(*type); diff --git a/src/sema/typecheck.cpp b/src/sema/typecheck.cpp index d2bc68f7..de0c953e 100644 --- a/src/sema/typecheck.cpp +++ b/src/sema/typecheck.cpp @@ -362,6 +362,10 @@ void TypeChecker::typecheckParamDecl(ParamDecl& decl) const { error(decl.getLocation(), "redefinition of '", decl.getName(), "'"); } + if (decl.getType().isMutable()) { + error(decl.getLocation(), "parameter types cannot be 'mutable'"); + } + typecheckType(decl.getType(), decl.getLocation()); getCurrentModule()->getSymbolTable().add(decl.getName(), &decl); } @@ -560,6 +564,12 @@ void TypeChecker::typecheckGenericParamDecls(llvm::ArrayRef ge } } +void TypeChecker::typecheckParams(llvm::MutableArrayRef params) const { + for (auto& param : params) { + typecheckParamDecl(param); + } +} + void TypeChecker::typecheckFunctionDecl(FunctionDecl& decl) const { if (decl.isTypechecked()) return; if (decl.isExtern()) return; // TODO: Typecheck parameters and return type of extern functions. @@ -570,12 +580,7 @@ void TypeChecker::typecheckFunctionDecl(FunctionDecl& decl) const { SAVE_STATE(currentFunction); currentFunction = &decl; - for (ParamDecl& param : decl.getParams()) { - if (param.getType().isMutable()) { - error(param.getLocation(), "parameter types cannot be 'mutable'"); - } - typecheckParamDecl(param); - } + typecheckParams(decl.getParams()); typecheckType(decl.getReturnType(), decl.getLocation()); if (decl.getReturnType().isMutable()) error(decl.getLocation(), "return types cannot be 'mutable'"); diff --git a/src/sema/typecheck.h b/src/sema/typecheck.h index a4800330..37fef919 100644 --- a/src/sema/typecheck.h +++ b/src/sema/typecheck.h @@ -60,6 +60,7 @@ class TypeChecker { void postProcess(); private: + void typecheckParams(llvm::MutableArrayRef params) const; void typecheckFunctionDecl(FunctionDecl& decl) const; void typecheckFunctionTemplate(FunctionTemplate& decl) const; void typecheckMemberDecl(Decl& decl) const; @@ -95,6 +96,7 @@ class TypeChecker { Type typecheckMemberExpr(MemberExpr& expr) const; Type typecheckSubscriptExpr(SubscriptExpr& expr) const; Type typecheckUnwrapExpr(UnwrapExpr& expr) const; + Type typecheckLambdaExpr(LambdaExpr& expr) const; bool isInterface(Type type) const; bool hasMethod(TypeDecl& type, FunctionDecl& functionDecl) const; diff --git a/test/irgen/lambda-noncapturing.delta b/test/irgen/lambda-noncapturing.delta new file mode 100644 index 00000000..612a4961 --- /dev/null +++ b/test/irgen/lambda-noncapturing.delta @@ -0,0 +1,17 @@ +// RUN: %delta -print-ir %s | %FileCheck %s + +// CHECK: define void @f(i32 (i32, i32)* %a) +func f(a: (int, int) -> int) { + // CHECK-NEXT: call i32 %a(i32 1, i32 2) + _ = a(1, 2); +} + +// CHECK: define i32 @main() +func main() { + // CHECK-NEXT: call void @f(i32 (i32, i32)* [[LAMBDA:@__lambda[0-9]+]]) + f((a: int, b: int) -> a + b); +} + +// CHECK: define i32 [[LAMBDA]](i32 %a, i32 %b) +// CHECK-NEXT: %1 = add i32 %a, %b +// CHECK-NEXT: ret i32 %1 diff --git a/test/stdlib/array/array-tests.delta b/test/stdlib/array/array-tests.delta index ca3216b5..87e4af12 100644 --- a/test/stdlib/array/array-tests.delta +++ b/test/stdlib/array/array-tests.delta @@ -72,11 +72,6 @@ func testEmpty() { assert(!a.isEmpty(), "The array is now not empty"); } -// TODO: Change 'value' to type 'int' when pointer auto-dereferencing is implemented. -func gt2(value: int*) -> bool { - return *value > 2; -} - func testMap() { var a = Array(); a.push(1); @@ -84,7 +79,7 @@ func testMap() { a.push(3); a.push(4); - let b = a.map(gt2); + let b = a.map((value: int*) -> *value > 2); assert(b.size() == 4, "testMap 1"); assert(*b[0] == false, "testMap 2"); assert(*b[1] == false, "testMap 3"); @@ -92,11 +87,6 @@ func testMap() { assert(*b[3] == true, "testMap 5"); } -// TODO: Change 'value' to type 'int' when pointer auto-dereferencing is implemented. -func even(value: int*) -> bool { - return *value % 2 == 0; -} - func testFilter() { var a = Array(); a.push(1); @@ -104,7 +94,7 @@ func testFilter() { a.push(3); a.push(4); - let b = a.filter(even); + let b = a.filter((value: int*) -> *value % 2 == 0); assert(b.size() == 2, "testFilter 1"); assert(*b[0] == 2, "testFilter 2"); assert(*b[1] == 4, "testFilter 3");