feat: infer external class attributes types

This commit is contained in:
Shunsuke Shibayama 2023-03-16 02:19:30 +09:00
parent 5ed9306ee2
commit 59284b6ad5
4 changed files with 88 additions and 25 deletions

View file

@ -8,12 +8,12 @@ use erg_compiler::artifact::IncompleteArtifact;
use erg_compiler::erg_parser::ast::{
Accessor, Args, Array, ArrayTypeSpec, BinOp, Block, ClassAttr, ClassAttrs, ClassDef,
ConstAccessor, ConstArgs, ConstExpr, Decorator, Def, DefBody, DefId, DefaultParamSignature,
Dict, Dummy, Expr, Identifier, KeyValue, Lambda, LambdaSignature, Literal, Methods, Module,
NonDefaultParamSignature, NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple,
ParamPattern, Params, PosArg, PreDeclTypeSpec, ReDef, Record, RecordAttrs, Set, Signature,
SimpleTypeSpec, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec, TypeSpecWithOp,
UnaryOp, VarName, VarPattern, VarRecordAttr, VarRecordAttrs, VarRecordPattern, VarSignature,
VisModifierSpec,
Dict, Dummy, Expr, Identifier, KeyValue, KwArg, Lambda, LambdaSignature, Literal, Methods,
Module, NonDefaultParamSignature, NormalArray, NormalDict, NormalRecord, NormalSet,
NormalTuple, ParamPattern, Params, PosArg, PreDeclTypeSpec, ReDef, Record, RecordAttrs, Set,
Signature, SimpleTypeSpec, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec,
TypeSpecWithOp, UnaryOp, VarName, VarPattern, VarRecordAttr, VarRecordAttrs, VarRecordPattern,
VarSignature, VisModifierSpec,
};
use erg_compiler::erg_parser::desugar::Desugarer;
use erg_compiler::erg_parser::token::{Token, TokenKind, COLON, DOT, EQUAL};
@ -1231,7 +1231,10 @@ impl ASTConverter {
let classdef = if inherit {
// TODO: multiple inheritance
let pos_args = vec![PosArg::new(bases.remove(0))];
let args = Args::pos_only(pos_args, None);
let mut args = Args::pos_only(pos_args, None);
if let Some(rec @ Expr::Record(_)) = base_type {
args.push_kw(KwArg::new(Token::symbol("Additional"), None, rec));
}
let inherit_acc = Expr::Accessor(Accessor::Ident(
self.convert_ident("Inherit".to_string(), loc),
));

View file

@ -5,7 +5,8 @@ use erg_common::config::Input;
use erg_common::log;
use erg_compiler::context::register::PylyzerStatus;
use erg_compiler::hir::{Expr, HIR};
use erg_compiler::ty::HasType;
use erg_compiler::ty::value::{GenTypeObj, TypeObj};
use erg_compiler::ty::{HasType, Type};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CheckStatus {
@ -28,7 +29,7 @@ pub struct DeclFile {
}
fn escape_type(typ: String) -> String {
typ.replace('%', "Type_")
typ.replace('%', "Type_").replace("<module>", "")
}
pub fn gen_decl_er(input: &Input, hir: HIR, status: CheckStatus) -> DeclFile {
@ -45,28 +46,65 @@ pub fn gen_decl_er(input: &Input, hir: HIR, status: CheckStatus) -> DeclFile {
};
let mut code = format!("{status}\n");
for chunk in hir.module.into_iter() {
match chunk {
Expr::Def(def) => {
let name = def.sig.ident().inspect().replace('\0', "");
let typ = def.sig.ident().ref_t().to_string();
let typ = escape_type(typ);
let decl = format!(".{name}: {typ}");
code += &decl;
}
Expr::ClassDef(def) => {
let name = def.sig.ident().inspect().replace('\0', "");
let decl = format!(".{name}: ClassType");
code += &decl;
}
_ => {}
}
code.push('\n');
gen_chunk_decl("", chunk, &mut code);
}
log!("code:\n{code}");
let filename = input.unescaped_filename().replace(".py", ".d.er");
DeclFile { filename, code }
}
fn gen_chunk_decl(namespace: &str, chunk: Expr, code: &mut String) {
match chunk {
Expr::Def(def) => {
let name = def.sig.ident().inspect().replace('\0', "");
let typ = def.sig.ident().ref_t().to_string();
let typ = escape_type(typ);
let decl = format!("{namespace}.{name}: {typ}");
*code += &decl;
}
Expr::ClassDef(def) => {
let class_name = def.sig.ident().inspect().replace('\0', "");
let namespace = format!("{namespace}.{class_name}");
let decl = format!(".{class_name}: ClassType");
*code += &decl;
code.push('\n');
if let GenTypeObj::Subclass(class) = &def.obj {
let sup = class.sup.as_ref().typ().to_string();
let sup = escape_type(sup);
let decl = format!(".{class_name} <: {sup}\n");
*code += &decl;
}
if let Some(TypeObj::Builtin {
t: Type::Record(rec),
..
}) = def.obj.base_or_sup()
{
for (attr, t) in rec.iter() {
let typ = escape_type(t.to_string());
let decl = format!("{namespace}.{}: {typ}\n", attr.symbol);
*code += &decl;
}
}
if let Some(TypeObj::Builtin {
t: Type::Record(rec),
..
}) = def.obj.additional()
{
for (attr, t) in rec.iter() {
let typ = escape_type(t.to_string());
let decl = format!("{namespace}.{}: {typ}\n", attr.symbol);
*code += &decl;
}
}
for attr in def.methods.into_iter() {
gen_chunk_decl(&namespace, attr, code);
}
}
_ => {}
}
code.push('\n');
}
pub fn dump_decl_er(input: Input, hir: HIR, status: CheckStatus) {
let file = gen_decl_er(&input, hir, status);
let mut dir = input.dir();