use super::super::module_resolver::ModuleResolver;
use super::super::SemanticAnalyzer;
use crate::ast::{File, Type};
use crate::error::CompilerError;
impl<R: ModuleResolver> SemanticAnalyzer<R> {
pub(in crate::semantic) fn validate_function_return_type(
&mut self,
func: &crate::ast::FnDef,
file: &File,
) {
self.local_let_bindings.clear();
self.consumed_bindings.clear();
let saved_closure_conventions = self.closure_binding_conventions.clone();
let saved_closure_captures = self.closure_binding_captures.clone();
let saved_fn_scope_captures = self.fn_scope_closure_captures.clone();
let saved_param_conventions = self.current_fn_param_conventions.clone();
self.current_fn_param_conventions.clear();
self.fn_scope_closure_captures.clear();
for param in &func.params {
if let Some(ty) = ¶m.ty {
self.validate_type(ty);
}
let ty_str = param.ty.as_ref().map_or_else(
|| {
if param.name.name == "self" {
self.current_impl_struct
.clone()
.unwrap_or_else(|| "Unknown".to_string())
} else {
"Unknown".to_string()
}
},
|ty| Self::type_to_string(ty),
);
let mutable = matches!(
param.convention,
crate::ast::ParamConvention::Mut | crate::ast::ParamConvention::Sink
);
self.local_let_bindings
.insert(param.name.name.clone(), (ty_str, mutable));
self.current_fn_param_conventions
.insert(param.name.name.clone(), param.convention);
if let Some(Type::Closure {
params: closure_params,
..
}) = ¶m.ty
{
let conventions: Vec<_> = closure_params.iter().map(|(c, _)| *c).collect();
self.closure_binding_conventions
.insert(param.name.name.clone(), conventions);
}
}
if let Some(body) = &func.body {
self.validate_expr(body, file);
self.validate_function_return_escape(func.return_type.as_ref(), body);
if let Some(declared_return_type) = &func.return_type {
let body_type = self.infer_type_sem(body, file).display();
let expected_type = Self::type_to_string(declared_return_type);
if !self.type_strings_compatible(&expected_type, &body_type) {
self.errors.push(CompilerError::FunctionReturnTypeMismatch {
function: func.name.name.clone(),
expected: expected_type,
actual: body_type,
span: func.name.span,
});
}
}
}
self.local_let_bindings.clear();
self.closure_binding_conventions = saved_closure_conventions;
self.closure_binding_captures = saved_closure_captures;
self.fn_scope_closure_captures = saved_fn_scope_captures;
self.current_fn_param_conventions = saved_param_conventions;
}
pub(in crate::semantic) fn validate_standalone_function(
&mut self,
func: &crate::ast::FunctionDef,
file: &File,
) {
self.push_generic_scope(&func.generics);
self.local_let_bindings.clear();
self.consumed_bindings.clear();
let saved_closure_conventions = self.closure_binding_conventions.clone();
let saved_closure_captures = self.closure_binding_captures.clone();
let saved_fn_scope_captures = self.fn_scope_closure_captures.clone();
let saved_param_conventions = self.current_fn_param_conventions.clone();
self.current_fn_param_conventions.clear();
self.fn_scope_closure_captures.clear();
for param in &func.params {
if let Some(ty) = ¶m.ty {
self.validate_type(ty);
}
let ty_str = param
.ty
.as_ref()
.map_or_else(|| "Unknown".to_string(), |ty| Self::type_to_string(ty));
let mutable = matches!(
param.convention,
crate::ast::ParamConvention::Mut | crate::ast::ParamConvention::Sink
);
self.local_let_bindings
.insert(param.name.name.clone(), (ty_str, mutable));
self.current_fn_param_conventions
.insert(param.name.name.clone(), param.convention);
if let Some(Type::Closure {
params: closure_params,
..
}) = ¶m.ty
{
let conventions: Vec<_> = closure_params.iter().map(|(c, _)| *c).collect();
self.closure_binding_conventions
.insert(param.name.name.clone(), conventions);
}
}
if let Some(return_type) = &func.return_type {
self.validate_type(return_type);
}
if let Some(body) = &func.body {
self.validate_expr(body, file);
self.validate_function_return_escape(func.return_type.as_ref(), body);
if let Some(declared_return_type) = &func.return_type {
let body_type = self.infer_type_sem(body, file).display();
let expected_type = Self::type_to_string(declared_return_type);
if !self.type_strings_compatible(&expected_type, &body_type) {
self.errors.push(CompilerError::FunctionReturnTypeMismatch {
function: func.name.name.clone(),
expected: expected_type,
actual: body_type,
span: func.name.span,
});
}
}
}
self.local_let_bindings.clear();
self.closure_binding_conventions = saved_closure_conventions;
self.closure_binding_captures = saved_closure_captures;
self.fn_scope_closure_captures = saved_fn_scope_captures;
self.current_fn_param_conventions = saved_param_conventions;
self.pop_generic_scope();
}
}