Implement Python class method declarations

This commit is contained in:
Shunsuke Shibayama 2022-09-30 18:21:18 +09:00
parent e4c61392d2
commit 33edcd2e1c
7 changed files with 141 additions and 4 deletions

View file

@ -1455,7 +1455,6 @@ impl CodeGenerator {
log!(info "entered {}", fn_name!());
let class = obj.ref_t().name(); // これは必ずmethodのあるクラスになっている
let uniq_obj_name = obj.__name__().map(Str::rc);
log!("{class} {method_name}");
if &method_name.inspect()[..] == "update!" {
return self.emit_call_update(obj, args);
} else if is_fake_method(&class, method_name.inspect()) {

View file

@ -127,6 +127,43 @@ impl Context {
})
}
pub fn get_mut_singular_ctx_from_ident(
&mut self,
ident: &ast::Identifier,
namespace: &Str,
) -> SingleTyCheckResult<&mut Context> {
let err = TyCheckError::no_var_error(
self.cfg.input.clone(),
line!() as usize,
ident.loc(),
namespace.into(),
ident.inspect(),
self.get_similar_name(ident.inspect()),
);
self.get_mut_type(ident.inspect())
.map(|(_, ctx)| ctx)
.ok_or(err)
}
pub fn get_mut_singular_ctx(
&mut self,
obj: &ast::Expr,
namespace: &Str,
) -> SingleTyCheckResult<&mut Context> {
match obj {
ast::Expr::Accessor(ast::Accessor::Ident(ident)) => {
self.get_mut_singular_ctx_from_ident(ident, namespace)
}
ast::Expr::Accessor(ast::Accessor::Attr(attr)) => {
// REVIEW: 両方singularとは限らない?
let ctx = self.get_mut_singular_ctx(&attr.obj, namespace)?;
let attr = ast::Expr::Accessor(ast::Accessor::Ident(attr.ident.clone()));
ctx.get_mut_singular_ctx(&attr, namespace)
}
_ => todo!(),
}
}
fn get_match_call_t(
&self,
pos_args: &[hir::PosArg],
@ -1567,6 +1604,16 @@ impl Context {
}
}
fn get_mut_type(&mut self, name: &str) -> Option<(&Type, &mut Context)> {
if let Some((t, ctx)) = self.mono_types.get_mut(name) {
Some((t, ctx))
} else if let Some((t, ctx)) = self.poly_types.get_mut(name) {
Some((t, ctx))
} else {
None
}
}
fn rec_get_method_traits(&self, name: &Identifier) -> SingleTyCheckResult<&Type> {
if let Some(candidates) = self.method_traits.get(name.inspect()) {
let first_t = candidates.first().unwrap();

View file

@ -628,7 +628,7 @@ impl Context {
}
}
fn register_gen_type(&mut self, ident: &Identifier, gen: GenTypeObj) {
pub(crate) fn register_gen_type(&mut self, ident: &Identifier, gen: GenTypeObj) {
match gen.kind {
TypeKind::Class => {
if gen.t.is_monomorphic() {

View file

@ -20,7 +20,7 @@ use erg_type::constructors::{
};
use erg_type::free::Constraint;
use erg_type::typaram::TyParam;
use erg_type::value::{GenTypeObj, TypeObj, ValueObj};
use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, Type};
use crate::context::{ClassDefType, Context, ContextKind, RegistrationMode};
@ -32,7 +32,7 @@ use crate::hir;
use crate::hir::HIR;
use crate::mod_cache::SharedModuleCache;
use crate::reorder::Reorderer;
use crate::varinfo::VarKind;
use crate::varinfo::{Mutability, VarInfo, VarKind};
use Visibility::*;
/// Singleton that checks types of an AST, and convert (lower) it into a HIR
@ -1116,6 +1116,27 @@ impl ASTLowerer {
res
}
fn fake_lower_obj(&self, obj: ast::Expr) -> LowerResult<hir::Expr> {
match obj {
ast::Expr::Accessor(ast::Accessor::Ident(ident)) => {
let acc = hir::Accessor::Ident(hir::Identifier::bare(ident.dot, ident.name));
Ok(hir::Expr::Accessor(acc))
}
ast::Expr::Accessor(ast::Accessor::Attr(attr)) => {
let obj = self.fake_lower_obj(*attr.obj)?;
let ident = hir::Identifier::bare(attr.ident.dot, attr.ident.name);
let acc = hir::Accessor::attr(obj, ident, Type::Uninited);
Ok(hir::Expr::Accessor(acc))
}
other => Err(LowerErrors::from(LowerError::declare_error(
self.cfg.input.clone(),
line!() as usize,
other.loc(),
self.ctx.caused_by(),
))),
}
}
fn declare_type(&mut self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> {
log!(info "entered {}({})", fn_name!(), tasc);
match *tasc.expr {
@ -1126,17 +1147,75 @@ impl ASTLowerer {
&mut None,
RegistrationMode::Normal,
)?;
if ident.is_const() {
let vi = VarInfo::new(
t.clone(),
Mutability::Const,
ident.vis(),
VarKind::Declared,
None,
);
self.ctx.decls.insert(ident.name.clone(), vi);
}
self.ctx.assign_var_sig(
&ast::VarSignature::new(ast::VarPattern::Ident(ident.clone()), None),
&t,
ast::DefId(0),
)?;
match t {
Type::Class => {
let ty_obj = GenTypeObj::new(
TypeKind::Class,
mono(self.ctx.path(), ident.inspect()),
TypeObj::Builtin(Type::Uninited),
None,
None,
);
self.ctx.register_gen_type(&ident, ty_obj);
}
Type::Trait => {
let ty_obj = GenTypeObj::new(
TypeKind::Trait,
mono(self.ctx.path(), ident.inspect()),
TypeObj::Builtin(Type::Uninited),
None,
None,
);
self.ctx.register_gen_type(&ident, ty_obj);
}
_ => {}
}
let ident = hir::Identifier::new(ident.dot, ident.name, None, t);
Ok(hir::TypeAscription::new(
hir::Expr::Accessor(hir::Accessor::Ident(ident)),
tasc.t_spec,
))
}
ast::Expr::Accessor(ast::Accessor::Attr(attr)) => {
let t = self.ctx.instantiate_typespec(
&tasc.t_spec,
None,
&mut None,
RegistrationMode::Normal,
)?;
let namespace = self.ctx.name.clone();
let ctx = self
.ctx
.get_mut_singular_ctx(attr.obj.as_ref(), &namespace)?;
ctx.assign_var_sig(
&ast::VarSignature::new(ast::VarPattern::Ident(attr.ident.clone()), None),
&t,
ast::DefId(0),
)?;
let obj = self.fake_lower_obj(*attr.obj)?;
let ident =
hir::Identifier::new(attr.ident.dot, attr.ident.name, None, Type::Uninited);
let attr = hir::Accessor::attr(obj, ident, t);
Ok(hir::TypeAscription::new(
hir::Expr::Accessor(attr),
tasc.t_spec,
))
}
other => Err(LowerErrors::from(LowerError::declare_error(
self.cfg.input.clone(),
line!() as usize,

View file

@ -1,2 +1,6 @@
.x: Int
.f: Int -> Int
.C: ClassType
.C.__call__: Int -> .C
.C.f: Int -> Int

View file

@ -1,2 +1,8 @@
x = 0
def f(x: int) -> int: return x + 1
class C:
def __init__(self, x: int) -> None:
self.x = x
def f(self, y: int) -> int:
return self.x + y

View file

@ -1,3 +1,5 @@
declare = pyimport "declare"
print! declare.f(declare.x + 1)
c = declare.C.__call__ 1
print! c.f(1)