mirror of https://github.com/exaloop/codon.git
Fix static bool unification
parent
99973373e0
commit
1fc0655ea7
|
@ -34,9 +34,9 @@ void TypecheckVisitor::visit(IdExpr *expr) {
|
|||
// if (ctx->isOuter(val) && !ctx->isCanonicalName(expr->value))
|
||||
// ctx->getBase()->captures.insert(expr->value);
|
||||
if (!val) {
|
||||
ctx->dump();
|
||||
LOG("=================================================================");
|
||||
ctx->cache->typeCtx->dump();
|
||||
// ctx->dump();
|
||||
// LOG("=================================================================");
|
||||
// ctx->cache->typeCtx->dump();
|
||||
E(Error::ID_NOT_FOUND, expr, expr->value);
|
||||
}
|
||||
if (expr->type->getUnbound() && in(ctx->cache->overloads, val->canonicalName))
|
||||
|
|
|
@ -153,14 +153,18 @@ StmtPtr TypecheckVisitor::transformAssignment(AssignStmt *stmt, bool mustExist)
|
|||
auto type = assign->lhs->getType();
|
||||
// Generalize non-variable types. That way we can support cases like:
|
||||
// `a = foo(x, ...); a(1); a('s')`
|
||||
if (!val->isVar())
|
||||
if (!val->isVar()) {
|
||||
val->type = val->type->generalize(ctx->typecheckLevel - 1);
|
||||
assign->lhs->type = val->type;
|
||||
}
|
||||
|
||||
// todo)) if (in(ctx->cache->globals, lhs)) {
|
||||
}
|
||||
|
||||
if ((!assign->rhs || assign->rhs->isDone()) && realize(assign->lhs->type)) {
|
||||
assign->setDone();
|
||||
} else if (assign->rhs && !val->isVar() && val->type->getUnbounds().empty()) {
|
||||
assign->setDone();
|
||||
}
|
||||
|
||||
// Register all toplevel variables as global in JIT mode
|
||||
|
|
|
@ -636,14 +636,18 @@ ExprPtr TypecheckVisitor::transformTupleGenerator(CallExpr *expr) {
|
|||
/// b: int```
|
||||
ExprPtr TypecheckVisitor::transformNamedTuple(CallExpr *expr) {
|
||||
// Ensure that namedtuple call is valid
|
||||
if (expr->args.size() != 2 || !expr->args[0].value->getString() ||
|
||||
!expr->args[1].value->origExpr->getList())
|
||||
if (expr->args.size() != 1 || !expr->args[0].value->origExpr->getList())
|
||||
E(Error::CALL_NAMEDTUPLE, getSrcInfo());
|
||||
|
||||
auto name = expr->expr->type->getFunc()
|
||||
->funcGenerics[0]
|
||||
.type->getStatic()
|
||||
->evaluate()
|
||||
.getString();
|
||||
// Construct the class statement
|
||||
std::vector<Param> generics, params;
|
||||
int ti = 1;
|
||||
for (auto &i : expr->args[1].value->origExpr->getList()->items) {
|
||||
for (auto &i : expr->args[0].value->origExpr->getList()->items) {
|
||||
if (auto s = i->getString()) {
|
||||
generics.emplace_back(format("T{}", ti), N<IdExpr>("type"), nullptr, true);
|
||||
params.emplace_back(s->getValue(), N<IdExpr>(format("T{}", ti++)), nullptr);
|
||||
|
@ -657,7 +661,6 @@ ExprPtr TypecheckVisitor::transformNamedTuple(CallExpr *expr) {
|
|||
}
|
||||
for (auto &g : generics)
|
||||
params.push_back(g);
|
||||
auto name = expr->args[0].value->getString()->getValue();
|
||||
prependStmts->push_back(transform(
|
||||
N<ClassStmt>(name, params, nullptr, std::vector<ExprPtr>{N<IdExpr>("tuple")})));
|
||||
return transformType(N<IdExpr>(name));
|
||||
|
|
|
@ -257,7 +257,9 @@ void TypecheckVisitor::visit(ClassStmt *stmt) {
|
|||
for (auto &mf : ctx->cache->overloads[mm.second]) {
|
||||
auto f = ctx->cache->functions[mf].origAst;
|
||||
if (!f->attributes.has("autogenerated")) {
|
||||
fnStmts.push_back(transform(clone(f)));
|
||||
LOG("=> adding {} . {} to {} : {}", base->name, f->name, name,
|
||||
f->toString(2));
|
||||
fnStmts.push_back(transform(clean_clone(f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -449,15 +451,15 @@ TypecheckVisitor::parseBaseClasses(std::vector<ExprPtr> &baseClasses,
|
|||
|
||||
if (auto st = getStaticGeneric(a.type.get())) {
|
||||
generic->isStatic = st;
|
||||
auto val = ctx->addVar(a.name, a.name, generic);
|
||||
auto val = ctx->addVar(ctx->cache->rev(a.name), a.name, generic);
|
||||
val->generic = true;
|
||||
val->staticType = st;
|
||||
} else {
|
||||
ctx->addType(a.name, a.name, generic)->generic = true;
|
||||
ctx->addType(ctx->cache->rev(a.name), a.name, generic)->generic = true;
|
||||
}
|
||||
ClassType::Generic g{a.name, a.name, generic->generalize(ctx->typecheckLevel),
|
||||
typId};
|
||||
if (a.status == Param::Generic) {
|
||||
if (args.back().status == Param::Generic) {
|
||||
typ->generics.push_back(g);
|
||||
} else {
|
||||
typ->hiddenGenerics.push_back(g);
|
||||
|
@ -481,7 +483,8 @@ TypecheckVisitor::parseBaseClasses(std::vector<ExprPtr> &baseClasses,
|
|||
seqassert(ctx->cache->classes[ast->name].fields[ai].name == a.name,
|
||||
"bad class fields: {} vs {}",
|
||||
ctx->cache->classes[ast->name].fields[ai].name, a.name);
|
||||
args.emplace_back(name, transformType(a.type), transform(a.defaultValue));
|
||||
args.emplace_back(name, transformType(clean_clone(a.type)),
|
||||
transform(clean_clone(a.defaultValue)));
|
||||
ctx->cache->classes[canonicalName].fields.push_back(Cache::Class::ClassField{
|
||||
name, args.back().type->getType(),
|
||||
ctx->cache->classes[ast->name].fields[ai].baseClass});
|
||||
|
|
|
@ -143,6 +143,7 @@ std::string TypeContext::generateCanonicalName(const std::string &name,
|
|||
bool includeBase, bool noSuffix) const {
|
||||
std::string newName = name;
|
||||
bool alreadyGenerated = name.find('.') != std::string::npos;
|
||||
alreadyGenerated |= !name.empty() && name[0] == '%';
|
||||
if (includeBase && !alreadyGenerated) {
|
||||
std::string base = getBaseName();
|
||||
if (base.empty())
|
||||
|
|
|
@ -125,6 +125,7 @@ void TypecheckVisitor::visit(FunctionStmt *stmt) {
|
|||
stmt->suite->firstInBlock());
|
||||
return;
|
||||
}
|
||||
auto stmt_clone = clone(stmt, true); // clean clone
|
||||
|
||||
// Parse attributes
|
||||
for (auto i = stmt->decorators.size(); i-- > 0;) {
|
||||
|
@ -178,6 +179,8 @@ void TypecheckVisitor::visit(FunctionStmt *stmt) {
|
|||
|
||||
// Handle captures. Add additional argument to the function for every capture.
|
||||
// Make sure to account for **kwargs if present
|
||||
if (stmt->name == "fromkeys")
|
||||
LOG("--");
|
||||
std::map<std::string, TypeContext::Item> captures;
|
||||
for (auto &[c, t] : stmt->attributes.captures) {
|
||||
if (auto v = ctx->find(c)) {
|
||||
|
@ -390,7 +393,7 @@ void TypecheckVisitor::visit(FunctionStmt *stmt) {
|
|||
auto f = N<FunctionStmt>(canonicalName, ret, args, suite, stmt->attributes);
|
||||
ctx->cache->functions[canonicalName].module = ctx->getModule();
|
||||
ctx->cache->functions[canonicalName].ast = f;
|
||||
ctx->cache->functions[canonicalName].origAst = clone(stmt);
|
||||
ctx->cache->functions[canonicalName].origAst = stmt_clone;
|
||||
ctx->cache->functions[canonicalName].isToplevel =
|
||||
ctx->getModule().empty() && ctx->isGlobal();
|
||||
ctx->cache->functions[canonicalName].rootName = rootName;
|
||||
|
@ -403,6 +406,8 @@ void TypecheckVisitor::visit(FunctionStmt *stmt) {
|
|||
if (isClassMember && stmt->attributes.has(Attr::Method)) {
|
||||
funcTyp->funcParent = ctx->find(stmt->attributes.parentClass)->type;
|
||||
}
|
||||
if (startswith(funcTyp->toString(), "std.collections.defaultdict.0.__init__:5"))
|
||||
LOG("-> realizing ... {:D}", funcTyp);
|
||||
funcTyp = std::static_pointer_cast<types::FuncType>(
|
||||
funcTyp->generalize(ctx->typecheckLevel));
|
||||
ctx->cache->functions[canonicalName].type = funcTyp;
|
||||
|
|
|
@ -319,19 +319,21 @@ StmtPtr TypecheckVisitor::transformNewImport(const ImportFile &file) {
|
|||
n = nullptr;
|
||||
}
|
||||
n = N<SuiteStmt>(n, parseFile(ctx->cache, file.path));
|
||||
ScopingVisitor::apply(ctx->cache, n);
|
||||
auto tv = TypecheckVisitor(ictx, preamble);
|
||||
n = tv.transform(n);
|
||||
ScopingVisitor::apply(ctx->cache, n);
|
||||
// n = tv.transform(n);
|
||||
|
||||
if (!ctx->cache->errors.empty())
|
||||
throw exc::ParserException();
|
||||
// Add comment to the top of import for easier dump inspection
|
||||
auto comment = N<CommentStmt>(format("import: {} at {}", file.module, file.path));
|
||||
auto suite = N<SuiteStmt>(comment, n);
|
||||
|
||||
if (ctx->isStdlibLoading) {
|
||||
// When loading the standard library, imports are not wrapped.
|
||||
// We assume that the standard library has no recursive imports and that all
|
||||
// statements are executed before the user-provided code.
|
||||
return N<SuiteStmt>(comment, n);
|
||||
return tv.transform(suite);
|
||||
} else {
|
||||
// Generate import identifier
|
||||
std::string importVar = import->second.importVar =
|
||||
|
@ -339,41 +341,29 @@ StmtPtr TypecheckVisitor::transformNewImport(const ImportFile &file) {
|
|||
std::string importDoneVar;
|
||||
|
||||
// `import_[I]_done = False` (set to True upon successful import)
|
||||
preamble->push_back(N<AssignStmt>(N<IdExpr>(importDoneVar = importVar + "_done"),
|
||||
N<BoolExpr>(false)));
|
||||
preamble->push_back(transform(N<AssignStmt>(
|
||||
N<IdExpr>(importDoneVar = importVar + "_done"), N<BoolExpr>(false))));
|
||||
ctx->cache->addGlobal(importDoneVar);
|
||||
|
||||
// Wrap all imported top-level statements into a function.
|
||||
// Make sure to register the global variables and set their assignments as updates.
|
||||
// Note: signatures/classes/functions are not wrapped
|
||||
std::vector<StmtPtr> stmts;
|
||||
auto processToplevelStmt = [&](const StmtPtr &s) {
|
||||
// Process toplevel statement
|
||||
if (auto a = s->getAssign()) {
|
||||
if (!a->isUpdate() && a->lhs->getId()) {
|
||||
// Global `a = ...`
|
||||
auto val = ictx->forceFind(a->lhs->getId()->value);
|
||||
if (val->isVar() && val->isGlobal())
|
||||
ctx->cache->addGlobal(val->canonicalName);
|
||||
}
|
||||
}
|
||||
stmts.push_back(s);
|
||||
};
|
||||
processToplevelStmt(comment);
|
||||
if (auto st = n->getSuite()) {
|
||||
for (auto &ss : st->stmts)
|
||||
if (ss)
|
||||
processToplevelStmt(ss);
|
||||
} else {
|
||||
processToplevelStmt(n);
|
||||
}
|
||||
|
||||
// Create import function manually with ForceRealize
|
||||
ctx->cache->functions[importVar].ast =
|
||||
N<FunctionStmt>(importVar, nullptr, std::vector<Param>{}, N<SuiteStmt>(stmts),
|
||||
Attr({Attr::ForceRealize}));
|
||||
preamble->push_back(clone(ctx->cache->functions[importVar].ast));
|
||||
ctx->cache->overloads[importVar].push_back(importVar);
|
||||
// TODO: Make sure to register the global variables and set their assignments as
|
||||
// updates. Note: signatures/classes/functions are not wrapped Create import
|
||||
// function manually with ForceRealize
|
||||
auto fn =
|
||||
N<FunctionStmt>(importVar, N<IdExpr>("NoneType"), std::vector<Param>{}, suite);
|
||||
tv.transform(fn);
|
||||
tv.realize(ictx->forceFind(importVar)->type);
|
||||
preamble->push_back(fn);
|
||||
// return fn;
|
||||
// LOG("--- {}", importVar);
|
||||
// ictx->dump();
|
||||
// auto baseType = getFuncTypeBase(0);
|
||||
// auto funcTyp = std::make_shared<types::FuncType>(
|
||||
// baseType, ctx->cache->functions[importVar].ast.get());
|
||||
// funcTyp->setSrcInfo(getSrcInfo());
|
||||
// ctx->cache->functions[importVar].type = funcTyp;
|
||||
// ctx->addFunc(importVar, importVar, funcTyp, getSrcInfo());
|
||||
// ctx->cache->overloads[importVar].push_back(importVar);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -299,15 +299,19 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type, bool force)
|
|||
E(Error::MAX_REALIZATION, getSrcInfo(), ctx->cache->rev(type->ast->name));
|
||||
}
|
||||
|
||||
getLogger().level++;
|
||||
ctx->addBlock();
|
||||
ctx->typecheckLevel++;
|
||||
if (!startswith(type->ast->name, "%_import_")) {
|
||||
getLogger().level++;
|
||||
ctx->addBlock();
|
||||
ctx->typecheckLevel++;
|
||||
}
|
||||
|
||||
// Find function parents
|
||||
ctx->bases.push_back({type->ast->name, type->getFunc(), type->getRetType()});
|
||||
LOG_TYPECHECK("[realize] fn {} -> {} : base {} ; depth = {} ; ctx-base: {}",
|
||||
type->ast->name, type->realizedName(), ctx->getRealizationStackName(),
|
||||
ctx->getRealizationDepth(), ctx->getBaseName());
|
||||
if (!startswith(type->ast->name, "%_import_")) {
|
||||
ctx->bases.push_back({type->ast->name, type->getFunc(), type->getRetType()});
|
||||
LOG_TYPECHECK("[realize] fn {} -> {} : base {} ; depth = {} ; ctx-base: {}",
|
||||
type->ast->name, type->realizedName(), ctx->getRealizationStackName(),
|
||||
ctx->getRealizationDepth(), ctx->getBaseName());
|
||||
}
|
||||
|
||||
// Clone the generic AST that is to be realized
|
||||
auto ast = generateSpecialAst(type);
|
||||
|
@ -360,10 +364,12 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type, bool force)
|
|||
// inferTypes(ast.suite, ctx);
|
||||
error("cannot typecheck the program");
|
||||
}
|
||||
ctx->bases.pop_back();
|
||||
ctx->popBlock();
|
||||
ctx->typecheckLevel--;
|
||||
getLogger().level--;
|
||||
if (!startswith(type->ast->name, "%_import_")) {
|
||||
ctx->bases.pop_back();
|
||||
ctx->popBlock();
|
||||
ctx->typecheckLevel--;
|
||||
getLogger().level--;
|
||||
}
|
||||
this->ctx = oldCtx;
|
||||
return nullptr; // inference must be delayed
|
||||
} else {
|
||||
|
@ -403,10 +409,12 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type, bool force)
|
|||
val = std::make_shared<TypecheckItem>(type->realizedName(), "", ctx->getModule(),
|
||||
type->getFunc());
|
||||
ctx->addAlwaysVisible(val);
|
||||
ctx->bases.pop_back();
|
||||
ctx->popBlock();
|
||||
ctx->typecheckLevel--;
|
||||
getLogger().level--;
|
||||
if (!startswith(type->ast->name, "%_import_")) {
|
||||
ctx->bases.pop_back();
|
||||
ctx->popBlock();
|
||||
ctx->typecheckLevel--;
|
||||
getLogger().level--;
|
||||
}
|
||||
this->ctx = oldCtx;
|
||||
|
||||
return type->getFunc();
|
||||
|
|
|
@ -361,17 +361,17 @@ class defaultdict(Static[Dict[K,V]]):
|
|||
V: type
|
||||
S: TypeVar[Callable[[], V]]
|
||||
|
||||
def __init__(self: defaultdict[K, VV, Function[[], V]], VV: TypeVar[V]):
|
||||
super().__init__()
|
||||
self.default_factory = lambda: VV()
|
||||
# def __init__(self: defaultdict[K, VV, Function[[], V]], VV: TypeVar[V]):
|
||||
# super().__init__()
|
||||
# self.default_factory = lambda: VV()
|
||||
|
||||
def __init__(self, f: S):
|
||||
super().__init__()
|
||||
self.default_factory = f
|
||||
|
||||
def __init__(self: defaultdict[K, VV, Function[[], V]], VV: TypeVar[V], other: Dict[K, V]):
|
||||
super().__init__(other)
|
||||
self.default_factory = lambda: VV()
|
||||
# def __init__(self: defaultdict[K, VV, Function[[], V]], VV: TypeVar[V], other: Dict[K, V]):
|
||||
# super().__init__(other)
|
||||
# self.default_factory = lambda: VV()
|
||||
|
||||
def __init__(self, f: S, other: Dict[K, V]):
|
||||
super().__init__(other)
|
||||
|
|
Loading…
Reference in New Issue