Unnamed repository; edit this file 'description' to name the repository.
-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 058d5059b1..a401c49ed2 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -16,21 +16,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,
@@ -469,7 +474,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;
@@ -497,17 +502,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("(")?;
@@ -529,69 +571,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 55803960e1..1a4d003bf5 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 28e7759db3..6e26d1f22a 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 6fe157f45c..5ed9513335 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 f60b4607f2..8f36188b78 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 7c432197a6..9e85690ec5 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2107,14 +2107,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 f2ee79a23e..d2c035c471 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 9f49344924..ce1e03a069 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 7f4838888b..c9e85e3687 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 {}
}