Add isinstance support for inherited classes; Fix review issues

pull/10/head
Ibrahim Numanagić 2022-01-11 11:49:12 -08:00
parent 9dde5be88f
commit 47bea7017b
4 changed files with 113 additions and 3 deletions

View File

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

View File

@ -302,6 +302,8 @@ private:
const std::vector<CallExpr::Arg> &args);
ExprPtr transformSuper(const CallExpr *expr);
std::vector<types::ClassTypePtr> getSuperTypes(const types::ClassTypePtr &cls);
private:
types::TypePtr unify(types::TypePtr &a, const types::TypePtr &b,

View File

@ -1423,8 +1423,15 @@ std::pair<bool, ExprPtr> 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<BoolExpr>(unifyOK))};
auto hierarchy = getSuperTypes(typ->getClass());
for (auto &tx: hierarchy) {
auto unifyOK = tx->unify(t.get(), nullptr) >= 0;
if (unifyOK) {
return {true, transform(N<BoolExpr>(true))};
}
}
return {true, transform(N<BoolExpr>(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<ClassTypePtr> TypecheckVisitor::getSuperTypes(const ClassTypePtr &cls) {
std::vector<ClassTypePtr> 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

View File

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