diff --git a/CMakeLists.txt b/CMakeLists.txt index 1478650b6..7ae24b95e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type") endif() -set(CMAKE_CXX_FLAGS_DEBUG "-g") +set(CMAKE_CXX_FLAGS_DEBUG "-O1 -g") if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-limit-debug-info") endif() diff --git a/codon/parser/ast/stmt.cpp b/codon/parser/ast/stmt.cpp index de8056a14..daac792c2 100644 --- a/codon/parser/ast/stmt.cpp +++ b/codon/parser/ast/stmt.cpp @@ -333,12 +333,14 @@ std::string GlobalStmt::toString(int indent) const { FunctionStmt::FunctionStmt(std::string name, Expr *ret, std::vector args, Stmt *suite, std::vector decorators, bool async) : AcceptorExtend(), Items(std::move(args)), name(std::move(name)), ret(ret), - suite(SuiteStmt::wrap(suite)), decorators(std::move(decorators)), async(async) {} + suite(SuiteStmt::wrap(suite)), decorators(std::move(decorators)), async(async), + nonInferrableGenerics(nullptr) {} FunctionStmt::FunctionStmt(const FunctionStmt &stmt, bool clean) : AcceptorExtend(stmt, clean), Items(ast::clone(stmt.items, clean)), name(stmt.name), ret(ast::clone(stmt.ret, clean)), suite(ast::clone(stmt.suite, clean)), - decorators(ast::clone(stmt.decorators, clean)), async(stmt.async) {} + decorators(ast::clone(stmt.decorators, clean)), async(stmt.async), + nonInferrableGenerics(nullptr) {} std::string FunctionStmt::toString(int indent) const { std::string pad = indent > 0 ? ("\n" + std::string(indent + INDENT_SIZE, ' ')) : " "; std::vector as; @@ -431,8 +433,10 @@ class IdSearchVisitor : public CallbackASTVisitor { /// Check if a function can be called with the given arguments. /// See @c reorderNamedArgs for details. -std::unordered_set FunctionStmt::getNonInferrableGenerics() const { - std::unordered_set nonInferrableGenerics; +const std::unordered_set &FunctionStmt::getNonInferrableGenerics() { + if (nonInferrableGenerics) + return *nonInferrableGenerics; + nonInferrableGenerics = std::make_shared>(); for (const auto &a : items) { if (a.status == Param::Generic && !a.defaultValue) { bool inferrable = false; @@ -444,10 +448,10 @@ std::unordered_set FunctionStmt::getNonInferrableGenerics() const { if (ret && IdSearchVisitor(a.name).transform(ret)) inferrable = true; if (!inferrable) - nonInferrableGenerics.insert(a.name); + nonInferrableGenerics->insert(a.name); } } - return nonInferrableGenerics; + return *nonInferrableGenerics; } ClassStmt::ClassStmt(std::string name, std::vector args, Stmt *suite, diff --git a/codon/parser/ast/stmt.h b/codon/parser/ast/stmt.h index 86692b11d..475cca769 100644 --- a/codon/parser/ast/stmt.h +++ b/codon/parser/ast/stmt.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include #include #include @@ -500,7 +501,11 @@ struct FunctionStmt : public AcceptorExtend, Items { void setDecorators(const std::vector &d) { decorators = d; } bool isAsync() const { return async; } void setAsync() { async = true; } - void addParam(const Param &p) { items.push_back(p); } + void addParam(const Param &p) { + items.push_back(p); + if (nonInferrableGenerics) + nonInferrableGenerics->clear(); + } /// @return a function signature that consists of generics and arguments in a /// S-expression form. @@ -509,7 +514,7 @@ struct FunctionStmt : public AcceptorExtend, Items { size_t getStarArgs() const; size_t getKwStarArgs() const; std::string getDocstr() const; - std::unordered_set getNonInferrableGenerics() const; + const std::unordered_set &getNonInferrableGenerics(); bool hasFunctionAttribute(const std::string &attr) const; ACCEPT(FunctionStmt, ASTVisitor, name, items, ret, suite, decorators, async); @@ -522,6 +527,9 @@ struct FunctionStmt : public AcceptorExtend, Items { bool async; std::string signature; + // Cache non-inferrable generics for speed. + std::shared_ptr> nonInferrableGenerics; + friend struct Cache; }; diff --git a/codon/parser/ast/types/class.cpp b/codon/parser/ast/types/class.cpp index 5fbb297e8..4ab5f75d3 100644 --- a/codon/parser/ast/types/class.cpp +++ b/codon/parser/ast/types/class.cpp @@ -153,11 +153,13 @@ int ClassType::unify(Type *typ, Unification *us) { TypePtr ClassType::generalize(int atLevel) const { std::vector g, hg; + g.reserve(generics.size()); + hg.reserve(hiddenGenerics.size()); for (auto &t : generics) g.push_back(t.generalize(atLevel)); for (auto &t : hiddenGenerics) hg.push_back(t.generalize(atLevel)); - auto c = std::make_shared(cache, name, g, hg); + auto c = std::make_shared(cache, name, std::move(g), std::move(hg)); c->isTuple = isTuple; c->setSrcInfo(getSrcInfo()); return c; @@ -166,11 +168,13 @@ TypePtr ClassType::generalize(int atLevel) const { TypePtr ClassType::instantiate(int atLevel, int *unboundCount, std::unordered_map *cache) const { std::vector g, hg; + g.reserve(generics.size()); + hg.reserve(hiddenGenerics.size()); for (auto &t : generics) g.push_back(t.instantiate(atLevel, unboundCount, cache)); for (auto &t : hiddenGenerics) hg.push_back(t.instantiate(atLevel, unboundCount, cache)); - auto c = std::make_shared(this->cache, name, g, hg); + auto c = std::make_shared(this->cache, name, std::move(g), std::move(hg)); c->isTuple = isTuple; c->setSrcInfo(getSrcInfo()); return c; diff --git a/codon/parser/ast/types/function.cpp b/codon/parser/ast/types/function.cpp index 41511fe7b..f383c14d4 100644 --- a/codon/parser/ast/types/function.cpp +++ b/codon/parser/ast/types/function.cpp @@ -15,6 +15,13 @@ FuncType::FuncType(const ClassType *baseType, FunctionStmt *ast, : ClassType(baseType), ast(ast), funcGenerics(std::move(funcGenerics)), funcParent(std::move(funcParent)) {} +// Instantiation/generalization produce a private temporary base. Take its storage +// instead of copying its generic names and shared pointers into the function type. +FuncType::FuncType(ClassType &&baseType, FunctionStmt *ast, + std::vector funcGenerics, TypePtr funcParent) + : ClassType(std::move(baseType)), ast(ast), funcGenerics(std::move(funcGenerics)), + funcParent(std::move(funcParent)) {} + int FuncType::unify(Type *typ, Unification *us) { if (this == typ) return 0; @@ -43,18 +50,20 @@ int FuncType::unify(Type *typ, Unification *us) { TypePtr FuncType::generalize(int atLevel) const { std::vector fg; + fg.reserve(funcGenerics.size()); for (auto &t : funcGenerics) fg.push_back(t.generalize(atLevel)); auto p = funcParent ? funcParent->generalize(atLevel) : nullptr; auto r = std::static_pointer_cast(this->ClassType::generalize(atLevel)); - auto t = std::make_shared(r->getClass(), ast, fg, p); + auto t = std::make_shared(std::move(*r), ast, std::move(fg), std::move(p)); return t; } TypePtr FuncType::instantiate(int atLevel, int *unboundCount, std::unordered_map *cache) const { std::vector fg; + fg.reserve(funcGenerics.size()); for (auto &t : funcGenerics) { fg.push_back(t.instantiate(atLevel, unboundCount, cache)); if (cache && fg.back().type) { @@ -65,7 +74,7 @@ TypePtr FuncType::instantiate(int atLevel, int *unboundCount, auto p = funcParent ? funcParent->instantiate(atLevel, unboundCount, cache) : nullptr; auto r = std::static_pointer_cast( this->ClassType::instantiate(atLevel, unboundCount, cache)); - auto t = std::make_shared(r->getClass(), ast, fg, p); + auto t = std::make_shared(std::move(*r), ast, std::move(fg), std::move(p)); return t; } diff --git a/codon/parser/ast/types/function.h b/codon/parser/ast/types/function.h index c0105e062..5bb9d7ad6 100644 --- a/codon/parser/ast/types/function.h +++ b/codon/parser/ast/types/function.h @@ -33,6 +33,8 @@ struct FuncType : public ClassType { const ClassType *baseType, FunctionStmt *ast, std::vector funcGenerics = std::vector(), TypePtr funcParent = nullptr); + FuncType(ClassType &&baseType, FunctionStmt *ast, + std::vector funcGenerics, TypePtr funcParent); public: int unify(Type *typ, Unification *undo) override; diff --git a/codon/parser/visitors/typecheck/call.cpp b/codon/parser/visitors/typecheck/call.cpp index 4f61b4e10..e8b5f8044 100644 --- a/codon/parser/visitors/typecheck/call.cpp +++ b/codon/parser/visitors/typecheck/call.cpp @@ -725,7 +725,7 @@ Expr *TypecheckVisitor::callReorderArguments(FuncType *calleeFn, CallExpr *expr, typeArgs.size() == calleeFn->funcGenerics.size()), "bad vector sizes"); if (!calleeFn->funcGenerics.empty()) { - auto niGenerics = calleeFn->ast->getNonInferrableGenerics(); + const auto &niGenerics = calleeFn->ast->getNonInferrableGenerics(); for (size_t si = 0; !expr->hasAttribute(Attr::ExprOrderedCall) && si < calleeFn->funcGenerics.size(); si++) { diff --git a/codon/parser/visitors/typecheck/typecheck.cpp b/codon/parser/visitors/typecheck/typecheck.cpp index 5f52eb3ea..b5dc7adef 100644 --- a/codon/parser/visitors/typecheck/typecheck.cpp +++ b/codon/parser/visitors/typecheck/typecheck.cpp @@ -487,7 +487,7 @@ int TypecheckVisitor::canCall(types::FuncType *fn, const std::vector &a } std::vector> reordered; - auto niGenerics = fn->ast->getNonInferrableGenerics(); + const auto &niGenerics = fn->ast->getNonInferrableGenerics(); auto score = reorderNamedArgs( fn, args, [&](int s, int k, const std::vector> &slots, bool _) { @@ -611,8 +611,9 @@ TypecheckVisitor::canWrapExpr(Type *exprType, Type *expectedType, FuncType *call bool allowUnwrap, bool isEllipsis) { auto expectedClass = expectedType->getClass(); auto exprClass = exprType->getClass(); - auto doArgWrap = !callee || !callee->ast->hasFunctionAttribute(getMangledFunc( - "std.internal.attributes", "no_argument_wrap")); + static const auto noArgumentWrap = + getMangledFunc("std.internal.attributes", "no_argument_wrap"); + auto doArgWrap = !callee || !callee->ast->hasFunctionAttribute(noArgumentWrap); if (!doArgWrap) return {true, expectedType ? expectedType->shared_from_this() : nullptr, nullptr}; @@ -1019,10 +1020,11 @@ TypecheckVisitor::extractNamedTuple(Expr *expr) { std::vector TypecheckVisitor::getClassFields(types::ClassType *t) const { - auto f = getClass(t->name)->fields; + // Tuple has MAX_TUPLE fields; copy only the requested prefix, not the whole table. + const auto &f = getClass(t->name)->fields; if (t->is(TYPE_TUPLE)) - f = std::vector(f.begin(), - f.begin() + t->generics.size()); + return std::vector(f.begin(), + f.begin() + t->generics.size()); return f; }