diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 2ccdc8c042..651502965e 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -14,3 +14,4 @@ f247090558c9ba3c551566eae5882b7ca865225f b2f6fd4f961fc7e4fbfdb80cae2e6065f8436f15 c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1 f532576ac53ddcc666bc8d59e0b6437065e2f599 +4704881b641884de50645637108b6b6f5b68aaf9 diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index e83ce6dc42..166e00c9d2 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -501,4 +501,5 @@ language_item_table! { String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; + Ordering, sym::Ordering, ordering, Target::Enum, GenericRequirement::None; } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 8e4c4db102..6b20522cf3 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1644,14 +1644,15 @@ impl Evaluator<'_> { Variants::Multiple { tag, tag_encoding, variants, .. } => { let size = tag.size(&*self.target_data_layout).bytes_usize(); let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field + let is_signed = tag.is_signed(); match tag_encoding { TagEncoding::Direct => { let tag = &bytes[offset..offset + size]; - Ok(i128::from_le_bytes(pad16(tag, false))) + Ok(i128::from_le_bytes(pad16(tag, is_signed))) } TagEncoding::Niche { untagged_variant, niche_start, .. } => { let tag = &bytes[offset..offset + size]; - let candidate_tag = i128::from_le_bytes(pad16(tag, false)) + let candidate_tag = i128::from_le_bytes(pad16(tag, is_signed)) .wrapping_sub(*niche_start as i128) as usize; let idx = variants @@ -2943,10 +2944,10 @@ pub fn render_const_using_debug_impl( // a3 = ::core::fmt::Arguments::new_v1(a1, a2) // FIXME: similarly, we should call function here, not directly working with memory. let a3 = evaluator.heap_allocate(evaluator.ptr_size() * 6, evaluator.ptr_size())?; - evaluator.write_memory(a3.offset(2 * evaluator.ptr_size()), &a1.to_bytes())?; + evaluator.write_memory(a3, &a1.to_bytes())?; + evaluator.write_memory(a3.offset(evaluator.ptr_size()), &[1])?; + evaluator.write_memory(a3.offset(2 * evaluator.ptr_size()), &a2.to_bytes())?; evaluator.write_memory(a3.offset(3 * evaluator.ptr_size()), &[1])?; - evaluator.write_memory(a3.offset(4 * evaluator.ptr_size()), &a2.to_bytes())?; - evaluator.write_memory(a3.offset(5 * evaluator.ptr_size()), &[1])?; let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully( db.upcast(), &hir_def::path::Path::from_known_path_with_no_generic(path![std::fmt::format]), diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 0a78f4a5b2..38b189a517 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -1,11 +1,12 @@ //! Interpret intrinsics, lang items and `extern "C"` wellknown functions which their implementation //! is not available. //! -use std::cmp; +use std::cmp::{self, Ordering}; use chalk_ir::TyKind; use hir_def::{ builtin_type::{BuiltinInt, BuiltinUint}, + lang_item::LangItemTarget, resolver::HasResolver, }; use hir_expand::name::Name; @@ -1317,6 +1318,82 @@ impl Evaluator<'_> { self.write_memory_using_ref(dst, size)?.fill(val); Ok(()) } + "ptr_metadata" => { + let [ptr] = args else { + return Err(MirEvalError::InternalError( + "ptr_metadata args are not provided".into(), + )); + }; + let arg = ptr.interval.get(self)?.to_owned(); + let metadata = &arg[self.ptr_size()..]; + destination.write_from_bytes(self, metadata)?; + Ok(()) + } + "three_way_compare" => { + let [lhs, rhs] = args else { + return Err(MirEvalError::InternalError( + "three_way_compare args are not provided".into(), + )); + }; + let Some(ty) = + generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) + else { + return Err(MirEvalError::InternalError( + "three_way_compare generic arg is not provided".into(), + )); + }; + let signed = match ty.as_builtin().unwrap() { + BuiltinType::Int(_) => true, + BuiltinType::Uint(_) => false, + _ => { + return Err(MirEvalError::InternalError( + "three_way_compare expects an integral type".into(), + )) + } + }; + let rhs = rhs.get(self)?; + let lhs = lhs.get(self)?; + let mut result = Ordering::Equal; + for (l, r) in lhs.iter().zip(rhs).rev() { + let it = l.cmp(r); + if it != Ordering::Equal { + result = it; + break; + } + } + if signed { + if let Some((&l, &r)) = lhs.iter().zip(rhs).next_back() { + if l != r { + result = (l as i8).cmp(&(r as i8)); + } + } + } + if let Some(LangItemTarget::EnumId(e)) = + self.db.lang_item(self.crate_id, LangItem::Ordering) + { + let ty = self.db.ty(e.into()); + let r = self + .compute_discriminant(ty.skip_binders().clone(), &[result as i8 as u8])?; + destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])?; + Ok(()) + } else { + Err(MirEvalError::InternalError("Ordering enum not found".into())) + } + } + "aggregate_raw_ptr" => { + let [data, meta] = args else { + return Err(MirEvalError::InternalError( + "aggregate_raw_ptr args are not provided".into(), + )); + }; + destination.write_from_interval(self, data.interval)?; + Interval { + addr: destination.addr.offset(data.interval.size), + size: destination.size - data.interval.size, + } + .write_from_interval(self, meta.interval)?; + Ok(()) + } _ if needs_override => not_supported!("intrinsic {name} is not implemented"), _ => return Ok(false), } diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs index 1b543ddf81..8df7c59aa7 100644 --- a/crates/intern/src/symbol/symbols.rs +++ b/crates/intern/src/symbol/symbols.rs @@ -347,6 +347,7 @@ define_symbols! { option, Option, Ord, + Ordering, Output, CallRefFuture, CallOnceFuture,