From 47bea7017bb4029c174c3d4071adace520eb5f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ibrahim=20Numanagic=CC=81?= Date: Tue, 11 Jan 2022 11:49:12 -0800 Subject: [PATCH] Add isinstance support for inherited classes; Fix review issues --- .../visitors/simplify/simplify_stmt.cpp | 1 + codon/parser/visitors/typecheck/typecheck.h | 2 + .../visitors/typecheck/typecheck_expr.cpp | 39 +++++++++- test/parser/typecheck_expr.codon | 74 +++++++++++++++++++ 4 files changed, 113 insertions(+), 3 deletions(-) diff --git a/codon/parser/visitors/simplify/simplify_stmt.cpp b/codon/parser/visitors/simplify/simplify_stmt.cpp index b7cb13ec..178fc12a 100644 --- a/codon/parser/visitors/simplify/simplify_stmt.cpp +++ b/codon/parser/visitors/simplify/simplify_stmt.cpp @@ -544,6 +544,7 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) { if (!typeAst && isClassMember && ia == 0 && a.name == "self") { typeAst = ctx->bases[ctx->bases.size() - 2].ast; attr.set(".changedSelf"); + attr.set(Attr::Method); } if (attr.has(Attr::C)) { diff --git a/codon/parser/visitors/typecheck/typecheck.h b/codon/parser/visitors/typecheck/typecheck.h index a8bfca92..91e0aa74 100644 --- a/codon/parser/visitors/typecheck/typecheck.h +++ b/codon/parser/visitors/typecheck/typecheck.h @@ -302,6 +302,8 @@ private: const std::vector &args); ExprPtr transformSuper(const CallExpr *expr); + std::vector getSuperTypes(const types::ClassTypePtr &cls); + private: types::TypePtr unify(types::TypePtr &a, const types::TypePtr &b, diff --git a/codon/parser/visitors/typecheck/typecheck_expr.cpp b/codon/parser/visitors/typecheck/typecheck_expr.cpp index 168431de..811f28a6 100644 --- a/codon/parser/visitors/typecheck/typecheck_expr.cpp +++ b/codon/parser/visitors/typecheck/typecheck_expr.cpp @@ -1423,8 +1423,15 @@ std::pair TypecheckVisitor::transformSpecialCall(CallExpr *expr) expr->args[1].value = transformType(expr->args[1].value, /*disableActivation*/ true); auto t = expr->args[1].value->type; - auto unifyOK = typ->unify(t.get(), nullptr) >= 0; - return {true, transform(N(unifyOK))}; + auto hierarchy = getSuperTypes(typ->getClass()); + + for (auto &tx: hierarchy) { + auto unifyOK = tx->unify(t.get(), nullptr) >= 0; + if (unifyOK) { + return {true, transform(N(true))}; + } + } + return {true, transform(N(false))}; } } } else if (val == "staticlen") { @@ -1956,7 +1963,7 @@ ExprPtr TypecheckVisitor::transformSuper(const CallExpr *expr) { if (ctx->bases.empty() || !ctx->bases.back().type) error("no parent classes available"); auto fptyp = ctx->bases.back().type->getFunc(); - if (!fptyp || fptyp->ast->hasAttr(Attr::Method)) + if (!fptyp || !fptyp->ast->hasAttr(Attr::Method)) error("no parent classes available"); if (fptyp->args.size() < 2) error("no parent classes available"); @@ -2008,5 +2015,31 @@ ExprPtr TypecheckVisitor::transformSuper(const CallExpr *expr) { } } +std::vector TypecheckVisitor::getSuperTypes(const ClassTypePtr &cls) { + std::vector result; + if (!cls) + return result; + result.push_back(cls); + int start = 0; + for (auto &cand: ctx->cache->classes[cls->name].parentClasses) { + auto name = cand.first; + int fields = cand.second; + auto val = ctx->find(name); + seqassert(val, "cannot find '{}'", name); + auto ftyp = ctx->instantiate(nullptr, val->type)->getClass(); + for (int i = start; i < fields; i++) { + auto t = ctx->cache->classes[cls->name].fields[i].type; + t = ctx->instantiate(nullptr, t, cls.get()); + auto ft = ctx->cache->classes[name].fields[i].type; + ft = ctx->instantiate(nullptr, ft, ftyp.get()); + unify(t, ft); + } + start += fields; + for (auto &t: getSuperTypes(ftyp)) + result.push_back(t); + } + return result; +} + } // namespace ast } // namespace codon diff --git a/test/parser/typecheck_expr.codon b/test/parser/typecheck_expr.codon index d2c99d1a..f28f1b87 100644 --- a/test/parser/typecheck_expr.codon +++ b/test/parser/typecheck_expr.codon @@ -600,6 +600,30 @@ print hasattr(int, "__getitem__") print hasattr([1, 2], "__getitem__", str) #: False +#%% isinstance_inheritance,barebones +class AX[T]: + a: T + def __init__(self, a: T): + self.a = a +class Side: + def __init__(self): + pass +class BX[T,U](AX[T], Side): + b: U + def __init__(self, a: T, b: U): + super().__init__(a) + self.b = b +class CX[T,U](BX[T,U]): + c: int + def __init__(self, a: T, b: U): + super().__init__(a, b) + self.c = 1 +c = CX('a', False) +print isinstance(c, CX), isinstance(c, BX), isinstance(c, AX), isinstance(c, Side) +#: True True True True +print isinstance(c, BX[str, bool]), isinstance(c, BX[str, str]), isinstance(c, AX[int]) +#: True False False + #%% staticlen_err,barebones print staticlen([1, 2]) #! List[int] is not a tuple type @@ -698,6 +722,56 @@ b = B() print b.foo() #: A:s print b.baz() #: A:s::6 +class AX[T]: + a: T + def __init__(self, a: T): + self.a = a + def foo(self): + return f'[AX:{self.a}]' +class BX[T,U](AX[T]): + b: U + def __init__(self, a: T, b: U): + print super().__class__ + super().__init__(a) + self.b = b + def foo(self): + return f'[BX:{super().foo()}:{self.b}]' +class CX[T,U](BX[T,U]): + c: int + def __init__(self, a: T, b: U): + print super().__class__ + super().__init__(a, b) + self.c = 1 + def foo(self): + return f'CX:{super().foo()}:{self.c}' +c = CX('a', False) +print c.__class__, c.foo() +#: BX[str,bool] +#: AX[str] +#: CX[str,bool] CX:[BX:[AX:a]:False]:1 + + +#%% super_tuple,barebones +@tuple +class A[T]: + a: T + x: int + def __new__(a: T) -> A[T]: + return (a, 1) + def foo(self): + return f'A:{self.a}' +@tuple +class B(A[str]): + b: int + def __new__() -> B: + return (*(A('s')), 6) + def baz(self): + return f'{super().foo()}::{self.b}' + +b = B() +print b.foo() #: A:s +print b.baz() #: A:s::6 + #%% super_error,barebones class A: