use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, OnceLock,
};
use crate::{
metadata::{
customattributes::CustomAttributeValueList,
marshalling::MarshallingInfo,
signatures::SignatureParameter,
token::Token,
typesystem::{CilPrimitive, CilTypeRef, CilTypeRefList, TypeRegistry, TypeResolver},
},
Result,
};
pub struct Param {
pub rid: u32,
pub token: Token,
pub offset: usize,
pub flags: u32,
pub sequence: u32,
pub name: Option<String>,
pub default: OnceLock<CilPrimitive>,
pub marshal: OnceLock<MarshallingInfo>,
pub modifiers: CilTypeRefList,
pub base: OnceLock<CilTypeRef>,
pub is_by_ref: AtomicBool,
pub custom_attributes: CustomAttributeValueList,
}
impl Param {
pub fn apply_signature(
&self,
signature: &SignatureParameter,
types: Arc<TypeRegistry>,
method_param_count: Option<usize>,
) -> Result<()> {
if let Some(param_count) = method_param_count {
#[allow(clippy::cast_possible_truncation)]
if self.sequence > param_count as u32 {
return Err(malformed_error!(
"Parameter sequence {} exceeds method parameter count {} for parameter token {}",
self.sequence,
param_count,
self.token.value()
));
}
}
self.is_by_ref.store(signature.by_ref, Ordering::Relaxed);
for modifier in &signature.modifiers {
match types.get(&modifier.modifier_type) {
Some(new_mod) => {
self.modifiers.push(new_mod.into());
}
None => {
return Err(malformed_error!(
"Failed to resolve modifier type - {}",
modifier.modifier_type.value()
))
}
}
}
let mut resolver = TypeResolver::new(types).with_parent(self.token);
let resolved_type = resolver.resolve(&signature.base)?;
if self.base.set(resolved_type.clone().into()).is_err() {
if let Some(existing_type_ref) = self.base.get() {
let existing_type = existing_type_ref.upgrade().ok_or_else(|| {
malformed_error!(
"Invalid type reference: existing parameter type has been dropped"
)
})?;
if !resolved_type.is_compatible_with(&existing_type) {
return Err(malformed_error!(
"Type compatibility error: parameter {} cannot be shared between methods with incompatible types",
self.token.value()
));
}
}
}
Ok(())
}
}