Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/eval/shim.rs')
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs117
1 files changed, 112 insertions, 5 deletions
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index 9ad6087cad..b2e29fd34b 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -36,6 +36,9 @@ impl Evaluator<'_> {
destination: Interval,
span: MirSpan,
) -> Result<bool> {
+ if self.not_special_fn_cache.borrow().contains(&def) {
+ return Ok(false);
+ }
let function_data = self.db.function_data(def);
let is_intrinsic = match &function_data.abi {
Some(abi) => *abi == Interned::new_str("rust-intrinsic"),
@@ -124,9 +127,88 @@ impl Evaluator<'_> {
destination.write_from_bytes(self, &result)?;
return Ok(true);
}
+ if let ItemContainerId::TraitId(t) = def.lookup(self.db.upcast()).container {
+ if self.db.lang_attr(t.into()) == Some(LangItem::Clone) {
+ let [self_ty] = generic_args.as_slice(Interner) else {
+ not_supported!("wrong generic arg count for clone");
+ };
+ let Some(self_ty) = self_ty.ty(Interner) else {
+ not_supported!("wrong generic arg kind for clone");
+ };
+ // Clone has special impls for tuples and function pointers
+ if matches!(self_ty.kind(Interner), TyKind::Function(_) | TyKind::Tuple(..)) {
+ self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
+ return Ok(true);
+ }
+ // Return early to prevent caching clone as non special fn.
+ return Ok(false);
+ }
+ }
+ self.not_special_fn_cache.borrow_mut().insert(def);
Ok(false)
}
+ /// Clone has special impls for tuples and function pointers
+ fn exec_clone(
+ &mut self,
+ def: FunctionId,
+ args: &[IntervalAndTy],
+ self_ty: Ty,
+ locals: &Locals,
+ destination: Interval,
+ span: MirSpan,
+ ) -> Result<()> {
+ match self_ty.kind(Interner) {
+ TyKind::Function(_) => {
+ let [arg] = args else {
+ not_supported!("wrong arg count for clone");
+ };
+ let addr = Address::from_bytes(arg.get(self)?)?;
+ return destination
+ .write_from_interval(self, Interval { addr, size: destination.size });
+ }
+ TyKind::Tuple(_, subst) => {
+ let [arg] = args else {
+ not_supported!("wrong arg count for clone");
+ };
+ let addr = Address::from_bytes(arg.get(self)?)?;
+ let layout = self.layout(&self_ty)?;
+ for (i, ty) in subst.iter(Interner).enumerate() {
+ let ty = ty.assert_ty_ref(Interner);
+ let size = self.layout(ty)?.size.bytes_usize();
+ let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
+ let arg = IntervalAndTy {
+ interval: Interval { addr: tmp, size: self.ptr_size() },
+ ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone())
+ .intern(Interner),
+ };
+ let offset = layout.fields.offset(i).bytes_usize();
+ self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
+ self.exec_clone(
+ def,
+ &[arg],
+ ty.clone(),
+ locals,
+ destination.slice(offset..offset + size),
+ span,
+ )?;
+ }
+ }
+ _ => {
+ self.exec_fn_with_args(
+ def,
+ args,
+ Substitution::from1(Interner, self_ty),
+ locals,
+ destination,
+ None,
+ span,
+ )?;
+ }
+ }
+ Ok(())
+ }
+
fn exec_alloc_fn(
&mut self,
alloc_fn: &str,
@@ -618,12 +700,15 @@ impl Evaluator<'_> {
else {
return Err(MirEvalError::TypeError("type_name generic arg is not provided"));
};
- let Ok(ty_name) = ty.display_source_code(
+ let ty_name = match ty.display_source_code(
self.db,
locals.body.owner.module(self.db.upcast()),
true,
- ) else {
- not_supported!("fail in generating type_name using source code display");
+ ) {
+ Ok(ty_name) => ty_name,
+ // Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to
+ // render full paths.
+ Err(_) => ty.display(self.db).to_string(),
};
let len = ty_name.len();
let addr = self.heap_allocate(len, 1)?;
@@ -679,7 +764,22 @@ impl Evaluator<'_> {
let ans = lhs.wrapping_add(rhs);
destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
}
- "wrapping_sub" | "unchecked_sub" | "ptr_offset_from_unsigned" | "ptr_offset_from" => {
+ "ptr_offset_from_unsigned" | "ptr_offset_from" => {
+ let [lhs, rhs] = args else {
+ return Err(MirEvalError::TypeError("wrapping_sub args are not provided"));
+ };
+ let lhs = i128::from_le_bytes(pad16(lhs.get(self)?, false));
+ let rhs = i128::from_le_bytes(pad16(rhs.get(self)?, false));
+ let ans = lhs.wrapping_sub(rhs);
+ let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ else {
+ return Err(MirEvalError::TypeError("ptr_offset_from generic arg is not provided"));
+ };
+ let size = self.size_of_sized(ty, locals, "ptr_offset_from arg")? as i128;
+ let ans = ans / size;
+ destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
+ }
+ "wrapping_sub" | "unchecked_sub" => {
let [lhs, rhs] = args else {
return Err(MirEvalError::TypeError("wrapping_sub args are not provided"));
};
@@ -1057,7 +1157,14 @@ impl Evaluator<'_> {
_span: MirSpan,
) -> Result<()> {
// We are a single threaded runtime with no UB checking and no optimization, so
- // we can implement these as normal functions.
+ // we can implement atomic intrinsics as normal functions.
+
+ if name.starts_with("singlethreadfence_") || name.starts_with("fence_") {
+ return Ok(());
+ }
+
+ // The rest of atomic intrinsics have exactly one generic arg
+
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
return Err(MirEvalError::TypeError("atomic intrinsic generic arg is not provided"));
};