mirror of https://github.com/exaloop/codon.git
Add isinstance support for inherited classes; Fix review issues
parent
9dde5be88f
commit
47bea7017b
codon/parser/visitors
simplify
typecheck
test/parser
|
@ -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)) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue