mod closures;
mod control_flow;
mod expr;
mod functions;
mod invocation;
mod let_and_block;
mod method_call;
mod qualified_types;
mod structs;
use super::module_resolver::ModuleResolver;
use super::SemanticAnalyzer;
use crate::ast::{Definition, File, Statement, StructDef};
impl<R: ModuleResolver> SemanticAnalyzer<R> {
pub(in crate::semantic) fn validate_expressions(&mut self, file: &File) {
for statement in &file.statements {
match statement {
Statement::Let(let_binding) => self.validate_let_statement(let_binding, file),
Statement::Definition(def) => self.validate_definition_expressions(def, file),
Statement::Use(_) => {}
}
}
}
fn validate_definition_expressions(&mut self, def: &Definition, file: &File) {
match def {
Definition::Struct(struct_def) => self.validate_struct_expressions(struct_def, file),
Definition::Impl(impl_def) => self.validate_impl_expressions(impl_def, file),
Definition::Function(func_def) => self.validate_function_body(func_def, file),
Definition::Module(module_def) => {
for nested_def in &module_def.definitions {
self.validate_definition_expressions(nested_def, file);
}
}
Definition::Trait(_) | Definition::Enum(_) => {}
}
}
fn validate_impl_expressions(&mut self, impl_def: &crate::ast::ImplDef, file: &File) {
self.push_impl_generic_scope(&impl_def.generics, &impl_def.name.name);
self.current_impl_struct = Some(impl_def.name.name.clone());
self.local_let_bindings.clear();
self.consumed_bindings.clear();
for func in &impl_def.functions {
self.validate_function_return_type(func, file);
}
self.current_impl_struct = None;
self.local_let_bindings.clear();
self.consumed_bindings.clear();
self.pop_generic_scope();
}
fn validate_function_body(&mut self, func_def: &crate::ast::FunctionDef, file: &File) {
self.push_generic_scope(&func_def.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 = std::mem::take(&mut self.fn_scope_closure_captures);
let saved_param_conventions = self.current_fn_param_conventions.clone();
self.current_fn_param_conventions.clear();
for param in &func_def.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(crate::ast::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_def.body {
self.validate_expr(body, file);
self.validate_function_return_escape(func_def.return_type.as_ref(), body);
}
self.local_let_bindings.clear();
self.consumed_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();
}
pub(in crate::semantic) fn validate_struct_expressions(
&mut self,
struct_def: &StructDef,
file: &File,
) {
for field in &struct_def.fields {
if let Some(default_expr) = &field.default {
self.validate_expr(default_expr, file);
let inferred_sem = self.infer_type_sem(default_expr, file);
let inferred = inferred_sem.display();
let declared = Self::type_to_string(&field.ty);
let nil_to_optional = matches!(inferred_sem, super::sem_type::SemType::Nil)
&& declared.ends_with('?');
let inner_to_optional =
declared.ends_with('?') && declared.trim_end_matches('?') == inferred.as_str();
if !nil_to_optional
&& !inner_to_optional
&& !inferred_sem.is_indeterminate()
&& declared != "Unknown"
&& !self.type_strings_compatible(&declared, &inferred)
{
self.errors.push(crate::error::CompilerError::TypeMismatch {
expected: declared,
found: inferred,
span: field.span,
});
}
}
}
}
}