mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 12:24:45 +00:00
WIP: Impl DataPack type checking
This commit is contained in:
parent
e7898c094e
commit
263c43d74b
7 changed files with 119 additions and 58 deletions
|
@ -101,7 +101,7 @@ impl Context {
|
|||
let mut tv_ctx = TyVarContext::new(self.level, ctx.type_params_bounds(), self);
|
||||
let t = Self::instantiate_t(t, &mut tv_ctx);
|
||||
if let Some((_, root_ctx)) = self.poly_types.get_mut(&t.name()) {
|
||||
root_ctx.specializations.push((t, ctx));
|
||||
root_ctx.method_defs.push((t, ctx));
|
||||
} else {
|
||||
let name = VarName::from_str(t.name());
|
||||
self.locals
|
||||
|
|
|
@ -192,6 +192,7 @@ pub enum ContextKind {
|
|||
Func,
|
||||
Proc,
|
||||
Class,
|
||||
MethodDefs,
|
||||
Trait,
|
||||
StructuralTrait,
|
||||
Patch(Type),
|
||||
|
@ -230,8 +231,8 @@ pub struct Context {
|
|||
// patchによってsuper class/traitになったものはここに含まれない
|
||||
pub(crate) super_classes: Vec<Type>, // if self is a patch, means patch classes
|
||||
pub(crate) super_traits: Vec<Type>, // if self is not a trait, means implemented traits
|
||||
// specialized contexts, If self is a type
|
||||
pub(crate) specializations: Vec<(Type, Context)>,
|
||||
// method definitions, if the context is a type
|
||||
pub(crate) method_defs: Vec<(Type, Context)>,
|
||||
/// K: method name, V: impl patch
|
||||
/// Provided methods can switch implementations on a scope-by-scope basis
|
||||
/// K: メソッド名, V: それを実装するパッチたち
|
||||
|
@ -357,7 +358,7 @@ impl Context {
|
|||
outer: outer.map(Box::new),
|
||||
super_classes,
|
||||
super_traits,
|
||||
specializations: vec![],
|
||||
method_defs: vec![],
|
||||
const_param_defaults: Dict::default(),
|
||||
method_impl_patches: Dict::default(),
|
||||
trait_impls: Dict::default(),
|
||||
|
@ -539,7 +540,7 @@ impl Context {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn pop(&mut self) -> Result<(), TyCheckErrors> {
|
||||
pub(crate) fn pop(&mut self) -> Result<Context, TyCheckErrors> {
|
||||
let mut uninited_errs = TyCheckErrors::empty();
|
||||
for (name, vi) in self.decls.iter() {
|
||||
uninited_errs.push(TyCheckError::uninitialized_error(
|
||||
|
@ -551,12 +552,14 @@ impl Context {
|
|||
));
|
||||
}
|
||||
if let Some(parent) = &mut self.outer {
|
||||
*self = mem::take(parent);
|
||||
let parent = mem::take(parent);
|
||||
let ctx = mem::take(self);
|
||||
*self = *parent;
|
||||
log!(info "{}: current namespace: {}", fn_name!(), self.name);
|
||||
if !uninited_errs.is_empty() {
|
||||
Err(uninited_errs)
|
||||
} else {
|
||||
Ok(())
|
||||
Ok(ctx)
|
||||
}
|
||||
} else {
|
||||
Err(TyCheckErrors::from(TyCheckError::checker_bug(
|
||||
|
|
|
@ -328,13 +328,19 @@ impl Context {
|
|||
pub(crate) fn preregister(&mut self, block: &ast::Block) -> TyCheckResult<()> {
|
||||
for expr in block.iter() {
|
||||
if let ast::Expr::Def(def) = expr {
|
||||
self.preregister_def(def)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn preregister_def(&mut self, def: &ast::Def) -> TyCheckResult<()> {
|
||||
let id = Some(def.body.id);
|
||||
let __name__ = def.sig.ident().map(|i| i.inspect());
|
||||
match &def.sig {
|
||||
ast::Signature::Subr(sig) => {
|
||||
if sig.is_const() {
|
||||
let (obj, const_t) =
|
||||
match self.eval_const_block(&def.body.block, __name__) {
|
||||
let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) {
|
||||
Ok(obj) => (obj.clone(), enum_t(set! {obj})),
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
|
@ -342,13 +348,7 @@ impl Context {
|
|||
};
|
||||
if let Some(spec) = sig.return_t_spec.as_ref() {
|
||||
let spec_t = self.instantiate_typespec(spec, PreRegister)?;
|
||||
self.sub_unify(
|
||||
&const_t,
|
||||
&spec_t,
|
||||
Some(def.body.loc()),
|
||||
None,
|
||||
None,
|
||||
)?;
|
||||
self.sub_unify(&const_t, &spec_t, Some(def.body.loc()), None, None)?;
|
||||
}
|
||||
self.register_const(__name__.unwrap(), obj);
|
||||
} else {
|
||||
|
@ -362,8 +362,7 @@ impl Context {
|
|||
}
|
||||
}
|
||||
ast::Signature::Var(sig) if sig.is_const() => {
|
||||
let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__)
|
||||
{
|
||||
let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) {
|
||||
Ok(obj) => (obj.clone(), enum_t(set! {obj})),
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
|
@ -377,8 +376,6 @@ impl Context {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ use erg_common::{enum_unwrap, fmt_option, fn_name, get_hash, log, switch_lang, S
|
|||
use erg_parser::ast;
|
||||
use erg_parser::ast::AST;
|
||||
|
||||
use erg_parser::token::{Token, TokenKind};
|
||||
use erg_type::constructors::{array, array_mut, class, free_var, func, poly_class, proc, quant};
|
||||
use erg_type::free::Constraint;
|
||||
use erg_type::typaram::TyParam;
|
||||
|
@ -338,14 +339,36 @@ impl ASTLowerer {
|
|||
hir_args.push_kw(hir::KwArg::new(arg.keyword, self.lower_expr(arg.expr)?));
|
||||
}
|
||||
let obj = self.lower_expr(*call.obj)?;
|
||||
let t = self.ctx.get_call_t(
|
||||
let sig_t = self.ctx.get_call_t(
|
||||
&obj,
|
||||
&call.method_name,
|
||||
&hir_args.pos_args,
|
||||
&hir_args.kw_args,
|
||||
&self.ctx.name,
|
||||
)?;
|
||||
Ok(hir::Call::new(obj, call.method_name, hir_args, t))
|
||||
Ok(hir::Call::new(obj, call.method_name, hir_args, sig_t))
|
||||
}
|
||||
|
||||
fn lower_pack(&mut self, pack: ast::DataPack) -> LowerResult<hir::Call> {
|
||||
log!(info "entered {}({pack})", fn_name!());
|
||||
let class = self.lower_expr(*pack.class)?;
|
||||
let args = self.lower_record(pack.args)?;
|
||||
let args = vec![hir::PosArg::new(hir::Expr::Record(args))];
|
||||
let method_name = Token::new(
|
||||
TokenKind::Symbol,
|
||||
Str::rc("new"),
|
||||
pack.connector.lineno,
|
||||
pack.connector.col_begin,
|
||||
);
|
||||
let sig_t = self.ctx.get_call_t(
|
||||
&class,
|
||||
&Some(method_name.clone()),
|
||||
&args,
|
||||
&[],
|
||||
&self.ctx.name,
|
||||
)?;
|
||||
let args = hir::Args::new(args, vec![], None);
|
||||
Ok(hir::Call::new(class, Some(method_name), args, sig_t))
|
||||
}
|
||||
|
||||
/// TODO: varargs
|
||||
|
@ -523,6 +546,40 @@ impl ASTLowerer {
|
|||
Ok(hir::Def::new(hir::Signature::Subr(sig), body))
|
||||
}
|
||||
|
||||
fn lower_method_defs(&mut self, method_defs: ast::MethodDefs) -> LowerResult<hir::MethodDefs> {
|
||||
log!(info "entered {}({method_defs})", fn_name!());
|
||||
let mut hir_defs = hir::RecordAttrs::new();
|
||||
let class = self
|
||||
.ctx
|
||||
.instantiate_typespec(&method_defs.class, RegistrationMode::Normal)?;
|
||||
self.ctx
|
||||
.grow(&class.name(), ContextKind::MethodDefs, Private)?;
|
||||
for def in method_defs.defs.iter() {
|
||||
self.ctx.preregister_def(def)?;
|
||||
}
|
||||
for def in method_defs.defs.into_iter() {
|
||||
let def = self.lower_def(def)?;
|
||||
hir_defs.push(def);
|
||||
}
|
||||
match self.ctx.pop() {
|
||||
Ok(ctx) => {
|
||||
if let Some((_, class_root)) = self.ctx.poly_types.get_mut(&class.name()) {
|
||||
class_root.method_defs.push((class, ctx));
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
Err(mut errs) => {
|
||||
self.errs.append(&mut errs);
|
||||
}
|
||||
}
|
||||
Ok(hir::MethodDefs::new(
|
||||
method_defs.class,
|
||||
method_defs.vis,
|
||||
hir_defs,
|
||||
))
|
||||
}
|
||||
|
||||
// Call.obj == Accessor cannot be type inferred by itself (it can only be inferred with arguments)
|
||||
// so turn off type checking (check=false)
|
||||
fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
|
||||
|
@ -536,8 +593,10 @@ impl ASTLowerer {
|
|||
ast::Expr::BinOp(bin) => Ok(hir::Expr::BinOp(self.lower_bin(bin)?)),
|
||||
ast::Expr::UnaryOp(unary) => Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?)),
|
||||
ast::Expr::Call(call) => Ok(hir::Expr::Call(self.lower_call(call)?)),
|
||||
ast::Expr::DataPack(pack) => Ok(hir::Expr::Call(self.lower_pack(pack)?)),
|
||||
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?)),
|
||||
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)),
|
||||
ast::Expr::MethodDefs(defs) => Ok(hir::Expr::MethodDefs(self.lower_method_defs(defs)?)),
|
||||
other => todo!("{other}"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -897,6 +897,7 @@ impl Call {
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct DataPack {
|
||||
pub class: Box<Expr>,
|
||||
pub connector: Token,
|
||||
pub args: Record,
|
||||
}
|
||||
|
||||
|
@ -915,9 +916,10 @@ impl Locational for DataPack {
|
|||
}
|
||||
|
||||
impl DataPack {
|
||||
pub fn new(class: Expr, args: Record) -> Self {
|
||||
pub fn new(class: Expr, connector: Token, args: Record) -> Self {
|
||||
Self {
|
||||
class: Box::new(class),
|
||||
connector,
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -330,7 +330,7 @@ impl Desugarer {
|
|||
let class = self.rec_desugar_shortened_record(*pack.class);
|
||||
let rec = self.desugar_shortened_record_inner(rec);
|
||||
let args = Record::Normal(rec);
|
||||
Expr::DataPack(DataPack::new(class, args))
|
||||
Expr::DataPack(DataPack::new(class, pack.connector, args))
|
||||
} else {
|
||||
Expr::DataPack(pack)
|
||||
}
|
||||
|
|
|
@ -997,7 +997,7 @@ impl Parser {
|
|||
.map_err(|_| self.stack_dec())?;
|
||||
match container {
|
||||
BraceContainer::Record(args) => {
|
||||
let pack = DataPack::new(maybe_class, args);
|
||||
let pack = DataPack::new(maybe_class, vis, args);
|
||||
stack.push(ExprOrOp::Expr(Expr::DataPack(pack)));
|
||||
}
|
||||
BraceContainer::Dict(dict) => todo!("{dict}"),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue