Fix static bool unification

typecheck-v2
Ibrahim Numanagić 2023-11-18 10:37:26 -08:00
parent 99973373e0
commit 1fc0655ea7
9 changed files with 84 additions and 70 deletions

View File

@ -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))

View File

@ -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

View File

@ -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));

View File

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

View File

@ -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())

View File

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

View File

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

View File

@ -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();

View File

@ -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)