WIP: Impl DataPack type checking

This commit is contained in:
Shunsuke Shibayama 2022-09-03 20:58:28 +09:00
parent e7898c094e
commit 263c43d74b
7 changed files with 119 additions and 58 deletions

View file

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

View file

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

View file

@ -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(())
}

View file

@ -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}"),
}
}

View file

@ -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,
}
}

View file

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

View file

@ -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}"),