Fix call tests [wip]

typecheck-v2
Ibrahim Numanagić 2023-12-09 18:13:07 -08:00
parent abadfeb03e
commit bef36e016a
34 changed files with 229 additions and 226 deletions

View File

@ -357,7 +357,7 @@ const std::string Attr::HasSelf = ".__hasself__";
const std::string Attr::Extend = "extend";
const std::string Attr::Tuple = "tuple";
const std::string Attr::Test = "std.internal.attributes.test";
const std::string Attr::Overload = "overload";
const std::string Attr::Overload = "overload:0";
const std::string Attr::Export = "std.internal.attributes.export";
FunctionStmt::FunctionStmt(std::string name, ExprPtr ret, std::vector<Param> args,

View File

@ -25,7 +25,7 @@
#define TYPE_CALLABLE "Callable"
#define TYPE_OPTIONAL "Optional"
#define TYPE_SLICE "std.internal.types.slice.Slice"
#define FN_UNWRAP "std.internal.types.optional.unwrap.0"
#define FN_UNWRAP "std.internal.types.optional.unwrap.0:0"
#define VAR_ARGV "__argv__"
#define MAX_INT_WIDTH 10000

View File

@ -148,7 +148,7 @@ void TranslateVisitor::defaultVisit(Expr *n) {
}
void TranslateVisitor::visit(NoneExpr *expr) {
auto f = expr->type->realizedName() + ":Optional.__new__";
auto f = expr->type->realizedName() + ":Optional.__new__:0";
auto val = ctx->find(f);
seqassert(val, "cannot find '{}'", f);
result = make<ir::CallInstr>(expr, make<ir::VarValue>(expr, val->getFunc()),
@ -263,7 +263,7 @@ void TranslateVisitor::visit(CallExpr *expr) {
expr->args[0].value->getId()->value);
result = make<ir::PointerValue>(expr, val->getVar());
return;
} else if (expr->expr->isId("__array__.__new__")) {
} else if (expr->expr->isId("__array__.__new__:0")) {
auto fnt = expr->expr->type->getFunc();
auto szt = fnt->funcGenerics[0].type->getStatic();
auto sz = szt->evaluate().getInt();

View File

@ -22,8 +22,8 @@ using namespace types;
/// For tuple identifiers, generate appropriate class. See @c generateTuple for
/// details.
void TypecheckVisitor::visit(IdExpr *expr) {
if (isTuple(expr->value))
generateTuple(std::stoi(expr->value.substr(sizeof(TYPE_TUPLE) - 1)));
// if (isTuple(expr->value))
// generateTuple(std::stoi(expr->value.substr(sizeof(TYPE_TUPLE) - 1)));
auto val = ctx->find(expr->value);
// if (!val && ctx->getBase()->pyCaptures) {
@ -39,8 +39,11 @@ void TypecheckVisitor::visit(IdExpr *expr) {
// ctx->cache->typeCtx->dump();
E(Error::ID_NOT_FOUND, expr, expr->value);
}
if (expr->type->getUnbound() && in(ctx->cache->overloads, val->canonicalName))
auto o = in(ctx->cache->overloads, val->canonicalName);
if (expr->type->getUnbound() && o && o->size() > 1) {
// LOG("dispatch: {}", val->canonicalName);
val = ctx->forceFind(getDispatch(val->canonicalName)->ast->name);
}
// If we are accessing an outside variable, capture it or raise an error
auto captured = checkCapture(val);
@ -414,10 +417,10 @@ ExprPtr TypecheckVisitor::transformDot(DotExpr *expr,
// __internal__.class_get_rtti_vtable(expr)[T[VIRTUAL_ID]]
// )
auto e = N<CallExpr>(
fnType,
N<IndexExpr>(N<CallExpr>(N<IdExpr>("__internal__.class_get_rtti_vtable"),
expr->expr),
N<IntExpr>(vid)));
fnType, N<IndexExpr>(N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"),
"class_get_rtti_vtable"),
expr->expr),
N<IntExpr>(vid)));
return transform(e);
}
}
@ -529,7 +532,7 @@ ExprPtr TypecheckVisitor::getClassMember(DotExpr *expr,
// Case: transform `union.m` to `__internal__.get_union_method(union, "m", ...)`
if (typ->getUnion()) {
return transform(N<CallExpr>(
N<IdExpr>("__internal__.get_union_method"),
N<DotExpr>(N<IdExpr>("__internal__"), "get_union_method"),
std::vector<CallExpr::Arg>{{"union", expr->expr},
{"method", N<StringExpr>(expr->member)},
{"", N<EllipsisExpr>(EllipsisExpr::PARTIAL)}}));

View File

@ -19,7 +19,7 @@ void TypecheckVisitor::visit(NoneExpr *expr) {
if (realize(expr->type)) {
// Realize the appropriate `Optional.__new__` for the translation stage
auto cls = expr->type->getClass();
auto f = ctx->forceFind(TYPE_OPTIONAL ".__new__")->type;
auto f = ctx->forceFind(TYPE_OPTIONAL ".__new__:0")->type;
auto t = realize(ctx->instantiate(f, cls)->getFunc());
expr->setDone();
}

View File

@ -60,6 +60,18 @@ void TypecheckVisitor::visit(EllipsisExpr *expr) {
/// See @c transformCallArgs , @c getCalleeFn , @c callReorderArguments ,
/// @c typecheckCallArgs , @c transformSpecialCall and @c wrapExpr for more details.
void TypecheckVisitor::visit(CallExpr *expr) {
// Special case!
if (expr->type->getUnbound()) {
auto callExpr = transform(clean_clone(expr->expr));
if (callExpr->isId("std.collections.namedtuple.0")) {
resultExpr = transformNamedTuple(expr);
return;
} else if (callExpr->isId("std.functools.partial.0:0")) {
resultExpr = transformFunctoolsPartial(expr);
return;
}
}
// Transform and expand arguments. Return early if it cannot be done yet
if (!transformCallArgs(expr->args))
return;
@ -423,7 +435,7 @@ ExprPtr TypecheckVisitor::callReorderArguments(FuncTypePtr calleeFn, CallExpr *e
// Reorder arguments if needed
part.args = part.kwArgs = nullptr; // Stores partial *args/**kwargs expression
if (expr->hasAttr(ExprAttr::OrderedCall) || expr->expr->isId("superf")) {
if (expr->hasAttr(ExprAttr::OrderedCall)) {
args = expr->args;
} else {
ctx->reorderNamedArgs(
@ -598,26 +610,23 @@ std::pair<bool, ExprPtr> TypecheckVisitor::transformSpecialCall(CallExpr *expr)
if (!expr->expr->getId())
return {false, nullptr};
auto val = expr->expr->getId()->value;
// LOG(".. {}", val);
if (val == "tuple" && expr->args.size() == 1 &&
CAST(expr->args.front().value, GeneratorExpr)) {
return {true, transformTupleGenerator(expr)};
} else if (val == "std.collections.namedtuple.0") {
return {true, transformNamedTuple(expr)};
} else if (val == "std.functools.partial.0") {
return {true, transformFunctoolsPartial(expr)};
} else if (val == "superf") {
return {true, transformSuperF(expr)};
} else if (val == "super") {
} else if (val == "super:0") {
return {true, transformSuper()};
} else if (val == "__ptr__") {
return {true, transformPtr(expr)};
} else if (val == "__array__.__new__") {
} else if (val == "__array__.__new__:0") {
return {true, transformArray(expr)};
} else if (val == "isinstance") {
return {true, transformIsInstance(expr)};
} else if (val == "staticlen") {
return {true, transformStaticLen(expr)};
} else if (val == "hasattr" || val == "hasattr:1") {
} else if (startswith(val, "hasattr:")) {
return {true, transformHasAttr(expr)};
} else if (val == "getattr") {
return {true, transformGetAttr(expr)};
@ -661,18 +670,15 @@ ExprPtr TypecheckVisitor::transformTupleGenerator(CallExpr *expr) {
/// b: int```
ExprPtr TypecheckVisitor::transformNamedTuple(CallExpr *expr) {
// Ensure that namedtuple call is valid
if (expr->args.size() != 1 || !expr->args[0].value->origExpr->getList())
if (expr->args.size() != 2 || !(expr->args[0].value->getString()) ||
!(expr->args[1].value->getList()))
E(Error::CALL_NAMEDTUPLE, getSrcInfo());
auto name = expr->expr->type->getFunc()
->funcGenerics[0]
.type->getStatic()
->evaluate()
.getString();
auto name = expr->args[0].value->getString()->getValue();
// Construct the class statement
std::vector<Param> generics, params;
int ti = 1;
for (auto &i : expr->args[0].value->origExpr->getList()->items) {
for (auto &i : expr->args[1].value->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);
@ -737,11 +743,18 @@ ExprPtr TypecheckVisitor::transformSuperF(CallExpr *expr) {
}
if (supers.empty())
E(Error::CALL_SUPERF, expr);
seqassert(expr->args.size() == 1 && expr->args[0].value->getCall(),
"bad superf call");
std::vector<CallExpr::Arg> newArgs;
for (auto &a : expr->args[0].value->getCall()->args)
newArgs.push_back({"", a.value});
auto m = findMatchingMethods(
func->funcParent ? func->funcParent->getClass() : nullptr, supers, expr->args);
func->funcParent ? func->funcParent->getClass() : nullptr, supers, newArgs);
if (m.empty())
E(Error::CALL_SUPERF, expr);
return transform(N<CallExpr>(N<IdExpr>(m[0]->ast->name), expr->args));
auto c = transform(N<CallExpr>(N<IdExpr>(m[0]->ast->name), newArgs));
return c;
}
/// Typecheck and transform super method. Replace it with the current self object cast
@ -782,8 +795,8 @@ ExprPtr TypecheckVisitor::transformSuper() {
std::vector<ExprPtr> members;
for (auto &field : ctx->cache->classes[name].fields)
members.push_back(N<DotExpr>(N<IdExpr>(funcTyp->ast->args[0].name), field.name));
ExprPtr e = transform(
N<CallExpr>(N<IdExpr>(format(TYPE_TUPLE "{}", members.size())), members));
ExprPtr e =
transform(N<CallExpr>(N<IdExpr>(generateTuple(members.size())), members));
e->type = unify(superTyp, e->type); // see super_tuple test for this line
return e;
} else {
@ -867,7 +880,8 @@ ExprPtr TypecheckVisitor::transformIsInstance(CallExpr *expr) {
if (tag == -1)
return transform(N<BoolExpr>(false));
return transform(N<BinaryExpr>(
N<CallExpr>(N<IdExpr>("__internal__.union_get_tag"), expr->args[0].value),
N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "union_get_tag"),
expr->args[0].value),
"==", N<IntExpr>(tag)));
} else if (typExpr->type->is("pyobj") && !typExpr->isType()) {
if (typ->is("pyobj")) {
@ -931,15 +945,14 @@ ExprPtr TypecheckVisitor::transformHasAttr(CallExpr *expr) {
->evaluate()
.getString();
std::vector<std::pair<std::string, TypePtr>> args{{"", typ}};
if (expr->expr->isId("hasattr")) {
if (expr->expr->isId("hasattr:0")) {
// Case: the first hasattr overload allows passing argument types via *args
auto tup = expr->args[1].value->getTuple();
seqassert(tup, "not a tuple");
for (auto &a : tup->items) {
transform(a);
if (!a->getType()->getClass())
auto tup = expr->args[1].value->getCall();
seqassert(tup, "not a tuple call");
for (auto &a : tup->args) {
if (!a.value->getType()->getClass())
return nullptr;
args.emplace_back("", a->getType());
args.emplace_back("", a.value->getType());
}
seqassert(expr->args[2].value->origExpr && expr->args[2].value->origExpr->getCall(),
"expected call: {}", expr->args[2].value->origExpr);
@ -1038,9 +1051,9 @@ ExprPtr TypecheckVisitor::transformTupleFn(CallExpr *expr) {
for (auto &field : ctx->cache->classes[cls->name].fields)
args.emplace_back(N<DotExpr>(N<IdExpr>(var), field.name));
return transform(N<StmtExpr>(
N<AssignStmt>(N<IdExpr>(var), expr->args.front().value),
N<CallExpr>(N<IdExpr>(format("{}{}", TYPE_TUPLE, args.size())), args)));
return transform(
N<StmtExpr>(N<AssignStmt>(N<IdExpr>(var), expr->args.front().value),
N<CallExpr>(N<IdExpr>(generateTuple(args.size())), args)));
}
/// Transform type function to a type IdExpr identifier.

View File

@ -6,6 +6,7 @@
#include "codon/parser/ast.h"
#include "codon/parser/cache.h"
#include "codon/parser/common.h"
#include "codon/parser/visitors/format/format.h"
#include "codon/parser/visitors/typecheck/typecheck.h"
using fmt::format;
@ -151,7 +152,7 @@ void TypecheckVisitor::visit(ClassStmt *stmt) {
}
// Collect classes (and their fields) that are to be statically inherited
std::vector<ClassStmt *> staticBaseASTs, baseASTs;
std::vector<types::ClassTypePtr> staticBaseASTs;
if (!stmt->attributes.has(Attr::Extend)) {
staticBaseASTs = parseBaseClasses(stmt->staticBaseClasses, args, stmt->attributes,
canonicalName, nullptr, typ);
@ -183,7 +184,7 @@ void TypecheckVisitor::visit(ClassStmt *stmt) {
// stmt->attributes.has(Attr::Extend)
// ? a.name
// : ctx->generateCanonicalName(a.name);
args.emplace_back(varName, clone(a.type),
args.emplace_back(varName, transformType(clean_clone(a.type)),
transform(clone(a.defaultValue), true));
ctx->cache->classes[canonicalName].fields.push_back(
Cache::Class::ClassField{varName, nullptr, canonicalName});
@ -203,17 +204,16 @@ void TypecheckVisitor::visit(ClassStmt *stmt) {
if (!stmt->attributes.has(Attr::Extend)) {
ctx->typecheckLevel++; // to avoid unifying generics early
auto &fields = ctx->cache->classes[canonicalName].fields;
for (auto ai = 0, aj = 0; ai < stmt->args.size(); ai++)
if (stmt->args[ai].status == Param::Normal &&
!ClassStmt::isClassVar(stmt->args[ai])) {
fields[aj].type = transformType(stmt->args[ai].type)
->getType()
->generalize(ctx->typecheckLevel - 1);
fields[aj].type->setSrcInfo(stmt->args[ai].type->getSrcInfo());
for (auto ai = 0, aj = 0; ai < args.size(); ai++) {
if (args[ai].status == Param::Normal && !ClassStmt::isClassVar(args[ai])) {
fields[aj].type =
args[ai].type->getType()->generalize(ctx->typecheckLevel - 1);
fields[aj].type->setSrcInfo(args[ai].type->getSrcInfo());
if (stmt->isRecord())
typ->getRecord()->args.push_back(fields[aj].type);
aj++;
}
}
ctx->typecheckLevel--;
}
@ -256,10 +256,11 @@ void TypecheckVisitor::visit(ClassStmt *stmt) {
for (auto &mm : ctx->cache->classes[base->name].methods)
for (auto &mf : ctx->cache->overloads[mm.second]) {
auto f = ctx->cache->functions[mf].origAst;
if (!f->attributes.has("autogenerated")) {
LOG("=> adding {} . {} to {} : {}", base->name, f->name, name,
f->toString(2));
if (f && !f->attributes.has("autogenerated")) {
ctx->addBlock();
addClassGenerics(base);
fnStmts.push_back(transform(clean_clone(f)));
ctx->popBlock();
}
}
}
@ -365,12 +366,12 @@ void TypecheckVisitor::visit(ClassStmt *stmt) {
/// @param args Class fields that are to be updated with base classes' fields.
/// @param typeAst Transformed AST for base class type (e.g., `A[T]`).
/// Only set when dealing with dynamic polymorphism.
std::vector<ClassStmt *>
std::vector<types::ClassTypePtr>
TypecheckVisitor::parseBaseClasses(std::vector<ExprPtr> &baseClasses,
std::vector<Param> &args, const Attr &attr,
const std::string &canonicalName,
const ExprPtr &typeAst, types::ClassTypePtr &typ) {
std::vector<ClassStmt *> asts;
std::vector<types::ClassTypePtr> asts;
// MAJOR TODO: fix MRO it to work with generic classes (maybe replacements? IDK...)
std::vector<std::vector<ExprPtr>> mro{{typeAst}};
@ -382,28 +383,22 @@ TypecheckVisitor::parseBaseClasses(std::vector<ExprPtr> &baseClasses,
// Get the base class and generic replacements (e.g., if there is Bar[T],
// Bar in Foo(Bar[int]) will have `T = int`)
transformType(cls);
if (auto i = cls->getId()) {
name = i->value;
} else if (auto e = CAST(cls, InstantiateExpr)) {
if (auto ei = e->typeExpr->getId()) {
name = ei->value;
subs = e->typeParams;
}
}
if (!cls->type->getClass())
E(Error::CLASS_ID_NOT_FOUND, getSrcInfo(), FormatVisitor::apply(cls));
Cache::Class *cachedCls = in(ctx->cache->classes, name);
if (!cachedCls)
E(Error::CLASS_ID_NOT_FOUND, getSrcInfo(), ctx->cache->rev(name));
asts.push_back(cachedCls->ast.get());
auto clsTyp = cls->type->getClass();
name = clsTyp->name;
asts.push_back(clsTyp);
parentClasses.push_back(clone(cls));
Cache::Class *cachedCls = in(ctx->cache->classes, name);
mro.push_back(cachedCls->mro);
// Sanity checks
if (attr.has(Attr::Tuple) && typeAst)
E(Error::CLASS_NO_INHERIT, getSrcInfo(), "tuple");
if (!attr.has(Attr::Tuple) && asts.back()->attributes.has(Attr::Tuple))
if (!attr.has(Attr::Tuple) && cachedCls->ast->attributes.has(Attr::Tuple))
E(Error::CLASS_TUPLE_INHERIT, getSrcInfo());
if (asts.back()->attributes.has(Attr::Internal))
if (cachedCls->ast->attributes.has(Attr::Internal))
E(Error::CLASS_NO_INHERIT, getSrcInfo(), "internal");
// Mark parent classes as polymorphic as well.
@ -411,67 +406,18 @@ TypecheckVisitor::parseBaseClasses(std::vector<ExprPtr> &baseClasses,
cachedCls->rtti = true;
}
// Add generics first
int nGenerics = 0;
for (auto &a : asts.back()->args)
nGenerics += a.status == Param::Generic;
int si = 0;
for (auto &a : asts.back()->args) {
if (a.status == Param::Normal)
continue;
if (a.status == Param::Generic) {
if (si == subs.size())
E(Error::GENERICS_MISMATCH, cls, ctx->cache->rev(asts.back()->name),
nGenerics, subs.size());
args.emplace_back(a.name, a.type, transformType(subs[si++], false),
Param::HiddenGeneric);
} else if (a.status == Param::HiddenGeneric) {
args.emplace_back(a);
}
auto generic = ctx->getUnbound();
auto typId = generic->id;
generic->getLink()->genericName = ctx->cache->rev(a.name);
if (args.back().defaultValue) {
auto defType = transformType(clone(args.back().defaultValue));
// Hidden generics can be outright replaced (e.g., `T=int`).
// Unify them immediately.
unify(defType->type, generic);
}
if (auto ti = CAST(a.type, InstantiateExpr)) {
// Parse TraitVar
seqassert(ti->typeExpr->isId(TYPE_TYPEVAR), "not a TypeVar instantiation");
auto l = transformType(ti->typeParams[0])->type;
if (l->getLink() && l->getLink()->trait)
generic->getLink()->trait = l->getLink()->trait;
else
generic->getLink()->trait = std::make_shared<types::TypeTrait>(l);
}
if (auto st = getStaticGeneric(a.type.get())) {
generic->isStatic = st;
auto val = ctx->addVar(ctx->cache->rev(a.name), a.name, generic);
val->generic = true;
val->staticType = st;
} else {
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 (args.back().status == Param::Generic) {
typ->generics.push_back(g);
} else {
typ->hiddenGenerics.push_back(g);
}
}
if (si != subs.size())
E(Error::GENERICS_MISMATCH, cls, ctx->cache->rev(asts.back()->name), nGenerics,
subs.size());
// Add hidden generics
for (auto &g : clsTyp->generics)
typ->hiddenGenerics.push_back(g);
for (auto &g : clsTyp->hiddenGenerics)
typ->hiddenGenerics.push_back(g);
}
// Add normal fields
for (auto &ast : asts) {
for (auto &clsTyp : asts) {
int ai = 0;
auto ast = ctx->cache->classes[clsTyp->name].ast;
ctx->addBlock();
addClassGenerics(clsTyp);
for (auto &a : ast->args) {
if (a.status == Param::Normal && !ClassStmt::isClassVar(a)) {
auto name = a.name;
@ -491,6 +437,7 @@ TypecheckVisitor::parseBaseClasses(std::vector<ExprPtr> &baseClasses,
ai++;
}
}
ctx->popBlock();
}
if (typeAst) {
if (!parentClasses.empty()) {
@ -791,4 +738,20 @@ int TypecheckVisitor::generateKwId(const std::vector<std::string> &names) {
}
}
void TypecheckVisitor::addClassGenerics(const types::ClassTypePtr &clsTyp) {
auto addGen = [&](auto g) {
if (auto st = g.type->getStatic()) {
auto val = ctx->addVar(ctx->cache->rev(g.name), g.name, st);
val->generic = true;
val->staticType = st->expr->staticValue.type;
} else {
ctx->addType(ctx->cache->rev(g.name), g.name, g.type)->generic = true;
}
};
for (auto &g : clsTyp->hiddenGenerics)
addGen(g);
for (auto &g : clsTyp->generics)
addGen(g);
}
} // namespace codon::ast

View File

@ -152,16 +152,17 @@ void TypecheckVisitor::visit(FunctionStmt *stmt) {
// Case 2: function overload
if (auto c = ctx->find(stmt->name)) {
if (c->isFunc() && c->getModule() == ctx->getModule() &&
c->getBaseName() == ctx->getBaseName())
rootName = ctx->cache->functions[c->canonicalName].rootName;
c->getBaseName() == ctx->getBaseName()) {
rootName = c->canonicalName;
}
}
}
if (rootName.empty())
rootName = ctx->generateCanonicalName(stmt->name, true, isClassMember);
// Append overload number to the name
auto canonicalName = rootName;
if (!ctx->cache->overloads[rootName].empty())
canonicalName += format(":{}", ctx->cache->overloads[rootName].size());
// if (!ctx->cache->overloads[rootName].empty())
canonicalName += format(":{}", ctx->cache->overloads[rootName].size());
ctx->cache->reverseIdentifierLookup[canonicalName] = stmt->name;
if (isClassMember) {
@ -179,8 +180,6 @@ 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)) {
@ -406,12 +405,12 @@ 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;
auto val = ctx->addFunc(stmt->name, canonicalName, funcTyp);
ctx->addFunc(stmt->name, rootName, funcTyp);
ctx->addFunc(canonicalName, canonicalName, funcTyp);
if (stmt->attributes.has(Attr::Overload)) {
ctx->remove(stmt->name); // first overload will handle it!
} else if (isClassMember) {
@ -435,6 +434,7 @@ void TypecheckVisitor::visit(FunctionStmt *stmt) {
// Hack so that we can later use same helpers for class overloads
ctx->cache->classes[".toplevel"].methods[stmt->name] = rootName;
}
// LOG("-> {} {} {} {}", getSrcInfo(), stmt->name, rootName, canonicalName);
// Ensure that functions with @C, @force_realize, and @export attributes can be
// realized
@ -461,9 +461,9 @@ void TypecheckVisitor::visit(FunctionStmt *stmt) {
a.value = clone(a.value);
}
// todo)) right now this adds a capture hook for recursive calls
f->suite = N<SuiteStmt>(
N<AssignStmt>(N<IdExpr>(rootName), N<CallExpr>(N<IdExpr>(rootName), pa)),
suite);
f->suite = N<SuiteStmt>(N<AssignStmt>(N<IdExpr>(canonicalName),
N<CallExpr>(N<IdExpr>(canonicalName), pa)),
suite);
}
// Parse remaining decorators
@ -577,8 +577,14 @@ std::pair<bool, std::string> TypecheckVisitor::getDecorator(const ExprPtr &e) {
if (id && id->getId()) {
auto ci = ctx->find(id->getId()->value);
if (ci && ci->isFunc()) {
return {ctx->cache->functions[ci->canonicalName].ast->attributes.isAttribute,
ci->canonicalName};
if (auto f = in(ctx->cache->functions, ci->canonicalName)) {
return {ctx->cache->functions[ci->canonicalName].ast->attributes.isAttribute,
ci->canonicalName};
} else if (ctx->cache->overloads[ci->canonicalName].size() == 1) {
return {ctx->cache->functions[ctx->cache->overloads[ci->canonicalName][0]]
.ast->attributes.isAttribute,
ci->canonicalName};
}
}
}
return {false, ""};

View File

@ -349,9 +349,9 @@ StmtPtr TypecheckVisitor::transformNewImport(const ImportFile &file) {
// 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 =
StmtPtr fn =
N<FunctionStmt>(importVar, N<IdExpr>("NoneType"), std::vector<Param>{}, suite);
tv.transform(fn);
fn = tv.transform(fn);
tv.realize(ictx->forceFind(importVar)->type);
preamble->push_back(fn);
// return fn;

View File

@ -424,7 +424,7 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type, bool force)
/// Intended to be called once the typechecking is done.
/// TODO: add JIT compatibility.
StmtPtr TypecheckVisitor::prepareVTables() {
auto rep = "__internal__.class_populate_vtables"; // see internal.codon
auto rep = "__internal__.class_populate_vtables:0"; // see internal.codon
if (!in(ctx->cache->functions, rep))
return nullptr;
auto &initFn = ctx->cache->functions[rep];
@ -440,7 +440,7 @@ StmtPtr TypecheckVisitor::prepareVTables() {
continue;
// __internal__.class_set_rtti_vtable(real.ID, size, real.type)
suite->stmts.push_back(N<ExprStmt>(
N<CallExpr>(N<IdExpr>("__internal__.class_set_rtti_vtable"),
N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "class_set_rtti_vtable"),
N<IntExpr>(real->id), N<IntExpr>(vtSz + 2), NT<IdExpr>(r))));
// LOG("[poly] {} -> {}", r, real->id);
vtSz = 0;
@ -454,18 +454,16 @@ StmtPtr TypecheckVisitor::prepareVTables() {
// p[real.ID].__setitem__(f.ID, Function[<TYPE_F>](f).__raw__())
LOG_REALIZE("[poly] vtable[{}][{}] = {}", real->id, vtSz + id, fn);
suite->stmts.push_back(N<ExprStmt>(N<CallExpr>(
N<IdExpr>("__internal__.class_set_rtti_vtable_fn"),
N<DotExpr>(N<IdExpr>("__internal__"), "class_set_rtti_vtable_fn"),
N<IntExpr>(real->id), N<IntExpr>(vtSz + id),
N<CallExpr>(N<DotExpr>(
N<CallExpr>(
NT<InstantiateExpr>(
NT<IdExpr>("Function"),
std::vector<ExprPtr>{
NT<InstantiateExpr>(
NT<IdExpr>(format("{}{}", TYPE_TUPLE, ids.size())),
ids),
NT<IdExpr>(fn->getRetType()->realizedName())}),
N<IdExpr>(fn->realizedName())),
N<CallExpr>(NT<InstantiateExpr>(
NT<IdExpr>("Function"),
std::vector<ExprPtr>{
NT<InstantiateExpr>(
NT<IdExpr>(generateTuple(ids.size())), ids),
NT<IdExpr>(fn->getRetType()->realizedName())}),
N<IdExpr>(fn->realizedName())),
"__raw__")),
NT<IdExpr>(r))));
}
@ -480,7 +478,7 @@ StmtPtr TypecheckVisitor::prepareVTables() {
typ->ast = initFn.ast.get();
realizeFunc(typ.get(), true);
auto &initDist = ctx->cache->functions["__internal__.class_base_derived_dist"];
auto &initDist = ctx->cache->functions["__internal__.class_base_derived_dist:0"];
// def class_base_derived_dist(B, D):
// return Tuple[<types before B is reached in D>].__elemsize__
auto oldAst = initDist.ast;
@ -505,8 +503,7 @@ StmtPtr TypecheckVisitor::prepareVTables() {
"cannot find distance between {} and {}", derivedTyp->name,
baseTyp->name);
StmtPtr suite = N<ReturnStmt>(
N<DotExpr>(NT<InstantiateExpr>(
NT<IdExpr>(format("{}{}", TYPE_TUPLE, types.size())), types),
N<DotExpr>(NT<InstantiateExpr>(NT<IdExpr>(generateTuple(types.size())), types),
"__elemsize__"));
LOG_REALIZE("[poly] {} : {}", t, *suite);
initDist.ast->suite = suite;
@ -606,7 +603,7 @@ size_t TypecheckVisitor::getRealizationID(types::ClassType *cp, types::FuncType
nullptr);
std::vector<ExprPtr> callArgs;
callArgs.emplace_back(
N<CallExpr>(N<IdExpr>("__internal__.class_base_to_derived"),
N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "class_base_to_derived"),
N<IdExpr>(fp->ast->args[0].name), N<IdExpr>(cp->realizedName()),
N<IdExpr>(real->type->realizedName())));
for (size_t i = 1; i < args.size(); i++)
@ -842,8 +839,8 @@ TypecheckVisitor::generateSpecialAst(types::FuncType *type) {
seqassert(unionType, "expected union, got {}", type->funcParent);
StmtPtr suite = N<ReturnStmt>(N<CallExpr>(
N<IdExpr>("__internal__.new_union"), N<IdExpr>(type->ast->args[0].name),
N<IdExpr>(unionType->realizedTypeName())));
N<DotExpr>(N<IdExpr>("__internal__"), "new_union"),
N<IdExpr>(type->ast->args[0].name), N<IdExpr>(unionType->realizedTypeName())));
ast->suite = suite;
} else if (startswith(ast->name, "__internal__.new_union")) {
// Special case: __internal__.new_union
@ -865,7 +862,7 @@ TypecheckVisitor::generateSpecialAst(types::FuncType *type) {
suite->stmts.push_back(N<IfStmt>(
N<CallExpr>(N<IdExpr>("isinstance"), N<IdExpr>(objVar),
NT<IdExpr>(t->realizedName())),
N<ReturnStmt>(N<CallExpr>(N<IdExpr>("__internal__.union_make"),
N<ReturnStmt>(N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "union_make"),
N<IntExpr>(tag), N<IdExpr>(objVar),
N<IdExpr>(unionType->realizedTypeName())))));
// Check for Union[T]
@ -874,11 +871,11 @@ TypecheckVisitor::generateSpecialAst(types::FuncType *type) {
N<IdExpr>("isinstance"), N<IdExpr>(objVar),
NT<InstantiateExpr>(NT<IdExpr>("Union"),
std::vector<ExprPtr>{NT<IdExpr>(t->realizedName())})),
N<ReturnStmt>(
N<CallExpr>(N<IdExpr>("__internal__.union_make"), N<IntExpr>(tag),
N<CallExpr>(N<IdExpr>("__internal__.get_union"),
N<IdExpr>(objVar), NT<IdExpr>(t->realizedName())),
N<IdExpr>(unionType->realizedTypeName())))));
N<ReturnStmt>(N<CallExpr>(
N<DotExpr>(N<IdExpr>("__internal__"), "union_make"), N<IntExpr>(tag),
N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "get_union"),
N<IdExpr>(objVar), NT<IdExpr>(t->realizedName())),
N<IdExpr>(unionType->realizedTypeName())))));
tag++;
}
suite->stmts.push_back(N<ExprStmt>(N<CallExpr>(
@ -901,12 +898,13 @@ TypecheckVisitor::generateSpecialAst(types::FuncType *type) {
for (const auto &t : unionTypes) {
if (t->realizedName() == targetType->realizedName()) {
suite->stmts.push_back(N<IfStmt>(
N<BinaryExpr>(N<CallExpr>(N<IdExpr>("__internal__.union_get_tag"),
N<IdExpr>(selfVar)),
"==", N<IntExpr>(tag)),
N<ReturnStmt>(N<CallExpr>(N<IdExpr>("__internal__.union_get_data"),
N<IdExpr>(selfVar),
NT<IdExpr>(t->realizedName())))));
N<BinaryExpr>(
N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "union_get_tag"),
N<IdExpr>(selfVar)),
"==", N<IntExpr>(tag)),
N<ReturnStmt>(
N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "union_get_data"),
N<IdExpr>(selfVar), NT<IdExpr>(t->realizedName())))));
}
tag++;
}
@ -929,21 +927,21 @@ TypecheckVisitor::generateSpecialAst(types::FuncType *type) {
auto suite = N<SuiteStmt>();
int tag = 0;
for (auto &t : unionTypes) {
auto callee =
N<DotExpr>(N<CallExpr>(N<IdExpr>("__internal__.union_get_data"),
N<IdExpr>(selfVar), NT<IdExpr>(t->realizedName())),
fnName);
auto callee = N<DotExpr>(
N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "union_get_data"),
N<IdExpr>(selfVar), NT<IdExpr>(t->realizedName())),
fnName);
auto args = N<StarExpr>(N<IdExpr>(ast->args[2].name.substr(1)));
auto kwargs = N<KeywordStarExpr>(N<IdExpr>(ast->args[3].name.substr(2)));
std::vector<CallExpr::Arg> callArgs;
ExprPtr check = N<CallExpr>(N<IdExpr>("hasattr"), NT<IdExpr>(t->realizedName()),
N<StringExpr>(fnName), clone(args), clone(kwargs));
suite->stmts.push_back(N<IfStmt>(
N<BinaryExpr>(
check, "&&",
N<BinaryExpr>(N<CallExpr>(N<IdExpr>("__internal__.union_get_tag"),
N<IdExpr>(selfVar)),
"==", N<IntExpr>(tag))),
N<BinaryExpr>(check, "&&",
N<BinaryExpr>(N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"),
"union_get_tag"),
N<IdExpr>(selfVar)),
"==", N<IntExpr>(tag))),
N<SuiteStmt>(N<ReturnStmt>(N<CallExpr>(callee, args, kwargs)))));
tag++;
}
@ -961,8 +959,8 @@ TypecheckVisitor::generateSpecialAst(types::FuncType *type) {
auto selfVar = ast->args[0].name;
auto suite = N<SuiteStmt>(N<ReturnStmt>(
N<CallExpr>(N<IdExpr>("__internal__.union_get_data"), N<IdExpr>(selfVar),
NT<IdExpr>(unionTypes[0]->realizedName()))));
N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "union_get_data"),
N<IdExpr>(selfVar), NT<IdExpr>(unionTypes[0]->realizedName()))));
ast->suite = suite;
} else if (startswith(ast->name, "__internal__.namedkeys")) {
auto n = type->funcGenerics[0].type->getStatic()->evaluate().getInt();

View File

@ -272,7 +272,7 @@ void TypecheckVisitor::visit(IndexExpr *expr) {
if (expr->expr->isId("tuple") || expr->expr->isId("Tuple")) {
// Special case: tuples. Change to Tuple.N
auto t = expr->index->getTuple();
expr->expr = NT<IdExpr>(format(TYPE_TUPLE "{}", t ? t->items.size() : 1));
expr->expr = NT<IdExpr>(generateTuple(t ? t->items.size() : 1));
} else {
transform(expr->expr, true);
}
@ -828,9 +828,9 @@ TypecheckVisitor::transformStaticTupleIndex(const ClassTypePtr &tuple,
E(Error::TUPLE_RANGE_BOUNDS, index, sz - 1, i);
te.push_back(N<DotExpr>(clone(var), classItem->fields[i].name));
}
ExprPtr e = transform(N<StmtExpr>(
std::vector<StmtPtr>{ass},
N<CallExpr>(N<DotExpr>(format(TYPE_TUPLE "{}", te.size()), "__new__"), te)));
ExprPtr e = transform(
N<StmtExpr>(std::vector<StmtPtr>{ass},
N<CallExpr>(N<DotExpr>(generateTuple(te.size()), "__new__"), te)));
return {true, e};
}

View File

@ -504,7 +504,7 @@ bool TypecheckVisitor::wrapExpr(ExprPtr &expr, const TypePtr &expectedType,
expr = transform(N<CallExpr>(expr, N<EllipsisExpr>(EllipsisExpr::PARTIAL)));
else
expr = transform(N<CallExpr>(
N<IdExpr>("__internal__.class_ctr"),
N<DotExpr>(N<IdExpr>("__internal__"), "class_ctr"),
std::vector<CallExpr::Arg>{{"T", expr},
{"", N<EllipsisExpr>(EllipsisExpr::PARTIAL)}}));
}
@ -555,8 +555,8 @@ bool TypecheckVisitor::wrapExpr(ExprPtr &expr, const TypePtr &expectedType,
!expectedClass->getUnion()) {
// Extract union types via __internal__.get_union
if (auto t = realize(expectedClass)) {
expr = transform(N<CallExpr>(N<IdExpr>("__internal__.get_union"), expr,
N<IdExpr>(t->realizedName())));
expr = transform(N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "get_union"),
expr, N<IdExpr>(t->realizedName())));
} else {
return false;
}
@ -566,8 +566,8 @@ bool TypecheckVisitor::wrapExpr(ExprPtr &expr, const TypePtr &expectedType,
expectedClass->getUnion()->addType(exprClass);
if (auto t = realize(expectedClass)) {
if (expectedClass->unify(exprClass.get(), nullptr) == -1)
expr = transform(N<CallExpr>(N<IdExpr>("__internal__.new_union"), expr,
NT<IdExpr>(t->realizedName())));
expr = transform(N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "new_union"),
expr, NT<IdExpr>(t->realizedName())));
} else {
return false;
}

View File

@ -235,10 +235,9 @@ private: // Node typechecking rules
/* Classes (class.cpp) */
void visit(ClassStmt *) override;
std::vector<ClassStmt *> parseBaseClasses(std::vector<ExprPtr> &,
std::vector<Param> &, const Attr &,
const std::string &, const ExprPtr &,
types::ClassTypePtr &);
std::vector<types::ClassTypePtr>
parseBaseClasses(std::vector<ExprPtr> &, std::vector<Param> &, const Attr &,
const std::string &, const ExprPtr &, types::ClassTypePtr &);
std::pair<StmtPtr, FunctionStmt *> autoDeduceMembers(ClassStmt *,
std::vector<Param> &);
std::vector<StmtPtr> getClassMethods(const StmtPtr &s);
@ -248,6 +247,7 @@ private: // Node typechecking rules
bool);
std::string generateTuple(size_t);
int generateKwId(const std::vector<std::string> & = {});
void addClassGenerics(const types::ClassTypePtr &);
/* The rest (typecheck.cpp) */
void visit(SuiteStmt *) override;

View File

@ -16,10 +16,10 @@ from internal.types.float import *
from internal.types.byte import *
from internal.types.generator import *
from internal.types.optional import *
from internal.internal import *
from internal.types.slice import *
from internal.types.range import *
from internal.types.complex import *
from internal.internal import *
__argv__ = Array[str](0)

View File

@ -2,8 +2,9 @@
# Core library
from internal.core import *
from internal.attributes import *
from internal.static import static_print as __static_print__
from internal.types.ptr import *
from internal.types.str import *
from internal.types.int import *
@ -15,9 +16,13 @@ from internal.types.float import *
from internal.types.byte import *
from internal.types.generator import *
from internal.types.optional import *
from internal.internal import *
from internal.types.slice import *
from internal.types.range import *
from internal.internal import *
from internal.types.complex import *
__argv__ = Array[str](0)
from internal.types.strbuf import strbuf as _strbuf
from internal.types.collections.list import *
import internal.c_stubs as _C
@ -143,6 +148,21 @@ class str:
return str(self.ptr + i, j - i)
def join(self, l: Generator[str]) -> str:
buf = _strbuf()
if len(self) == 0:
for a in l:
buf.append(a)
else:
first = True
for a in l:
if first:
first = False
else:
buf.append(self)
buf.append(a)
return buf.__str__()
def __repr__(self) -> str:
return f"'{self}'"

View File

@ -31,7 +31,7 @@ class Exception(Static[BaseException]):
_pytype: ClassVar[cobj] = cobj()
def __init__(self, typename: str, msg: str = ""):
super().__init__(typename, msg)
if (hasattr(self.__class__, "_pytype")):
if hasattr(self.__class__, "_pytype"):
self.python_type = self.__class__._pytype
class NameError(Static[Exception]):

View File

@ -407,23 +407,23 @@ auto getTypeTests(const vector<string> &files) {
INSTANTIATE_TEST_SUITE_P(
TypeTests, SeqTest,
testing::ValuesIn(getTypeTests({
"parser/typecheck/access.codon",
"parser/typecheck/assign.codon",
"parser/typecheck/basic.codon",
"parser/typecheck/call.codon",
"parser/typecheck/class.codon",
"parser/typecheck/collections.codon",
"parser/typecheck/cond.codon",
"parser/typecheck/ctx.codon",
"parser/typecheck/error.codon",
"parser/typecheck/function.codon",
"parser/typecheck/import.codon",
"parser/typecheck/infer.codon",
"parser/typecheck/loops.codon",
"parser/typecheck/op.codon",
"parser/typecheck/parser.codon",
"parser/typecheck/python.codon",
"parser/typecheck/typecheck.codon"
"parser/typecheck/test_access.codon",
"parser/typecheck/test_assign.codon",
"parser/typecheck/test_basic.codon",
"parser/typecheck/test_call.codon",
"parser/typecheck/test_class.codon",
"parser/typecheck/test_collections.codon",
"parser/typecheck/test_cond.codon",
"parser/typecheck/test_ctx.codon",
"parser/typecheck/test_error.codon",
"parser/typecheck/test_function.codon",
"parser/typecheck/test_import.codon",
"parser/typecheck/test_infer.codon",
"parser/typecheck/test_loops.codon",
"parser/typecheck/test_op.codon",
"parser/typecheck/test_parser.codon",
"parser/typecheck/test_python.codon",
"parser/typecheck/test_typecheck.codon"
})),
getTypeTestNameFromParam);

View File

@ -227,7 +227,7 @@ class Foo:
print('foo')
def method(self, a):
print(a)
Foo().clsmethod() #! 'Foo' object has no method 'clsmethod' with arguments (Foo)
Foo().clsmethod() #! clsmethod() takes 0 arguments (1 given)
#%% nested_class_error,barebones
class X:

View File

@ -171,7 +171,7 @@ def doo[R, T](a: Callable[[T], R], b: Generator[T], c: Optional[T], d: T):
l = [1, 2, 3]
doo(b=l, d=Optional(5), c=l[0], a=lambda x: x+1)
#: int int
#: ._lambda Generator[int]
#: %_lambda Generator[int]
#: 2
#: 3
#: 4

View File

@ -5,12 +5,12 @@ assert True, "blah"
try:
assert False
except AssertionError as e:
print e.message[:15], e.message[-24:] #: Assert failed ( simplify_stmt.codon:164)
print e.message[:15], e.message[-19:] #: Assert failed ( test_error.codon:6)
try:
assert False, f"hehe {1}"
except AssertionError as e:
print e.message[:23], e.message[-24:] #: Assert failed: hehe 1 ( simplify_stmt.codon:169)
print e.message[:23], e.message[-20:] #: Assert failed: hehe 1 ( test_error.codon:11)
#%% try_throw,barebones
class MyError(Static[Exception]):
@ -27,8 +27,8 @@ try:
except MyError:
print "my"
except OSError as o:
print "os", o.typename, len(o.message), o.file[-20:], o.line
#: os OSError 9 typecheck_stmt.codon 249
print "os", o.typename, len(o.message), o.file[-16:], o.line
#: os OSError 9 test_error.codon 24
finally:
print "whoa" #: whoa