use crate::functions::follow_type::follow_type_id;
use crate::records::free_type::FreeType;
use crate::records::pending_type::PendingType;
use crate::records::r#type::Type;
use crate::records::txn_log::TxnLog;
use crate::records::type_arena::TypeArena;
use crate::records::union_type::UnionType;
use crate::type_aliases::bound_type::BoundType;
use crate::type_aliases::type_id::TypeId;
use crate::type_aliases::type_variant::{TypeVariant, TypeVariantMember};
use alloc::boxed::Box;
use alloc::vec;
impl TxnLog {
pub fn concat_as_union(&mut self, mut rhs: TxnLog, arena: *mut TypeArena) {
let right_keys: alloc::vec::Vec<TypeId> =
rhs.type_var_changes.iter().map(|(ty, _)| *ty).collect();
for right_ty in right_keys {
let right_rep: *mut PendingType = match rhs.type_var_changes.find_mut(&right_ty) {
Some(rep) => rep.as_mut() as *mut PendingType,
None => continue,
};
unsafe {
if (*right_rep).dead {
continue;
}
let rf = FreeType::get_if(&(*right_ty).ty);
if rf.is_none() {
continue;
}
let rf = rf.unwrap();
let rb = BoundType::get_if(&(*right_rep).pending.ty);
if rb.is_none() {
continue;
}
let rb = rb.unwrap();
let left_ty: TypeId = rb.boundTo;
let lf = FreeType::get_if(&(*left_ty).ty);
if lf.is_none() {
continue;
}
let lf = lf.unwrap();
let left_rep: *mut PendingType = match self.type_var_changes.find_mut(&left_ty) {
Some(rep) => rep.as_mut() as *mut PendingType,
None => continue,
};
if (*left_rep).dead {
continue;
}
let lb = BoundType::get_if(&(*left_rep).pending.ty);
if lb.is_none() {
continue;
}
let lb = lb.unwrap();
if lb.boundTo == right_ty {
let discard_left = lf.level.subsumes(&rf.level);
if discard_left {
(*left_rep).dead = true;
} else {
(*right_rep).dead = true;
}
}
}
}
let right_keys: alloc::vec::Vec<TypeId> =
rhs.type_var_changes.iter().map(|(ty, _)| *ty).collect();
for ty in right_keys {
let dead = match rhs.type_var_changes.find(&ty) {
Some(rep) => rep.dead,
None => continue,
};
if dead {
continue;
}
let left_live = matches!(self.type_var_changes.find(&ty), Some(rep) if !rep.dead);
if left_live {
let (left_clone, right_clone) = {
let left_rep = self.type_var_changes.find(&ty).unwrap();
let right_rep = rhs.type_var_changes.find(&ty).unwrap();
(left_rep.pending.clone(), right_rep.pending.clone())
};
let left_ty: TypeId = unsafe { (*arena).add_type::<Type>(left_clone) };
let right_ty: TypeId = unsafe { (*arena).add_type::<Type>(right_clone) };
if unsafe { follow_type_id(left_ty) } == unsafe { follow_type_id(right_ty) } {
let right_box = take_pending(&mut rhs, ty);
*self.type_var_changes.get_or_insert(ty) = right_box;
} else {
let slot = self.type_var_changes.get_or_insert(ty);
slot.pending.ty = TypeVariant::Union(UnionType {
options: vec![left_ty, right_ty],
});
}
} else {
let right_box = take_pending(&mut rhs, ty);
*self.type_var_changes.get_or_insert(ty) = right_box;
}
}
let pack_keys: alloc::vec::Vec<*const crate::records::type_pack_var::TypePackVar> =
rhs.type_pack_changes.iter().map(|(tp, _)| *tp).collect();
for tp in pack_keys {
let rep = take_pending_pack(&mut rhs, tp);
*self.type_pack_changes.get_or_insert(tp) = rep;
}
self.radioactive |= rhs.radioactive;
}
}
fn take_pending(rhs: &mut TxnLog, ty: TypeId) -> Box<PendingType> {
let slot = rhs.type_var_changes.get_or_insert(ty);
let placeholder = Box::new(PendingType {
pending: unsafe { (*ty).clone() },
dead: true,
});
core::mem::replace(slot, placeholder)
}
fn take_pending_pack(
rhs: &mut TxnLog,
tp: *const crate::records::type_pack_var::TypePackVar,
) -> Box<crate::records::pending_type_pack::PendingTypePack> {
let slot = rhs.type_pack_changes.get_or_insert(tp);
let placeholder = Box::new(crate::records::pending_type_pack::PendingTypePack {
pending: unsafe { (*tp).clone() },
});
core::mem::replace(slot, placeholder)
}