Merge branch 'new-super' of https://github.com/exaloop/codon into new-super

pull/363/head
A. R. Shajii 2023-04-27 17:56:35 -04:00
commit 3ef57416b9
12 changed files with 238 additions and 178 deletions

View File

@ -29,7 +29,6 @@
#define TYPE_SLICE "std.internal.types.slice.Slice"
#define FN_UNWRAP "std.internal.types.optional.unwrap"
#define VAR_ARGV "__argv__"
#define VAR_CLSID ".__id__"
#define MAX_INT_WIDTH 10000
#define MAX_REALIZATION_DEPTH 200
@ -115,6 +114,8 @@ struct Cache : public std::enable_shared_from_this<Cache> {
std::string name;
/// A corresponding generic field type.
types::TypePtr type;
/// Base class name (if available)
std::string baseClass;
};
/// A list of class' ClassField instances. List is needed (instead of map) because
/// the order of the fields matters.
@ -149,6 +150,8 @@ struct Cache : public std::enable_shared_from_this<Cache> {
/// ClassRealization instance.
std::unordered_map<std::string, std::shared_ptr<ClassRealization>> realizations;
/// Set if a class is polymorphic and has RTTI.
bool rtti = false;
/// List of virtual method names
std::unordered_set<std::string> virtuals;
/// MRO

View File

@ -86,8 +86,8 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
} else {
ctx->addType(genName, varName, a.type->getSrcInfo())->generic = true;
}
args.emplace_back(Param{varName, transformType(clone(a.type), false),
transformType(clone(a.defaultValue), false), a.status});
args.emplace_back(varName, transformType(clone(a.type), false),
transformType(clone(a.defaultValue), false), a.status);
}
}
@ -108,14 +108,15 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
// Collect classes (and their fields) that are to be statically inherited
std::vector<ClassStmt *> staticBaseASTs, baseASTs;
std::vector<std::string> args_classes(args.size(), "");
if (!stmt->attributes.has(Attr::Extend)) {
staticBaseASTs = parseBaseClasses(stmt->staticBaseClasses, args, stmt->attributes,
canonicalName);
staticBaseASTs = parseBaseClasses(stmt->staticBaseClasses, args, args_classes,
stmt->attributes, canonicalName);
if (ctx->cache->isJit && !stmt->baseClasses.empty())
E(Error::CUSTOM, stmt->baseClasses[0],
"inheritance is not yet supported in JIT mode");
parseBaseClasses(stmt->baseClasses, args, stmt->attributes, canonicalName,
transformedTypeAst);
parseBaseClasses(stmt->baseClasses, args, args_classes, stmt->attributes,
canonicalName, transformedTypeAst);
}
// A ClassStmt will be separated into class variable assignments, method-free
@ -126,8 +127,9 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
for (auto &a : argsToParse) {
if (a.status == Param::Normal) {
if (!ClassStmt::isClassVar(a)) {
args.emplace_back(Param{a.name, transformType(clone(a.type), false),
transform(clone(a.defaultValue), true)});
args.emplace_back(a.name, transformType(clone(a.type), false),
transform(clone(a.defaultValue), true));
args_classes.emplace_back();
} else if (!stmt->attributes.has(Attr::Extend)) {
// Handle class variables. Transform them later to allow self-references
auto name = format("{}.{}", canonicalName, a.name);
@ -153,7 +155,8 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
if (!stmt->attributes.has(Attr::Extend)) {
for (size_t ai = 0; ai < args.size();) {
if (args[ai].status == Param::Normal)
ctx->cache->classes[canonicalName].fields.push_back({args[ai].name, nullptr});
ctx->cache->classes[canonicalName].fields.push_back(
Cache::Class::ClassField{args[ai].name, nullptr, args_classes[ai]});
ai++;
}
}
@ -289,7 +292,8 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
/// @param typeAst Transformed AST for base class type (e.g., `A[T]`).
/// Only set when dealing with dynamic polymorphism.
std::vector<ClassStmt *> SimplifyVisitor::parseBaseClasses(
std::vector<ExprPtr> &baseClasses, std::vector<Param> &args, const Attr &attr,
std::vector<ExprPtr> &baseClasses, std::vector<Param> &args,
std::vector<std::string> &args_classes, const Attr &attr,
const std::string &canonicalName, const ExprPtr &typeAst) {
std::vector<ClassStmt *> asts;
@ -327,14 +331,9 @@ std::vector<ClassStmt *> SimplifyVisitor::parseBaseClasses(
if (asts.back()->attributes.has(Attr::Internal))
E(Error::CLASS_NO_INHERIT, getSrcInfo(), "internal");
// Add __vtable__ to parent classes if it is not there already
auto var = format("{}.{}", VAR_CLSID, name);
if (typeAst && (cachedCls->fields.empty() || cachedCls->fields[0].name != var)) {
// LOG("[virtual] vtable({}) := {}", name, var);
cachedCls->fields.insert(cachedCls->fields.begin(), {var, nullptr});
cachedCls->ast->args.insert(cachedCls->ast->args.begin(),
Param{var, transformType(N<IdExpr>("int")), nullptr});
}
// Mark parent classes as polymorphic as well.
if (typeAst)
cachedCls->rtti = true;
// Add generics first
int nGenerics = 0;
@ -348,8 +347,10 @@ std::vector<ClassStmt *> SimplifyVisitor::parseBaseClasses(
nGenerics, subs.size());
args.emplace_back(a.name, a.type, transformType(subs[si++], false),
Param::HiddenGeneric);
args_classes.emplace_back(asts.back()->name);
} else if (a.status == Param::HiddenGeneric) {
args.emplace_back(a);
args_classes.emplace_back(asts.back()->name);
}
if (a.status != Param::Normal) {
if (auto st = getStaticGeneric(a.type.get())) {
@ -376,12 +377,14 @@ std::vector<ClassStmt *> SimplifyVisitor::parseBaseClasses(
if (i)
name = format("{}#{}", name, i);
args.emplace_back(name, a.type, a.defaultValue);
args_classes.emplace_back(ast->name);
}
}
}
if (typeAst) {
if (!parentClasses.empty())
mro.push_back(parentClasses);
ctx->cache->classes[canonicalName].rtti = true;
ctx->cache->classes[canonicalName].mro = Cache::mergeC3(mro);
if (ctx->cache->classes[canonicalName].mro.empty()) {
E(Error::CLASS_BAD_MRO, getSrcInfo());
@ -423,8 +426,8 @@ SimplifyVisitor::autoDeduceMembers(ClassStmt *stmt, std::vector<Param> &args) {
auto varName = ctx->generateCanonicalName(format("T{}", ++i));
auto memberName = ctx->cache->rev(varName);
ctx->addType(memberName, varName, stmt->getSrcInfo())->generic = true;
args.emplace_back(Param{varName, N<IdExpr>("type"), nullptr, Param::Generic});
args.emplace_back(Param{m, N<IdExpr>(varName)});
args.emplace_back(varName, N<IdExpr>("type"), nullptr, Param::Generic);
args.emplace_back(m, N<IdExpr>(varName));
}
ctx->getBase()->deducedMembers = nullptr;
return {transformed, f};
@ -506,8 +509,7 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
std::vector<Param> args;
for (auto &a : allArgs)
if (!startswith(a.name, VAR_CLSID))
args.push_back(a);
args.push_back(a);
if (op == "new") {
// Classes: @internal def __new__() -> T
@ -515,9 +517,9 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
ret = typExpr->clone();
if (isRecord) {
for (auto &a : args)
fargs.emplace_back(
Param{a.name, clone(a.type),
a.defaultValue ? clone(a.defaultValue) : N<CallExpr>(clone(a.type))});
fargs.emplace_back(a.name, clone(a.type),
a.defaultValue ? clone(a.defaultValue)
: N<CallExpr>(clone(a.type)));
attr.set(Attr::Internal);
} else {
stmts.emplace_back(N<ReturnStmt>(
@ -527,17 +529,17 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// Classes: def __init__(self: T, a1: T1, ..., aN: TN) -> void:
// self.aI = aI ...
ret = I("NoneType");
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
for (auto &a : args) {
stmts.push_back(N<AssignStmt>(N<DotExpr>(I("self"), a.name), I(a.name)));
fargs.emplace_back(
Param{a.name, clone(a.type),
a.defaultValue ? clone(a.defaultValue) : N<CallExpr>(clone(a.type))});
fargs.emplace_back(a.name, clone(a.type),
a.defaultValue ? clone(a.defaultValue)
: N<CallExpr>(clone(a.type)));
}
} else if (op == "raw") {
// Classes: def __raw__(self: T) -> Ptr[byte]:
// return __internal__.class_raw(self)
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
ret = N<IndexExpr>(I("Ptr"), I("byte"));
stmts.emplace_back(N<ReturnStmt>(
N<CallExpr>(N<DotExpr>(I("__internal__"), "class_raw"), I("self"))));
@ -545,8 +547,8 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// Tuples: def __getitem__(self: T, index: int) -> T1:
// return __internal__.tuple_getitem[T, T1](self, index)
// (error during a realizeFunc() method if T is a heterogeneous tuple)
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"index", I("int")});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("index", I("int"));
ret = !args.empty() ? clone(args[0].type) : I("NoneType");
stmts.emplace_back(N<ReturnStmt>(
N<CallExpr>(N<DotExpr>(I("__internal__"), "tuple_getitem"), I("self"),
@ -555,7 +557,7 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// Tuples: def __iter__(self: T) -> Generator[T]:
// yield self.aI ...
// (error during a realizeFunc() method if T is a heterogeneous tuple)
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
ret = N<IndexExpr>(I("Generator"), !args.empty() ? clone(args[0].type) : I("int"));
for (auto &a : args)
stmts.emplace_back(N<YieldStmt>(N<DotExpr>("self", a.name)));
@ -566,8 +568,8 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// Tuples: def __contains__(self: T, what) -> bool:
// if isinstance(what, T1): if what == self.a1: return True ...
// return False
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"what", nullptr});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("what", nullptr);
ret = I("bool");
for (auto &a : args)
stmts.push_back(N<IfStmt>(N<CallExpr>(I("isinstance"), I("what"), clone(a.type)),
@ -579,8 +581,8 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// def __eq__(self: T, other: T) -> bool:
// if not self.arg1.__eq__(other.arg1): return False ...
// return True
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"other", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("other", typExpr->clone());
ret = I("bool");
for (auto &a : args)
stmts.push_back(N<IfStmt>(
@ -593,8 +595,8 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// def __ne__(self: T, other: T) -> bool:
// if self.arg1.__ne__(other.arg1): return True ...
// return False
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"other", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("other", typExpr->clone());
ret = I("bool");
for (auto &a : args)
stmts.emplace_back(
@ -608,8 +610,8 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// elif self.arg1.__eq__(other.arg1):
// ... (arg2, ...) ...
// return False
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"other", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("other", typExpr->clone());
ret = I("bool");
std::vector<StmtPtr> *v = &stmts;
for (size_t i = 0; i + 1 < args.size(); i++) {
@ -638,8 +640,8 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// elif self.arg1.__eq__(other.arg1):
// ... (arg2, ...) ...
// return True
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"other", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("other", typExpr->clone());
ret = I("bool");
std::vector<StmtPtr> *v = &stmts;
for (size_t i = 0; i + 1 < args.size(); i++) {
@ -669,7 +671,7 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// seed ^ ((self.arg1.__hash__() + 2654435769) + ((seed << 6) + (seed >> 2)))
// ) ...
// return seed
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
ret = I("int");
stmts.emplace_back(N<AssignStmt>(I("seed"), N<IntExpr>(0)));
for (auto &a : args)
@ -688,8 +690,8 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
} else if (op == "pickle") {
// def __pickle__(self: T, dest: Ptr[byte]) -> void:
// self.arg1.__pickle__(dest) ...
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"dest", N<IndexExpr>(I("Ptr"), I("byte"))});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("dest", N<IndexExpr>(I("Ptr"), I("byte")));
ret = I("NoneType");
for (auto &a : args)
stmts.emplace_back(N<ExprStmt>(N<CallExpr>(
@ -697,7 +699,7 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
} else if (op == "unpickle") {
// def __unpickle__(src: Ptr[byte]) -> T:
// return T(T1.__unpickle__(src),...)
fargs.emplace_back(Param{"src", N<IndexExpr>(I("Ptr"), I("byte"))});
fargs.emplace_back("src", N<IndexExpr>(I("Ptr"), I("byte")));
ret = typExpr->clone();
std::vector<ExprPtr> ar;
ar.reserve(args.size());
@ -707,7 +709,7 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
} else if (op == "len") {
// def __len__(self: T) -> int:
// return N (number of args)
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
ret = I("int");
stmts.emplace_back(N<ReturnStmt>(N<IntExpr>(args.size())));
} else if (op == "to_py") {
@ -715,7 +717,7 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// o = pyobj._tuple_new(N) (number of args)
// pyobj._tuple_set(o, 1, self.arg1.__to_py__()) ...
// return o
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
ret = I("cobj");
stmts.emplace_back(
N<AssignStmt>(I("o"), N<CallExpr>(N<DotExpr>(I("pyobj"), "_tuple_new"),
@ -728,7 +730,7 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
} else if (op == "from_py") {
// def __from_py__(src: cobj) -> T:
// return T(T1.__from_py__(pyobj._tuple_get(src, 1)), ...)
fargs.emplace_back(Param{"src", I("cobj")});
fargs.emplace_back("src", I("cobj"));
ret = typExpr->clone();
std::vector<ExprPtr> ar;
ar.reserve(args.size());
@ -740,23 +742,23 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
} else if (op == "to_gpu") {
// def __to_gpu__(self: T, cache) -> T:
// return __internal__.class_to_gpu(self, cache)
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"cache"});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("cache");
ret = typExpr->clone();
stmts.emplace_back(N<ReturnStmt>(N<CallExpr>(
N<DotExpr>(I("__internal__"), "class_to_gpu"), I("self"), I("cache"))));
} else if (op == "from_gpu") {
// def __from_gpu__(self: T, other: T) -> None:
// __internal__.class_from_gpu(self, other)
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"other", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("other", typExpr->clone());
ret = I("NoneType");
stmts.emplace_back(N<ExprStmt>(N<CallExpr>(
N<DotExpr>(I("__internal__"), "class_from_gpu"), I("self"), I("other"))));
} else if (op == "from_gpu_new") {
// def __from_gpu_new__(other: T) -> T:
// return __internal__.class_from_gpu_new(other)
fargs.emplace_back(Param{"other", typExpr->clone()});
fargs.emplace_back("other", typExpr->clone());
ret = typExpr->clone();
stmts.emplace_back(N<ReturnStmt>(
N<CallExpr>(N<DotExpr>(I("__internal__"), "class_from_gpu_new"), I("other"))));
@ -767,7 +769,7 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// a.__setitem__(0, self.arg1.__repr__()) ...
// n.__setitem__(0, "arg1") ... (if not a Tuple.N; otherwise "")
// return __internal__.tuple_str(a.ptr, n.ptr, N)
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
ret = I("str");
if (!args.empty()) {
stmts.emplace_back(
@ -798,7 +800,7 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
// d = List[str](N)
// d.append('arg1') ...
// return d
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back("self", typExpr->clone());
stmts.emplace_back(
N<AssignStmt>(I("d"), N<CallExpr>(N<IndexExpr>(I("List"), I("str")),
N<IntExpr>(args.size()))));
@ -809,15 +811,15 @@ StmtPtr SimplifyVisitor::codegenMagic(const std::string &op, const ExprPtr &typE
} else if (op == "add") {
// def __add__(self, tup):
// return __internal__.tuple_add(self, tup)
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"tup", nullptr});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("tup", nullptr);
stmts.emplace_back(N<ReturnStmt>(
N<CallExpr>(N<DotExpr>(I("__internal__"), "tuple_add"), I("self"), I("tup"))));
} else if (op == "mul") {
// def __mul__(self, i: Static[int]):
// return __internal__.tuple_add(self, tup)
fargs.emplace_back(Param{"self", typExpr->clone()});
fargs.emplace_back(Param{"i", N<IndexExpr>(I("Static"), I("int"))});
fargs.emplace_back("self", typExpr->clone());
fargs.emplace_back("i", N<IndexExpr>(I("Static"), I("int")));
stmts.emplace_back(N<ReturnStmt>(
N<CallExpr>(N<DotExpr>(I("__internal__"), "tuple_mul"), I("self"), I("i"))));
} else if (op == "tuplesize") {

View File

@ -176,7 +176,8 @@ private: // Node simplification rules
/* Classes (class.cpp) */
void visit(ClassStmt *) override;
std::vector<ClassStmt *> parseBaseClasses(std::vector<ExprPtr> &,
std::vector<Param> &, const Attr &,
std::vector<Param> &,
std::vector<std::string> &, const Attr &,
const std::string &,
const ExprPtr & = nullptr);
std::pair<StmtPtr, FunctionStmt *> autoDeduceMembers(ClassStmt *,

View File

@ -194,12 +194,10 @@ ExprPtr TypecheckVisitor::transformDot(DotExpr *expr,
if (args) {
unify(expr->type, ctx->instantiate(bestMethod, typ));
// Handle virtual calls
auto clsidName = format("{}.{}", VAR_CLSID, typ->name);
// A function is deemed virtual if it is marked as such and if a base class has a
// vtable
// A function is deemed virtual if it is marked as such and
// if a base class has a RTTI
bool isVirtual = in(ctx->cache->classes[typ->name].virtuals, expr->member);
isVirtual &= ctx->findMember(typ->name, clsidName) != nullptr;
isVirtual &= ctx->cache->classes[typ->name].rtti;
isVirtual &= !expr->expr->isType();
if (isVirtual && !bestMethod->ast->attributes.has(Attr::StaticMethod) &&
!bestMethod->ast->attributes.has(Attr::Property)) {
@ -217,12 +215,14 @@ ExprPtr TypecheckVisitor::transformDot(DotExpr *expr,
NT<IdExpr>("Function"),
std::vector<ExprPtr>{NT<InstantiateExpr>(NT<IdExpr>(name), ids),
NT<IdExpr>(fn->getRetType()->realizedName())});
// Function[Tuple[TArg1, TArg2, ...],
// TRet](__vtables__[expr.__id__][T[VIRTUAL_ID]])
// Function[Tuple[TArg1, TArg2, ...],TRet](
// __internal__.class_get_rtti_vtable(expr)[T[VIRTUAL_ID]]
// )
auto e = N<CallExpr>(
fnType, N<IndexExpr>(N<IndexExpr>(N<IdExpr>("__vtables__"),
N<DotExpr>(expr->expr, clsidName)),
N<IntExpr>(vid)));
fnType,
N<IndexExpr>(N<CallExpr>(N<IdExpr>("__internal__.class_get_rtti_vtable:0"),
expr->expr),
N<IntExpr>(vid)));
return transform(e);
}
}

View File

@ -569,6 +569,8 @@ std::pair<bool, ExprPtr> TypecheckVisitor::transformSpecialCall(CallExpr *expr)
return {true, transformRealizedFn(expr)};
} else if (val == "std.internal.static.static_print") {
return {false, transformStaticPrintFn(expr)};
} else if (val == "__has_rtti__") {
return {true, transformHasRttiFn(expr)};
} else {
return transformInternalStaticFn(expr);
}
@ -644,7 +646,7 @@ ExprPtr TypecheckVisitor::transformSuper() {
auto typExpr = N<IdExpr>(superTyp->name);
typExpr->setType(superTyp);
return transform(N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "class_super"),
self, typExpr));
self, typExpr, N<IntExpr>(1)));
}
auto name = cands.front(); // the first inherited type
@ -659,7 +661,7 @@ ExprPtr TypecheckVisitor::transformSuper() {
e->type = unify(superTyp, e->type); // see super_tuple test for this line
return e;
} else {
// Case: reference types. Return `__internal__.to_class_ptr(self.__raw__(), T)`
// Case: reference types. Return `__internal__.class_super(self, T)`
auto self = N<IdExpr>(funcTyp->ast->args[0].name);
self->type = typ;
return castToSuperClass(self, superTyp);
@ -945,6 +947,18 @@ ExprPtr TypecheckVisitor::transformStaticPrintFn(CallExpr *expr) {
return nullptr;
}
/// Transform __has_rtti__ to a static boolean that indicates RTTI status of a type.
ExprPtr TypecheckVisitor::transformHasRttiFn(CallExpr *expr) {
expr->staticValue.type = StaticValue::INT;
auto funcTyp = expr->expr->type->getFunc();
auto t = funcTyp->funcGenerics[0].type->getClass();
if (!t)
return nullptr;
auto c = in(ctx->cache->classes, t->name);
seqassert(c, "bad class {}", t->name);
return transform(N<BoolExpr>(const_cast<Cache::Class *>(c)->rtti));
}
// Transform internal.static calls
std::pair<bool, ExprPtr> TypecheckVisitor::transformInternalStaticFn(CallExpr *expr) {
if (expr->expr->isId("std.internal.static.fn_can_call")) {

View File

@ -396,19 +396,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_init_vtables:0";
// def class_init_vtables():
// return __internal__.class_make_n_vtables(<NUM_REALIZATIONS> + 1)
auto &initAllVT = ctx->cache->functions[rep];
auto suite = N<SuiteStmt>(N<ReturnStmt>(N<CallExpr>(
N<IdExpr>("__internal__.class_make_n_vtables:0"), N<IdExpr>("__vtable_size__"))));
initAllVT.ast->suite = suite;
auto typ = initAllVT.realizations.begin()->second->type;
LOG_REALIZE("[poly] {} : {}", typ, *suite);
typ->ast = initAllVT.ast.get();
auto fx = realizeFunc(typ.get(), true);
rep = "__internal__.class_populate_vtables:0";
auto rep = "__internal__.class_populate_vtables:0";
// def class_populate_vtables(p):
// for real in <REALIZATIONS>:
// if real.vtables:
@ -417,7 +405,7 @@ StmtPtr TypecheckVisitor::prepareVTables() {
// for f in real.vtables:
// p[real.ID].__setitem__(f.ID, Function[<TYPE_F>](f).__raw__())
auto &initFn = ctx->cache->functions[rep];
suite = N<SuiteStmt>();
auto suite = N<SuiteStmt>();
for (auto &[_, cls] : ctx->cache->classes) {
for (auto &[r, real] : cls.realizations) {
size_t vtSz = 0;
@ -470,41 +458,15 @@ StmtPtr TypecheckVisitor::prepareVTables() {
}
}
initFn.ast->suite = suite;
typ = initFn.realizations.begin()->second->type;
auto typ = initFn.realizations.begin()->second->type;
LOG_REALIZE("[poly] {} : {}", typ, suite->toString(2));
typ->ast = initFn.ast.get();
realizeFunc(typ.get(), true);
rep = "__internal__.class_set_obj_vtable:0";
// def class_set_obj_vtable(pf):
// pf.__vtable__ = __vtables__[pf.__vtable_id___]
auto &initObjFns = ctx->cache->functions[rep];
auto oldAst = initObjFns.ast;
for (auto &[_, real] : initObjFns.realizations) {
auto t = real->type;
auto clsTyp = t->getArgTypes()[0]->getClass();
auto varName = initObjFns.ast->args[0].name;
const auto &fields = ctx->cache->classes[clsTyp->name].fields;
auto suite = N<SuiteStmt>();
for (auto &f : fields)
if (startswith(f.name, VAR_CLSID)) {
suite->stmts.push_back(N<AssignMemberStmt>(
N<IdExpr>(varName), f.name,
N<DotExpr>(N<IdExpr>(clsTyp->realizedName()), "__id__")));
}
LOG_REALIZE("[poly] {} : {}", t, *suite);
initObjFns.ast->suite = suite;
t->ast = initObjFns.ast.get();
realizeFunc(t.get(), true);
}
initObjFns.ast = oldAst;
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__
oldAst = initDist.ast;
auto oldAst = initDist.ast;
for (auto &[_, real] : initDist.realizations) {
auto t = real->type;
auto baseTyp = t->funcGenerics[0].type->getClass();
@ -514,7 +476,7 @@ StmtPtr TypecheckVisitor::prepareVTables() {
auto types = std::vector<ExprPtr>{};
auto found = false;
for (auto &f : fields) {
if (endswith(f.name, format(".{}", baseTyp->name))) {
if (f.baseClass == baseTyp->name) {
found = true;
break;
} else {
@ -621,21 +583,16 @@ size_t TypecheckVisitor::getRealizationID(types::ClassType *cp, types::FuncType
// <DERIVED>), <DERIVED>
// ), <ARGS...>)
std::vector<Param> fnArgs;
fnArgs.push_back(
Param{fp->ast->args[0].name, N<IdExpr>(cp->realizedName()), nullptr});
fnArgs.emplace_back(fp->ast->args[0].name, N<IdExpr>(cp->realizedName()),
nullptr);
for (size_t i = 1; i < args.size(); i++)
fnArgs.push_back(Param{fp->ast->args[i].name,
N<IdExpr>(args[i]->realizedName()), nullptr});
fnArgs.emplace_back(fp->ast->args[i].name, N<IdExpr>(args[i]->realizedName()),
nullptr);
std::vector<ExprPtr> callArgs;
callArgs.emplace_back(N<CallExpr>(
N<IdExpr>("__internal__.to_class_ptr:0"),
N<BinaryExpr>(
N<CallExpr>(N<DotExpr>(N<IdExpr>(fp->ast->args[0].name), "__raw__")),
"-",
N<CallExpr>(N<IdExpr>("__internal__.class_base_derived_dist:0"),
N<IdExpr>(cp->realizedName()),
N<IdExpr>(real->type->realizedName()))),
NT<IdExpr>(real->type->realizedName())));
callArgs.emplace_back(
N<CallExpr>(N<IdExpr>("__internal__.class_base_to_derived:0"),
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++)
callArgs.emplace_back(N<IdExpr>(fp->ast->args[i].name));
auto thunkAst = N<FunctionStmt>(

View File

@ -451,23 +451,11 @@ ExprPtr TypecheckVisitor::castToSuperClass(ExprPtr expr, ClassTypePtr superTyp,
ctx->instantiate(parentField.type, superTyp));
}
}
realize(superTyp);
auto typExpr = N<IdExpr>(superTyp->name);
typExpr->setType(superTyp);
// `dist = expr.__raw__()`
ExprPtr dist = N<CallExpr>(N<DotExpr>(expr, "__raw__"));
if (isVirtual) {
// Virtual inheritance: `dist += class_base_derived_dist(super, type(expr))`
dist =
N<BinaryExpr>(dist, "+",
N<CallExpr>(N<IdExpr>("__internal__.class_base_derived_dist:0"),
N<IdExpr>(superTyp->realizedName()),
N<CallExpr>(N<IdExpr>("type"), expr)));
}
realize(superTyp);
// No inheritance: `__internal__.to_class_ptr(dist, T)`
return transform(N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "to_class_ptr"),
dist, typExpr));
return transform(
N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "class_super"), expr, typExpr));
}
/// Unpack a Tuple or KwTuple expression into (name, type) vector.

View File

@ -145,6 +145,7 @@ private: // Node typechecking rules
ExprPtr transformTypeFn(CallExpr *expr);
ExprPtr transformRealizedFn(CallExpr *expr);
ExprPtr transformStaticPrintFn(CallExpr *expr);
ExprPtr transformHasRttiFn(CallExpr *expr);
std::pair<bool, ExprPtr> transformInternalStaticFn(CallExpr *expr);
std::vector<types::ClassTypePtr> getSuperTypes(const types::ClassTypePtr &cls);
void addFunctionGenerics(const types::FuncType *t);

View File

@ -196,3 +196,6 @@ def __realized__(fn, args):
def statictuple(*args):
return args
def __has_rtti__(T: type):
pass

View File

@ -1,37 +1,81 @@
# Copyright (C) 2022-2023 Exaloop Inc. <https://exaloop.io>
from internal.gc import (
alloc, alloc_atomic, alloc_uncollectable, alloc_atomic_uncollectable,
free, atomic, sizeof, register_finalizer
alloc, alloc_atomic, alloc_atomic_uncollectable,
free, sizeof, register_finalizer
)
__vtables__ = Ptr[Ptr[cobj]]()
__vtable_size__ = 0
@extend
class __internal__:
def class_init_vtables():
"""
Create a global vtable.
"""
sz = __vtable_size__ + 1
__vtables__ = Ptr[Ptr[cobj]](alloc_atomic_uncollectable(sz * sizeof(Ptr[cobj])))
__internal__.class_populate_vtables(__vtables__)
@__internal__
class RTTI:
id: int
@extend
class __internal__:
def yield_final(val):
pass
def yield_in_no_suspend(T: type) -> T:
pass
@pure
@derives
@llvm
def class_raw(obj) -> Ptr[byte]:
def class_raw_ptr(obj) -> Ptr[byte]:
ret ptr %obj
@pure
@derives
@llvm
def class_raw_rtti_ptr(obj) -> Ptr[byte]:
%0 = extractvalue {ptr, ptr} %obj, i64 0
ret ptr %0
@llvm
def class_raw_rtti_rtti(obj: T, T: type) -> Ptr[byte]:
%0 = extractvalue {ptr, ptr} %obj, i64 1
ret ptr %0
@pure
@derives
def class_raw(obj) -> Ptr[byte]:
if __has_rtti__(type(obj)):
return __internal__.class_raw_rtti_ptr(obj)
else:
return __internal__.class_raw_ptr(obj)
def class_alloc(T: type) -> T:
"""Allocates a new reference (class) type"""
sz = sizeof(tuple(T))
p = alloc_atomic(sz) if T.__contents_atomic__ else alloc(sz)
register_finalizer(p)
return __internal__.to_class_ptr(p, T)
if __has_rtti__(T):
obj = alloc_atomic(sz) if T.__contents_atomic__ else alloc(sz)
register_finalizer(obj)
rsz = sizeof(tuple(T))
rtti = alloc_atomic(rsz) if RTTI.__contents_atomic__ else alloc(rsz)
__internal__.to_class_ptr(rtti, RTTI).id = T.__id__
return __internal__.to_class_ptr_rtti((obj, rtti), T)
else:
obj = alloc_atomic(sz) if T.__contents_atomic__ else alloc(sz)
register_finalizer(obj)
return __internal__.to_class_ptr(obj, T)
def class_new(T: type) -> T:
def class_new(T: type):
"""Create a new reference (class) type"""
pf = __internal__.class_alloc(T)
__internal__.class_set_obj_vtable(pf)
return pf
p = __internal__.class_alloc(T)
return p
def class_ctr(T: type, *args, **kwargs) -> T:
"""Shorthand for `t = T.__new__(); t.__init__(*args, **kwargs); t`"""
@ -45,19 +89,12 @@ class __internal__:
"""
pass
def class_init_vtables() -> Ptr[Ptr[cobj]]:
"""
Create a global vtable. Compiler generated.
Corresponds to:
return __internal__.class_make_n_vtables(<number of class realizations>)
"""
pass
def class_make_n_vtables(sz: int) -> Ptr[Ptr[cobj]]:
"""Create a global vtable."""
p = Ptr[Ptr[cobj]](alloc_atomic_uncollectable(sz * sizeof(Ptr[cobj])))
__internal__.class_populate_vtables(p)
return p
def class_get_rtti_vtable(obj) -> Ptr[byte]:
if not __has_rtti__(type(obj)):
compile_error("class is not polymorphic")
rtti = __internal__.class_raw_rtti_rtti(obj)
id = __internal__.to_class_ptr(rtti, RTTI).id
return __vtables__[id]
def class_populate_vtables(p: Ptr[Ptr[cobj]]) -> None:
"""
@ -86,17 +123,32 @@ class __internal__:
"""Calculates the byte distance of base class B and derived class D. Compiler generated."""
return 0
@inline
def class_base_to_derived(b: B, B: type, D: type) -> D:
if not (__has_rtti__(D) and __has_rtti__(B)):
compile_error("classes are not polymorphic")
off = __internal__.class_base_derived_dist(B, D)
ptr = __internal__.class_raw_rtti_ptr(b) - off
pr = __internal__.class_raw_rtti_rtti(b)
return __internal__.to_class_ptr_rtti((ptr, pr), D)
def class_copy(obj: T, T: type) -> T:
p = __internal__.class_alloc(T)
str.memcpy(p.__raw__(), obj.__raw__(), sizeof(tuple(T)))
return p
def class_super(obj: D, B: type, D: type) -> B:
pf = __internal__.to_class_ptr(obj.__raw__() + __internal__.class_base_derived_dist(B, D), B)
pn = __internal__.class_copy(pf)
# Replace vtables
__internal__.class_set_obj_vtable(pn) # replace vtables to point to its vtables!
return pn
def class_super(obj: D, B: type, D: type, change_rtti: Static[int] = 0) -> B:
if not __has_rtti__(D): # static inheritance
return __internal__.to_class_ptr(obj.__raw__(), B)
else:
if not __has_rtti__(B):
compile_error("classes are not polymorphic")
off = __internal__.class_base_derived_dist(B, D)
ptr = __internal__.class_raw_rtti_ptr(obj) + off
pr = __internal__.class_raw_rtti_rtti(obj)
if change_rtti:
__internal__.to_class_ptr(pr, RTTI).id = B.__id__
return __internal__.to_class_ptr_rtti((ptr, pr), B)
# Unions
@ -242,6 +294,14 @@ class __internal__:
def opt_ref_new(T: type) -> Optional[T]:
ret ptr null
@pure
def opt_ref_new_rtti(T: type) -> Optional[T]:
obj = Ptr[byte]()
rsz = sizeof(tuple(T))
rtti = alloc_atomic(rsz) if RTTI.__contents_atomic__ else alloc(rsz)
__internal__.to_class_ptr(rtti, RTTI).id = T.__id__
return __internal__.opt_ref_new_arg(__internal__.to_class_ptr_rtti((obj, rtti), T))
@pure
@derives
@llvm
@ -255,6 +315,12 @@ class __internal__:
def opt_ref_new_arg(what: T, T: type) -> Optional[T]:
ret ptr %what
@pure
@derives
@llvm
def opt_ref_new_arg_rtti(what: T, T: type) -> Optional[T]:
ret { ptr, ptr } %what
@pure
@llvm
def opt_tuple_bool(what: Optional[T], T: type) -> bool:
@ -269,6 +335,10 @@ class __internal__:
%1 = zext i1 %0 to i8
ret i8 %1
@pure
def opt_ref_bool_rtti(what: Optional[T], T: type) -> bool:
return __internal__.class_raw_rtti_ptr() != cobj()
@pure
@derives
@llvm
@ -282,12 +352,24 @@ class __internal__:
def opt_ref_invert(what: Optional[T], T: type) -> T:
ret ptr %what
@pure
@derives
@llvm
def opt_ref_invert_rtti(what: Optional[T], T: type) -> T:
ret { ptr, ptr } %what
@pure
@derives
@llvm
def to_class_ptr(p: Ptr[byte], T: type) -> T:
ret ptr %p
@pure
@derives
@llvm
def to_class_ptr_rtti(p: Tuple[Ptr[byte], Ptr[byte]], T: type) -> T:
ret { ptr, ptr } %p
def _tuple_offsetof(x, field: Static[int]) -> int:
@pure
@llvm
@ -478,9 +560,6 @@ class Function:
def __call__(self, *args) -> TR:
return Function.__call_internal__(self, args)
__vtables__ = __internal__.class_init_vtables()
def _____(): __vtables__ # make it global!
@tuple
class PyObject:
@ -492,3 +571,6 @@ class PyObject:
class PyWrapper[T]:
head: PyObject
data: T
__internal__.class_init_vtables()

View File

@ -2,6 +2,7 @@
import os
from gc import atomic, alloc_uncollectable
from internal.dlopen import *
# general

View File

@ -5,24 +5,32 @@ class Optional:
def __new__() -> Optional[T]:
if isinstance(T, ByVal):
return __internal__.opt_tuple_new(T)
elif __has_rtti__(T):
return __internal__.opt_ref_new_rtti(T)
else:
return __internal__.opt_ref_new(T)
def __new__(what: T) -> Optional[T]:
if isinstance(T, ByVal):
return __internal__.opt_tuple_new_arg(what, T)
elif __has_rtti__(T):
return __internal__.opt_ref_new_arg_rtti(what, T)
else:
return __internal__.opt_ref_new_arg(what, T)
def __has__(self) -> bool:
if isinstance(T, ByVal):
return __internal__.opt_tuple_bool(self, T)
elif __has_rtti__(T):
return __internal__.opt_ref_bool_rtti(T)
else:
return __internal__.opt_ref_bool(self, T)
def __val__(self) -> T:
if isinstance(T, ByVal):
return __internal__.opt_tuple_invert(self, T)
elif __has_rtti__(T):
return __internal__.opt_ref_invert_rtti(T)
else:
return __internal__.opt_ref_invert(self, T)