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;
}