Fixed to define subroutine as Type::Failure even if type checking fails

This commit is contained in:
Shunsuke Shibayama 2022-10-01 16:07:03 +09:00
parent 2c15b057de
commit 3147dfb1d8
3 changed files with 104 additions and 30 deletions

View file

@ -388,6 +388,7 @@ impl Context {
sig: &ast::SubrSignature,
mode: RegistrationMode,
) -> TyCheckResult<Type> {
// -> Result<Type, (Type, TyCheckErrors)> {
let opt_decl_sig_t = self
.rec_get_var_t(&sig.ident, &self.cfg.input, &self.name)
.ok()

View file

@ -3,6 +3,7 @@ use std::path::PathBuf;
use erg_common::config::{ErgConfig, Input};
use erg_common::levenshtein::get_similar_name;
use erg_common::set::Set;
use erg_common::traits::{Locational, Stream};
use erg_common::vis::Visibility;
use erg_common::Str;
@ -98,7 +99,6 @@ impl Context {
let vis = sig.ident.vis();
let muty = Mutability::from(&name[..]);
let kind = id.map_or(VarKind::Declared, VarKind::Defined);
let t = self.instantiate_sub_sig_t(sig, PreRegister)?;
let comptime_decos = sig
.decorators
.iter()
@ -108,7 +108,18 @@ impl Context {
}
_ => None,
})
.collect();
.collect::<Set<_>>();
let t = self.instantiate_sub_sig_t(sig, PreRegister).map_err(|e| {
let vi = VarInfo::new(
Type::Failure,
muty,
vis,
kind.clone(),
Some(comptime_decos.clone()),
);
self.decls.insert(sig.ident.name.clone(), vi);
e
})?;
let vi = VarInfo::new(t, muty, vis, kind, Some(comptime_decos));
if let Some(_decl) = self.decls.remove(name) {
Err(TyCheckErrors::from(TyCheckError::duplicate_decl_error(
@ -455,6 +466,40 @@ impl Context {
Ok(())
}
pub(crate) fn fake_subr_assign(&mut self, sig: &ast::SubrSignature, failure_t: Type) {
// already defined as const
if sig.is_const() {
let vi = self.decls.remove(sig.ident.inspect()).unwrap();
self.locals.insert(sig.ident.name.clone(), vi);
}
let muty = if sig.ident.is_const() {
Mutability::Const
} else {
Mutability::Immutable
};
let name = &sig.ident.name;
self.decls.remove(name);
let comptime_decos = sig
.decorators
.iter()
.filter_map(|deco| match &deco.0 {
ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => {
Some(local.inspect().clone())
}
_ => None,
})
.collect();
let vi = VarInfo::new(
failure_t,
muty,
sig.ident.vis(),
VarKind::DoesNotExist,
Some(comptime_decos),
);
log!(info "Registered {}::{name}: {}", self.name, &vi.t);
self.locals.insert(name.clone(), vi);
}
// To allow forward references and recursive definitions
pub(crate) fn preregister(&mut self, block: &ast::Block) -> TyCheckResult<()> {
let mut total_errs = TyCheckErrors::empty();

View file

@ -660,36 +660,64 @@ impl ASTLowerer {
.unwrap()
.t
.clone();
let t = enum_unwrap!(t, Type::Subr);
if let Err(errs) = self.ctx.assign_params(&sig.params, Some(t.clone())) {
self.errs.extend(errs.into_iter());
}
if let Err(errs) = self.ctx.preregister(&body.block) {
self.errs.extend(errs.into_iter());
}
let block = self.lower_block(body.block).map_err(|e| {
self.pop_append_errs();
e
})?;
let found_body_t = block.ref_t();
let expect_body_t = t.return_t.as_ref();
if !sig.is_const() {
if let Err(e) =
self.return_t_check(sig.loc(), sig.ident.inspect(), expect_body_t, found_body_t)
{
self.errs.push(e);
match t {
Type::Subr(t) => {
if let Err(errs) = self.ctx.assign_params(&sig.params, Some(t.clone())) {
self.errs.extend(errs.into_iter());
}
if let Err(errs) = self.ctx.preregister(&body.block) {
self.errs.extend(errs.into_iter());
}
let block = self.lower_block(body.block).map_err(|e| {
self.pop_append_errs();
e
})?;
let found_body_t = block.ref_t();
let expect_body_t = t.return_t.as_ref();
if !sig.is_const() {
if let Err(e) = self.return_t_check(
sig.loc(),
sig.ident.inspect(),
expect_body_t,
found_body_t,
) {
self.errs.push(e);
}
}
let id = body.id;
self.ctx
.outer
.as_mut()
.unwrap()
.assign_subr(&sig, id, found_body_t)?;
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, sig.params, Type::Subr(t));
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body))
}
Type::Failure => {
if let Err(errs) = self.ctx.assign_params(&sig.params, None) {
self.errs.extend(errs.into_iter());
}
if let Err(errs) = self.ctx.preregister(&body.block) {
self.errs.extend(errs.into_iter());
}
let block = self.lower_block(body.block).map_err(|e| {
self.pop_append_errs();
e
})?;
self.ctx
.outer
.as_mut()
.unwrap()
.fake_subr_assign(&sig, Type::Failure);
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, sig.params, Type::Failure);
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body))
}
_ => unreachable!(),
}
let id = body.id;
self.ctx
.outer
.as_mut()
.unwrap()
.assign_subr(&sig, id, found_body_t)?;
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, sig.params, Type::Subr(t));
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body))
}
fn lower_class_def(&mut self, class_def: ast::ClassDef) -> LowerResult<hir::ClassDef> {