about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-02 10:18:36 +0000
committerbors <bors@rust-lang.org>2023-06-02 10:18:36 +0000
commit0677c204ca9482f12a7ee6b5ef9e64957dfee343 (patch)
tree7665738443378b8be0768d8ced6b4e2153ba328d
parent0b4c09b1d2d3e6be0499f2683743716661821bf2 (diff)
parentf9e3b180b7cbee429c465408bbe0e8dbfc104cd7 (diff)
downloadrust-0677c204ca9482f12a7ee6b5ef9e64957dfee343.tar.gz
rust-0677c204ca9482f12a7ee6b5ef9e64957dfee343.zip
Auto merge of #14947 - HKalbasi:render-const, r=HKalbasi
Add enum, reference, array and slice to `render_const_scalar`
-rw-r--r--crates/hir-ty/src/display.rs253
-rw-r--r--crates/hir-ty/src/lib.rs24
-rw-r--r--crates/hir-ty/src/mir/eval.rs115
-rw-r--r--crates/hir-ty/src/mir/lower.rs2
-rw-r--r--crates/hir-ty/src/utils.rs50
-rw-r--r--crates/hir/src/lib.rs8
-rw-r--r--crates/ide/src/hover/tests.rs205
-rw-r--r--crates/ide/src/inlay_hints/chaining.rs12
-rw-r--r--crates/test-utils/src/minicore.rs7
9 files changed, 561 insertions, 115 deletions
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 32f50cb051d..d3dba52d5f0 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -17,21 +17,26 @@ use hir_def::{
     path::{Path, PathKind},
     type_ref::{TraitBoundModifier, TypeBound, TypeRef},
     visibility::Visibility,
-    HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId,
+    EnumVariantId, HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId,
+    TraitId,
 };
 use hir_expand::{hygiene::Hygiene, name::Name};
 use intern::{Internable, Interned};
 use itertools::Itertools;
+use la_arena::ArenaMap;
 use smallvec::SmallVec;
 use stdx::never;
 
 use crate::{
+    consteval::try_const_usize,
     db::HirDatabase,
-    from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
+    from_assoc_type_id, from_foreign_def_id, from_placeholder_idx,
+    layout::Layout,
+    lt_from_placeholder_idx,
     mapping::from_chalk,
     mir::pad16,
     primitive, to_assoc_type_id,
-    utils::{self, generics, ClosureSubst},
+    utils::{self, detect_variant_from_bytes, generics, ClosureSubst},
     AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstScalar, ConstValue,
     DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives,
     MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar,
@@ -470,7 +475,7 @@ fn render_const_scalar(
     // infrastructure and have it here as a field on `f`.
     let krate = *f.db.crate_graph().crates_in_topological_order().last().unwrap();
     match ty.kind(Interner) {
-        chalk_ir::TyKind::Scalar(s) => match s {
+        TyKind::Scalar(s) => match s {
             Scalar::Bool => write!(f, "{}", if b[0] == 0 { false } else { true }),
             Scalar::Char => {
                 let x = u128::from_le_bytes(pad16(b, false)) as u32;
@@ -498,17 +503,54 @@ fn render_const_scalar(
                 }
             },
         },
-        chalk_ir::TyKind::Ref(_, _, t) => match t.kind(Interner) {
-            chalk_ir::TyKind::Str => {
+        TyKind::Ref(_, _, t) => match t.kind(Interner) {
+            TyKind::Str => {
                 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
-                let bytes = memory_map.memory.get(&addr).map(|x| &**x).unwrap_or(&[]);
-                let s = std::str::from_utf8(bytes).unwrap_or("<utf8-error>");
+                let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
+                let Some(bytes) = memory_map.get(addr, size) else {
+                    return f.write_str("<ref-data-not-available>");
+                };
+                let s = std::str::from_utf8(&bytes).unwrap_or("<utf8-error>");
                 write!(f, "{s:?}")
             }
-            _ => f.write_str("<ref-not-supported>"),
+            TyKind::Slice(ty) => {
+                let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
+                let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
+                let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
+                    return f.write_str("<layout-error>");
+                };
+                let size_one = layout.size.bytes_usize();
+                let Some(bytes) = memory_map.get(addr, size_one * count) else {
+                    return f.write_str("<ref-data-not-available>");
+                };
+                f.write_str("&[")?;
+                let mut first = true;
+                for i in 0..count {
+                    if first {
+                        first = false;
+                    } else {
+                        f.write_str(", ")?;
+                    }
+                    let offset = size_one * i;
+                    render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, &ty)?;
+                }
+                f.write_str("]")
+            }
+            _ => {
+                let addr = usize::from_le_bytes(b.try_into().unwrap());
+                let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
+                    return f.write_str("<layout-error>");
+                };
+                let size = layout.size.bytes_usize();
+                let Some(bytes) = memory_map.get(addr, size) else {
+                    return f.write_str("<ref-data-not-available>");
+                };
+                f.write_str("&")?;
+                render_const_scalar(f, bytes, memory_map, t)
+            }
         },
-        chalk_ir::TyKind::Tuple(_, subst) => {
-            let Ok(layout) = f.db.layout_of_ty( ty.clone(), krate) else {
+        TyKind::Tuple(_, subst) => {
+            let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
                 return f.write_str("<layout-error>");
             };
             f.write_str("(")?;
@@ -530,69 +572,144 @@ fn render_const_scalar(
             }
             f.write_str(")")
         }
-        chalk_ir::TyKind::Adt(adt, subst) => match adt.0 {
-            hir_def::AdtId::StructId(s) => {
-                let data = f.db.struct_data(s);
-                let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), krate) else {
-                    return f.write_str("<layout-error>");
-                };
-                match data.variant_data.as_ref() {
-                    VariantData::Record(fields) | VariantData::Tuple(fields) => {
-                        let field_types = f.db.field_types(s.into());
-                        let krate = adt.0.module(f.db.upcast()).krate();
-                        let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
-                            let offset = layout
-                                .fields
-                                .offset(u32::from(id.into_raw()) as usize)
-                                .bytes_usize();
-                            let ty = field_types[id].clone().substitute(Interner, subst);
-                            let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
-                                return f.write_str("<layout-error>");
-                            };
-                            let size = layout.size.bytes_usize();
-                            render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
-                        };
-                        let mut it = fields.iter();
-                        if matches!(data.variant_data.as_ref(), VariantData::Record(_)) {
-                            write!(f, "{} {{", data.name.display(f.db.upcast()))?;
-                            if let Some((id, data)) = it.next() {
-                                write!(f, " {}: ", data.name.display(f.db.upcast()))?;
-                                render_field(f, id)?;
-                            }
-                            for (id, data) in it {
-                                write!(f, ", {}: ", data.name.display(f.db.upcast()))?;
-                                render_field(f, id)?;
-                            }
-                            write!(f, " }}")?;
-                        } else {
-                            let mut it = it.map(|x| x.0);
-                            write!(f, "{}(", data.name.display(f.db.upcast()))?;
-                            if let Some(id) = it.next() {
-                                render_field(f, id)?;
-                            }
-                            for id in it {
-                                write!(f, ", ")?;
-                                render_field(f, id)?;
-                            }
-                            write!(f, ")")?;
-                        }
-                        return Ok(());
-                    }
-                    VariantData::Unit => write!(f, "{}", data.name.display(f.db.upcast())),
+        TyKind::Adt(adt, subst) => {
+            let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), krate) else {
+                return f.write_str("<layout-error>");
+            };
+            match adt.0 {
+                hir_def::AdtId::StructId(s) => {
+                    let data = f.db.struct_data(s);
+                    write!(f, "{}", data.name.display(f.db.upcast()))?;
+                    let field_types = f.db.field_types(s.into());
+                    render_variant_after_name(
+                        &data.variant_data,
+                        f,
+                        &field_types,
+                        adt.0.module(f.db.upcast()).krate(),
+                        &layout,
+                        subst,
+                        b,
+                        memory_map,
+                    )
+                }
+                hir_def::AdtId::UnionId(u) => {
+                    write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast()))
+                }
+                hir_def::AdtId::EnumId(e) => {
+                    let Some((var_id, var_layout)) =
+                            detect_variant_from_bytes(&layout, f.db, krate, b, e) else {
+                        return f.write_str("<failed-to-detect-variant>");
+                    };
+                    let data = &f.db.enum_data(e).variants[var_id];
+                    write!(f, "{}", data.name.display(f.db.upcast()))?;
+                    let field_types =
+                        f.db.field_types(EnumVariantId { parent: e, local_id: var_id }.into());
+                    render_variant_after_name(
+                        &data.variant_data,
+                        f,
+                        &field_types,
+                        adt.0.module(f.db.upcast()).krate(),
+                        &var_layout,
+                        subst,
+                        b,
+                        memory_map,
+                    )
                 }
             }
-            hir_def::AdtId::UnionId(u) => {
-                write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast()))
-            }
-            hir_def::AdtId::EnumId(_) => f.write_str("<enum-not-supported>"),
-        },
-        chalk_ir::TyKind::FnDef(..) => ty.hir_fmt(f),
-        chalk_ir::TyKind::Raw(_, _) => {
+        }
+        TyKind::FnDef(..) => ty.hir_fmt(f),
+        TyKind::Function(_) | TyKind::Raw(_, _) => {
             let x = u128::from_le_bytes(pad16(b, false));
             write!(f, "{:#X} as ", x)?;
             ty.hir_fmt(f)
         }
-        _ => f.write_str("<not-supported>"),
+        TyKind::Array(ty, len) => {
+            let Some(len) = try_const_usize(f.db, len) else {
+                return f.write_str("<unknown-array-len>");
+            };
+            let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
+                return f.write_str("<layout-error>");
+            };
+            let size_one = layout.size.bytes_usize();
+            f.write_str("[")?;
+            let mut first = true;
+            for i in 0..len as usize {
+                if first {
+                    first = false;
+                } else {
+                    f.write_str(", ")?;
+                }
+                let offset = size_one * i;
+                render_const_scalar(f, &b[offset..offset + size_one], memory_map, &ty)?;
+            }
+            f.write_str("]")
+        }
+        TyKind::Never => f.write_str("!"),
+        TyKind::Closure(_, _) => f.write_str("<closure>"),
+        TyKind::Generator(_, _) => f.write_str("<generator>"),
+        TyKind::GeneratorWitness(_, _) => f.write_str("<generator-witness>"),
+        // The below arms are unreachable, since const eval will bail out before here.
+        TyKind::Foreign(_) => f.write_str("<extern-type>"),
+        TyKind::Error
+        | TyKind::Placeholder(_)
+        | TyKind::Alias(_)
+        | TyKind::AssociatedType(_, _)
+        | TyKind::OpaqueType(_, _)
+        | TyKind::BoundVar(_)
+        | TyKind::InferenceVar(_, _) => f.write_str("<placeholder-or-unknown-type>"),
+        // The below arms are unreachable, since we handled them in ref case.
+        TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => f.write_str("<unsized-value>"),
+    }
+}
+
+fn render_variant_after_name(
+    data: &VariantData,
+    f: &mut HirFormatter<'_>,
+    field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
+    krate: CrateId,
+    layout: &Layout,
+    subst: &Substitution,
+    b: &[u8],
+    memory_map: &MemoryMap,
+) -> Result<(), HirDisplayError> {
+    match data {
+        VariantData::Record(fields) | VariantData::Tuple(fields) => {
+            let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
+                let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
+                let ty = field_types[id].clone().substitute(Interner, subst);
+                let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
+                    return f.write_str("<layout-error>");
+                };
+                let size = layout.size.bytes_usize();
+                render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
+            };
+            let mut it = fields.iter();
+            if matches!(data, VariantData::Record(_)) {
+                write!(f, " {{")?;
+                if let Some((id, data)) = it.next() {
+                    write!(f, " {}: ", data.name.display(f.db.upcast()))?;
+                    render_field(f, id)?;
+                }
+                for (id, data) in it {
+                    write!(f, ", {}: ", data.name.display(f.db.upcast()))?;
+                    render_field(f, id)?;
+                }
+                write!(f, " }}")?;
+            } else {
+                let mut it = it.map(|x| x.0);
+                write!(f, "(")?;
+                if let Some(id) = it.next() {
+                    render_field(f, id)?;
+                }
+                for id in it {
+                    write!(f, ", ")?;
+                    render_field(f, id)?;
+                }
+                write!(f, ")")?;
+            }
+            return Ok(());
+        }
+        VariantData::Unit => Ok(()),
     }
 }
 
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 55803960e1a..1a4d003bf5e 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -35,7 +35,10 @@ mod tests;
 #[cfg(test)]
 mod test_db;
 
-use std::{collections::HashMap, hash::Hash};
+use std::{
+    collections::{hash_map::Entry, HashMap},
+    hash::Hash,
+};
 
 use chalk_ir::{
     fold::{Shift, TypeFoldable},
@@ -160,7 +163,16 @@ pub struct MemoryMap {
 
 impl MemoryMap {
     fn insert(&mut self, addr: usize, x: Vec<u8>) {
-        self.memory.insert(addr, x);
+        match self.memory.entry(addr) {
+            Entry::Occupied(mut e) => {
+                if e.get().len() < x.len() {
+                    e.insert(x);
+                }
+            }
+            Entry::Vacant(e) => {
+                e.insert(x);
+            }
+        }
     }
 
     /// This functions convert each address by a function `f` which gets the byte intervals and assign an address
@@ -172,6 +184,14 @@ impl MemoryMap {
     ) -> Result<HashMap<usize, usize>, MirEvalError> {
         self.memory.iter().map(|x| Ok((*x.0, f(x.1)?))).collect()
     }
+
+    fn get<'a>(&'a self, addr: usize, size: usize) -> Option<&'a [u8]> {
+        if size == 0 {
+            Some(&[])
+        } else {
+            self.memory.get(&addr)?.get(0..size)
+        }
+    }
 }
 
 /// A concrete constant value
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 28e7759db39..6e26d1f22aa 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -30,7 +30,7 @@ use crate::{
     method_resolution::{is_dyn_method, lookup_impl_method},
     name, static_lifetime,
     traits::FnTrait,
-    utils::ClosureSubst,
+    utils::{detect_variant_from_bytes, ClosureSubst},
     CallableDefId, ClosureId, Const, ConstScalar, FnDefId, GenericArgData, Interner, MemoryMap,
     Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
 };
@@ -1536,36 +1536,99 @@ impl Evaluator<'_> {
     }
 
     fn create_memory_map(&self, bytes: &[u8], ty: &Ty, locals: &Locals<'_>) -> Result<MemoryMap> {
-        // FIXME: support indirect references
-        let mut mm = MemoryMap::default();
-        match ty.kind(Interner) {
-            TyKind::Ref(_, _, t) => {
-                let size = self.size_align_of(t, locals)?;
-                match size {
-                    Some((size, _)) => {
-                        let addr_usize = from_bytes!(usize, bytes);
-                        mm.insert(
-                            addr_usize,
-                            self.read_memory(Address::from_usize(addr_usize), size)?.to_vec(),
-                        )
-                    }
-                    None => {
-                        let element_size = match t.kind(Interner) {
-                            TyKind::Str => 1,
-                            TyKind::Slice(t) => {
-                                self.size_of_sized(t, locals, "slice inner type")?
+        fn rec(
+            this: &Evaluator<'_>,
+            bytes: &[u8],
+            ty: &Ty,
+            locals: &Locals<'_>,
+            mm: &mut MemoryMap,
+        ) -> Result<()> {
+            match ty.kind(Interner) {
+                TyKind::Ref(_, _, t) => {
+                    let size = this.size_align_of(t, locals)?;
+                    match size {
+                        Some((size, _)) => {
+                            let addr_usize = from_bytes!(usize, bytes);
+                            mm.insert(
+                                addr_usize,
+                                this.read_memory(Address::from_usize(addr_usize), size)?.to_vec(),
+                            )
+                        }
+                        None => {
+                            let mut check_inner = None;
+                            let element_size = match t.kind(Interner) {
+                                TyKind::Str => 1,
+                                TyKind::Slice(t) => {
+                                    check_inner = Some(t);
+                                    this.size_of_sized(t, locals, "slice inner type")?
+                                }
+                                _ => return Ok(()), // FIXME: support other kind of unsized types
+                            };
+                            let (addr, meta) = bytes.split_at(bytes.len() / 2);
+                            let count = from_bytes!(usize, meta);
+                            let size = element_size * count;
+                            let addr = Address::from_bytes(addr)?;
+                            let b = this.read_memory(addr, size)?;
+                            mm.insert(addr.to_usize(), b.to_vec());
+                            if let Some(ty) = check_inner {
+                                for i in 0..count {
+                                    let offset = element_size * i;
+                                    rec(this, &b[offset..offset + element_size], ty, locals, mm)?;
+                                }
                             }
-                            _ => return Ok(mm), // FIXME: support other kind of unsized types
-                        };
-                        let (addr, meta) = bytes.split_at(bytes.len() / 2);
-                        let size = element_size * from_bytes!(usize, meta);
-                        let addr = Address::from_bytes(addr)?;
-                        mm.insert(addr.to_usize(), self.read_memory(addr, size)?.to_vec());
+                        }
+                    }
+                }
+                chalk_ir::TyKind::Tuple(_, subst) => {
+                    let layout = this.layout(ty)?;
+                    for (id, ty) in subst.iter(Interner).enumerate() {
+                        let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument
+                        let offset = layout.fields.offset(id).bytes_usize();
+                        let size = this.layout(ty)?.size.bytes_usize();
+                        rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
                     }
                 }
+                chalk_ir::TyKind::Adt(adt, subst) => match adt.0 {
+                    AdtId::StructId(s) => {
+                        let data = this.db.struct_data(s);
+                        let layout = this.layout(ty)?;
+                        let field_types = this.db.field_types(s.into());
+                        for (f, _) in data.variant_data.fields().iter() {
+                            let offset = layout
+                                .fields
+                                .offset(u32::from(f.into_raw()) as usize)
+                                .bytes_usize();
+                            let ty = &field_types[f].clone().substitute(Interner, subst);
+                            let size = this.layout(ty)?.size.bytes_usize();
+                            rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
+                        }
+                    }
+                    AdtId::EnumId(e) => {
+                        let layout = this.layout(ty)?;
+                        if let Some((v, l)) =
+                            detect_variant_from_bytes(&layout, this.db, this.crate_id, bytes, e)
+                        {
+                            let data = &this.db.enum_data(e).variants[v].variant_data;
+                            let field_types = this
+                                .db
+                                .field_types(EnumVariantId { parent: e, local_id: v }.into());
+                            for (f, _) in data.fields().iter() {
+                                let offset =
+                                    l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize();
+                                let ty = &field_types[f].clone().substitute(Interner, subst);
+                                let size = this.layout(ty)?.size.bytes_usize();
+                                rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
+                            }
+                        }
+                    }
+                    AdtId::UnionId(_) => (),
+                },
+                _ => (),
             }
-            _ => (),
+            Ok(())
         }
+        let mut mm = MemoryMap::default();
+        rec(self, bytes, ty, locals, &mut mm)?;
         Ok(mm)
     }
 
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 6fe157f45cf..5ed95133356 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -1855,7 +1855,7 @@ pub fn lower_to_mir(
     }
     let mut ctx = MirLowerCtx::new(db, owner, body, infer);
     // 0 is return local
-    ctx.result.locals.alloc(Local { ty: infer[root_expr].clone() });
+    ctx.result.locals.alloc(Local { ty: ctx.expr_ty_after_adjustments(root_expr) });
     let binding_picker = |b: BindingId| {
         if root_expr == body.body_expr {
             body[b].owner.is_none()
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index f60b4607f22..8f36188b78a 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -20,8 +20,8 @@ use hir_def::{
     lang_item::LangItem,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
-    ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId,
-    TypeOrConstParamId, TypeParamId,
+    ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId,
+    LocalEnumVariantId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId,
 };
 use hir_expand::name::Name;
 use intern::Interned;
@@ -30,8 +30,12 @@ use smallvec::{smallvec, SmallVec};
 use stdx::never;
 
 use crate::{
-    consteval::unknown_const, db::HirDatabase, ChalkTraitId, Const, ConstScalar, GenericArg,
-    Interner, Substitution, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
+    consteval::unknown_const,
+    db::HirDatabase,
+    layout::{Layout, TagEncoding},
+    mir::pad16,
+    ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt,
+    Ty, TyExt, WhereClause,
 };
 
 pub(crate) fn fn_traits(
@@ -440,3 +444,41 @@ impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
         Ok(constant)
     }
 }
+
+pub(crate) fn detect_variant_from_bytes<'a>(
+    layout: &'a Layout,
+    db: &dyn HirDatabase,
+    krate: CrateId,
+    b: &[u8],
+    e: EnumId,
+) -> Option<(LocalEnumVariantId, &'a Layout)> {
+    let (var_id, var_layout) = match &layout.variants {
+        hir_def::layout::Variants::Single { index } => (index.0, &*layout),
+        hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => {
+            let target_data_layout = db.target_data_layout(krate)?;
+            let size = tag.size(&*target_data_layout).bytes_usize();
+            let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field
+            let tag = i128::from_le_bytes(pad16(&b[offset..offset + size], false));
+            match tag_encoding {
+                TagEncoding::Direct => {
+                    let x = variants.iter_enumerated().find(|x| {
+                        db.const_eval_discriminant(EnumVariantId { parent: e, local_id: x.0 .0 })
+                            == Ok(tag)
+                    })?;
+                    (x.0 .0, x.1)
+                }
+                TagEncoding::Niche { untagged_variant, niche_start, .. } => {
+                    let candidate_tag = tag.wrapping_sub(*niche_start as i128) as usize;
+                    let variant = variants
+                        .iter_enumerated()
+                        .map(|(x, _)| x)
+                        .filter(|x| x != untagged_variant)
+                        .nth(candidate_tag)
+                        .unwrap_or(*untagged_variant);
+                    (variant.0, &variants[variant])
+                }
+            }
+        }
+    };
+    Some((var_id, var_layout))
+}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 19709bb44ad..2db4b483b69 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2106,14 +2106,6 @@ impl Const {
     pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
         let c = db.const_eval(self.id.into(), Substitution::empty(Interner))?;
         let r = format!("{}", HexifiedConst(c).display(db));
-        // We want to see things like `<utf8-error>` and `<layout-error>` as they are probably bug in our
-        // implementation, but there is no need to show things like `<enum-not-supported>` or `<ref-not-supported>` to
-        // the user.
-        if r.contains("not-supported>") {
-            return Err(ConstEvalError::MirEvalError(MirEvalError::NotSupported(
-                "rendering complex constants".to_string(),
-            )));
-        }
         return Ok(r);
     }
 }
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index f2ee79a23e6..d2c035c471e 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -4338,6 +4338,211 @@ const FOO$0: f64 = 1.0f64;
 }
 
 #[test]
+fn hover_const_eval_enum() {
+    check(
+        r#"
+enum Enum {
+    V1,
+    V2,
+}
+
+const VX: Enum = Enum::V1;
+
+const FOO$0: Enum = VX;
+"#,
+        expect![[r#"
+            *FOO*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const FOO: Enum = V1
+            ```
+        "#]],
+    );
+    check(
+        r#"
+//- minicore: option
+const FOO$0: Option<i32> = Some(2);
+"#,
+        expect![[r#"
+            *FOO*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const FOO: Option<i32> = Some(2)
+            ```
+        "#]],
+    );
+    check(
+        r#"
+//- minicore: option
+const FOO$0: Option<&i32> = Some(2).as_ref();
+"#,
+        expect![[r#"
+            *FOO*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const FOO: Option<&i32> = Some(&2)
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_const_eval_slice() {
+    check(
+        r#"
+//- minicore: slice, index, coerce_unsized
+const FOO$0: &[i32] = &[1, 2, 3 + 4];
+"#,
+        expect![[r#"
+            *FOO*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const FOO: &[i32] = &[1, 2, 7]
+            ```
+        "#]],
+    );
+    check(
+        r#"
+//- minicore: slice, index, coerce_unsized
+const FOO$0: &[i32; 5] = &[12; 5];
+"#,
+        expect![[r#"
+            *FOO*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const FOO: &[i32; 5] = &[12, 12, 12, 12, 12]
+            ```
+        "#]],
+    );
+    check(
+        r#"
+//- minicore: slice, index, coerce_unsized
+
+const FOO$0: (&i32, &[i32], &i32) = {
+    let a: &[i32] = &[1, 2, 3];
+    (&a[0], a, &a[0])
+}
+"#,
+        expect![[r#"
+            *FOO*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const FOO: (&i32, &[i32], &i32) = (&1, &[1, 2, 3], &1)
+            ```
+        "#]],
+    );
+    check(
+        r#"
+//- minicore: slice, index, coerce_unsized
+
+struct Tree(&[Tree]);
+
+const FOO$0: Tree = {
+    let x = &[Tree(&[]), Tree(&[Tree(&[])])];
+    Tree(&[Tree(x), Tree(x)])
+}
+"#,
+        expect![[r#"
+            *FOO*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const FOO: Tree = Tree(&[Tree(&[Tree(&[]), Tree(&[Tree(&[])])]), Tree(&[Tree(&[]), Tree(&[Tree(&[])])])])
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_const_eval_str() {
+    check(
+        r#"
+const FOO$0: &str = "foo";
+"#,
+        expect![[r#"
+            *FOO*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const FOO: &str = "foo"
+            ```
+        "#]],
+    );
+    check(
+        r#"
+struct X {
+    a: &'static str,
+    b: &'static str,
+}
+const FOO$0: X = X {
+    a: "axiom",
+    b: "buy N large",
+};
+"#,
+        expect![[r#"
+            *FOO*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const FOO: X = X { a: "axiom", b: "buy N large" }
+            ```
+        "#]],
+    );
+    check(
+        r#"
+const FOO$0: (&str, &str) = {
+    let x = "foo";
+    (x, x)
+};
+"#,
+        expect![[r#"
+            *FOO*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            const FOO: (&str, &str) = ("foo", "foo")
+            ```
+        "#]],
+    );
+}
+
+#[test]
 fn hover_const_eval_in_generic_trait() {
     // Doesn't compile, but we shouldn't crash.
     check(
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index 9f493449249..ce1e03a069b 100644
--- a/crates/ide/src/inlay_hints/chaining.rs
+++ b/crates/ide/src/inlay_hints/chaining.rs
@@ -474,7 +474,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9165..9173,
+                                        range: 9332..9340,
                                     },
                                 ),
                                 tooltip: "",
@@ -487,7 +487,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9197..9201,
+                                        range: 9364..9368,
                                     },
                                 ),
                                 tooltip: "",
@@ -511,7 +511,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9165..9173,
+                                        range: 9332..9340,
                                     },
                                 ),
                                 tooltip: "",
@@ -524,7 +524,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9197..9201,
+                                        range: 9364..9368,
                                     },
                                 ),
                                 tooltip: "",
@@ -548,7 +548,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9165..9173,
+                                        range: 9332..9340,
                                     },
                                 ),
                                 tooltip: "",
@@ -561,7 +561,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9197..9201,
+                                        range: 9364..9368,
                                     },
                                 ),
                                 tooltip: "",
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index 7f4838888bd..c9e85e36870 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -941,6 +941,13 @@ pub mod option {
             }
         }
 
+        pub const fn as_ref(&self) -> Option<&T> {
+            match self {
+                Some(x) => Some(x),
+                None => None,
+            }
+        }
+
         pub fn and<U>(self, optb: Option<U>) -> Option<U> {
             loop {}
         }