use super::*;
use crate::{
decl_engine::DeclRef,
language::{parsed::CodeBlock, ty},
};
impl ty::TyCodeBlock {
pub(crate) fn type_check(
mut ctx: TypeCheckContext,
code_block: CodeBlock,
) -> CompileResult<(Self, TypeId)> {
let mut warnings = Vec::new();
let mut errors = Vec::new();
let decl_engine = ctx.decl_engine;
let mut code_block_namespace = ctx.namespace.clone();
let evaluated_contents = code_block
.contents
.iter()
.filter_map(|node| {
let ctx = ctx.by_ref().scoped(&mut code_block_namespace);
ty::TyAstNode::type_check(ctx, node.clone()).ok(&mut warnings, &mut errors)
})
.collect::<Vec<ty::TyAstNode>>();
let implicit_return_span = code_block
.contents
.iter()
.find_map(|x| match &x.content {
AstNodeContent::ImplicitReturnExpression(expr) => Some(Some(expr.span())),
_ => None,
})
.flatten();
let span = implicit_return_span.unwrap_or_else(|| code_block.whole_block_span.clone());
let mut node_deterministically_aborts = false;
let block_type = evaluated_contents
.iter()
.find_map(|node| {
if node.deterministically_aborts(decl_engine, true) {
node_deterministically_aborts = true;
};
match node {
ty::TyAstNode {
content:
ty::TyAstNodeContent::ImplicitReturnExpression(ty::TyExpression {
ref return_type,
..
}),
..
} => Some(*return_type),
_ => None,
}
})
.unwrap_or_else(|| {
if node_deterministically_aborts {
let never_mod_path = vec![
Ident::new_with_override("core".into(), span.clone()),
Ident::new_with_override("never".into(), span.clone()),
];
let never_ident = Ident::new_with_override("Never".into(), span.clone());
let never_decl_opt = ctx
.namespace
.root()
.resolve_symbol(&never_mod_path, &never_ident)
.value;
if let Some(ty::TyDecl::EnumDecl {
name,
decl_id,
subst_list: _,
decl_span,
}) = never_decl_opt
{
return ctx.engines().te().insert(
decl_engine,
TypeInfo::Enum(DeclRef::new(name.clone(), *decl_id, decl_span.clone())),
);
}
ctx.type_engine.insert(decl_engine, TypeInfo::Unknown)
} else {
ctx.type_engine
.insert(decl_engine, TypeInfo::Tuple(Vec::new()))
}
});
append!(ctx.unify_with_self(block_type, &span), warnings, errors);
let typed_code_block = ty::TyCodeBlock {
contents: evaluated_contents,
};
ok((typed_code_block, block_type), warnings, errors)
}
}