use crate::ast::Expr;
use crate::types::Type;
use std::collections::{HashMap, HashSet};
#[derive(Clone)]
pub struct EmitCtx {
pub local_types: HashMap<String, Type>,
pub rc_wrapped: HashSet<String>,
pub borrowed_params: HashSet<String>,
}
impl EmitCtx {
pub fn empty() -> Self {
EmitCtx {
local_types: HashMap::new(),
rc_wrapped: HashSet::new(),
borrowed_params: HashSet::new(),
}
}
pub fn for_fn(param_types: HashMap<String, Type>) -> Self {
let borrowed_params = param_types
.iter()
.filter(|(_, ty)| should_borrow_param(ty))
.map(|(name, _)| name.clone())
.collect();
EmitCtx {
local_types: param_types,
rc_wrapped: HashSet::new(),
borrowed_params,
}
}
pub fn for_fn_no_borrow(param_types: HashMap<String, Type>) -> Self {
EmitCtx {
local_types: param_types,
rc_wrapped: HashSet::new(),
borrowed_params: HashSet::new(),
}
}
pub fn is_copy(&self, name: &str) -> bool {
self.local_types.get(name).is_some_and(is_copy_type)
}
pub fn is_rc_wrapped(&self, name: &str) -> bool {
self.rc_wrapped.contains(name)
}
pub fn is_borrowed_param(&self, name: &str) -> bool {
self.borrowed_params.contains(name)
}
pub fn with_rc_wrapped(&self, rc: HashSet<String>) -> Self {
EmitCtx {
local_types: self.local_types.clone(),
rc_wrapped: rc,
borrowed_params: self.borrowed_params.clone(),
}
}
}
pub fn expr_can_move(expr: &Expr) -> bool {
match expr {
Expr::Resolved { last_use, .. } => last_use.0,
Expr::Ident(_) => true, _ => false,
}
}
pub fn expr_skip_clone(expr: &Expr, ectx: &EmitCtx) -> bool {
match expr {
Expr::Resolved { name, last_use, .. } => {
if ectx.rc_wrapped.contains(name.as_str()) {
return false;
}
if ectx.borrowed_params.contains(name.as_str()) {
return false;
}
last_use.0 || ectx.is_copy(name)
}
Expr::Ident(name) => {
if !ectx.local_types.contains_key(name.as_str()) {
return true;
}
if ectx.rc_wrapped.contains(name.as_str()) {
return false;
}
if ectx.borrowed_params.contains(name.as_str()) {
return false;
}
ectx.is_copy(name)
}
_ => false,
}
}
pub fn is_copy_type(ty: &Type) -> bool {
matches!(ty, Type::Int | Type::Float | Type::Bool | Type::Unit)
}
pub fn should_borrow_param(ty: &Type) -> bool {
matches!(
ty,
Type::Map(_, _)
| Type::List(_)
| Type::Vector(_)
| Type::Result(_, _)
| Type::Option(_)
| Type::Tuple(_)
| Type::Named(_)
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_copy_type() {
assert!(is_copy_type(&Type::Int));
assert!(is_copy_type(&Type::Float));
assert!(is_copy_type(&Type::Bool));
assert!(is_copy_type(&Type::Unit));
assert!(!is_copy_type(&Type::Str));
assert!(!is_copy_type(&Type::List(Box::new(Type::Int))));
assert!(!is_copy_type(&Type::Named("Foo".to_string())));
}
}