Skip to content

Commit f9e3b18

Browse files
committed
Add enum, reference, array and slice to render_const_scalar
1 parent 4458e7f commit f9e3b18

File tree

9 files changed

+561
-115
lines changed

9 files changed

+561
-115
lines changed

crates/hir-ty/src/display.rs

Lines changed: 185 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,26 @@ use hir_def::{
1616
path::{Path, PathKind},
1717
type_ref::{TraitBoundModifier, TypeBound, TypeRef},
1818
visibility::Visibility,
19-
HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId,
19+
EnumVariantId, HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId,
20+
TraitId,
2021
};
2122
use hir_expand::{hygiene::Hygiene, name::Name};
2223
use intern::{Internable, Interned};
2324
use itertools::Itertools;
25+
use la_arena::ArenaMap;
2426
use smallvec::SmallVec;
2527
use stdx::never;
2628

2729
use crate::{
30+
consteval::try_const_usize,
2831
db::HirDatabase,
29-
from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
32+
from_assoc_type_id, from_foreign_def_id, from_placeholder_idx,
33+
layout::Layout,
34+
lt_from_placeholder_idx,
3035
mapping::from_chalk,
3136
mir::pad16,
3237
primitive, to_assoc_type_id,
33-
utils::{self, generics, ClosureSubst},
38+
utils::{self, detect_variant_from_bytes, generics, ClosureSubst},
3439
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstScalar, ConstValue,
3540
DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives,
3641
MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar,
@@ -469,7 +474,7 @@ fn render_const_scalar(
469474
// infrastructure and have it here as a field on `f`.
470475
let krate = *f.db.crate_graph().crates_in_topological_order().last().unwrap();
471476
match ty.kind(Interner) {
472-
chalk_ir::TyKind::Scalar(s) => match s {
477+
TyKind::Scalar(s) => match s {
473478
Scalar::Bool => write!(f, "{}", if b[0] == 0 { false } else { true }),
474479
Scalar::Char => {
475480
let x = u128::from_le_bytes(pad16(b, false)) as u32;
@@ -497,17 +502,54 @@ fn render_const_scalar(
497502
}
498503
},
499504
},
500-
chalk_ir::TyKind::Ref(_, _, t) => match t.kind(Interner) {
501-
chalk_ir::TyKind::Str => {
505+
TyKind::Ref(_, _, t) => match t.kind(Interner) {
506+
TyKind::Str => {
502507
let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
503-
let bytes = memory_map.memory.get(&addr).map(|x| &**x).unwrap_or(&[]);
504-
let s = std::str::from_utf8(bytes).unwrap_or("<utf8-error>");
508+
let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
509+
let Some(bytes) = memory_map.get(addr, size) else {
510+
return f.write_str("<ref-data-not-available>");
511+
};
512+
let s = std::str::from_utf8(&bytes).unwrap_or("<utf8-error>");
505513
write!(f, "{s:?}")
506514
}
507-
_ => f.write_str("<ref-not-supported>"),
515+
TyKind::Slice(ty) => {
516+
let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
517+
let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
518+
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
519+
return f.write_str("<layout-error>");
520+
};
521+
let size_one = layout.size.bytes_usize();
522+
let Some(bytes) = memory_map.get(addr, size_one * count) else {
523+
return f.write_str("<ref-data-not-available>");
524+
};
525+
f.write_str("&[")?;
526+
let mut first = true;
527+
for i in 0..count {
528+
if first {
529+
first = false;
530+
} else {
531+
f.write_str(", ")?;
532+
}
533+
let offset = size_one * i;
534+
render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, &ty)?;
535+
}
536+
f.write_str("]")
537+
}
538+
_ => {
539+
let addr = usize::from_le_bytes(b.try_into().unwrap());
540+
let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
541+
return f.write_str("<layout-error>");
542+
};
543+
let size = layout.size.bytes_usize();
544+
let Some(bytes) = memory_map.get(addr, size) else {
545+
return f.write_str("<ref-data-not-available>");
546+
};
547+
f.write_str("&")?;
548+
render_const_scalar(f, bytes, memory_map, t)
549+
}
508550
},
509-
chalk_ir::TyKind::Tuple(_, subst) => {
510-
let Ok(layout) = f.db.layout_of_ty( ty.clone(), krate) else {
551+
TyKind::Tuple(_, subst) => {
552+
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
511553
return f.write_str("<layout-error>");
512554
};
513555
f.write_str("(")?;
@@ -529,69 +571,144 @@ fn render_const_scalar(
529571
}
530572
f.write_str(")")
531573
}
532-
chalk_ir::TyKind::Adt(adt, subst) => match adt.0 {
533-
hir_def::AdtId::StructId(s) => {
534-
let data = f.db.struct_data(s);
535-
let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), krate) else {
536-
return f.write_str("<layout-error>");
537-
};
538-
match data.variant_data.as_ref() {
539-
VariantData::Record(fields) | VariantData::Tuple(fields) => {
540-
let field_types = f.db.field_types(s.into());
541-
let krate = adt.0.module(f.db.upcast()).krate();
542-
let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
543-
let offset = layout
544-
.fields
545-
.offset(u32::from(id.into_raw()) as usize)
546-
.bytes_usize();
547-
let ty = field_types[id].clone().substitute(Interner, subst);
548-
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
549-
return f.write_str("<layout-error>");
550-
};
551-
let size = layout.size.bytes_usize();
552-
render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
553-
};
554-
let mut it = fields.iter();
555-
if matches!(data.variant_data.as_ref(), VariantData::Record(_)) {
556-
write!(f, "{} {{", data.name.display(f.db.upcast()))?;
557-
if let Some((id, data)) = it.next() {
558-
write!(f, " {}: ", data.name.display(f.db.upcast()))?;
559-
render_field(f, id)?;
560-
}
561-
for (id, data) in it {
562-
write!(f, ", {}: ", data.name.display(f.db.upcast()))?;
563-
render_field(f, id)?;
564-
}
565-
write!(f, " }}")?;
566-
} else {
567-
let mut it = it.map(|x| x.0);
568-
write!(f, "{}(", data.name.display(f.db.upcast()))?;
569-
if let Some(id) = it.next() {
570-
render_field(f, id)?;
571-
}
572-
for id in it {
573-
write!(f, ", ")?;
574-
render_field(f, id)?;
575-
}
576-
write!(f, ")")?;
577-
}
578-
return Ok(());
579-
}
580-
VariantData::Unit => write!(f, "{}", data.name.display(f.db.upcast())),
574+
TyKind::Adt(adt, subst) => {
575+
let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), krate) else {
576+
return f.write_str("<layout-error>");
577+
};
578+
match adt.0 {
579+
hir_def::AdtId::StructId(s) => {
580+
let data = f.db.struct_data(s);
581+
write!(f, "{}", data.name.display(f.db.upcast()))?;
582+
let field_types = f.db.field_types(s.into());
583+
render_variant_after_name(
584+
&data.variant_data,
585+
f,
586+
&field_types,
587+
adt.0.module(f.db.upcast()).krate(),
588+
&layout,
589+
subst,
590+
b,
591+
memory_map,
592+
)
593+
}
594+
hir_def::AdtId::UnionId(u) => {
595+
write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast()))
596+
}
597+
hir_def::AdtId::EnumId(e) => {
598+
let Some((var_id, var_layout)) =
599+
detect_variant_from_bytes(&layout, f.db, krate, b, e) else {
600+
return f.write_str("<failed-to-detect-variant>");
601+
};
602+
let data = &f.db.enum_data(e).variants[var_id];
603+
write!(f, "{}", data.name.display(f.db.upcast()))?;
604+
let field_types =
605+
f.db.field_types(EnumVariantId { parent: e, local_id: var_id }.into());
606+
render_variant_after_name(
607+
&data.variant_data,
608+
f,
609+
&field_types,
610+
adt.0.module(f.db.upcast()).krate(),
611+
&var_layout,
612+
subst,
613+
b,
614+
memory_map,
615+
)
581616
}
582617
}
583-
hir_def::AdtId::UnionId(u) => {
584-
write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast()))
585-
}
586-
hir_def::AdtId::EnumId(_) => f.write_str("<enum-not-supported>"),
587-
},
588-
chalk_ir::TyKind::FnDef(..) => ty.hir_fmt(f),
589-
chalk_ir::TyKind::Raw(_, _) => {
618+
}
619+
TyKind::FnDef(..) => ty.hir_fmt(f),
620+
TyKind::Function(_) | TyKind::Raw(_, _) => {
590621
let x = u128::from_le_bytes(pad16(b, false));
591622
write!(f, "{:#X} as ", x)?;
592623
ty.hir_fmt(f)
593624
}
594-
_ => f.write_str("<not-supported>"),
625+
TyKind::Array(ty, len) => {
626+
let Some(len) = try_const_usize(f.db, len) else {
627+
return f.write_str("<unknown-array-len>");
628+
};
629+
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
630+
return f.write_str("<layout-error>");
631+
};
632+
let size_one = layout.size.bytes_usize();
633+
f.write_str("[")?;
634+
let mut first = true;
635+
for i in 0..len as usize {
636+
if first {
637+
first = false;
638+
} else {
639+
f.write_str(", ")?;
640+
}
641+
let offset = size_one * i;
642+
render_const_scalar(f, &b[offset..offset + size_one], memory_map, &ty)?;
643+
}
644+
f.write_str("]")
645+
}
646+
TyKind::Never => f.write_str("!"),
647+
TyKind::Closure(_, _) => f.write_str("<closure>"),
648+
TyKind::Generator(_, _) => f.write_str("<generator>"),
649+
TyKind::GeneratorWitness(_, _) => f.write_str("<generator-witness>"),
650+
// The below arms are unreachable, since const eval will bail out before here.
651+
TyKind::Foreign(_) => f.write_str("<extern-type>"),
652+
TyKind::Error
653+
| TyKind::Placeholder(_)
654+
| TyKind::Alias(_)
655+
| TyKind::AssociatedType(_, _)
656+
| TyKind::OpaqueType(_, _)
657+
| TyKind::BoundVar(_)
658+
| TyKind::InferenceVar(_, _) => f.write_str("<placeholder-or-unknown-type>"),
659+
// The below arms are unreachable, since we handled them in ref case.
660+
TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => f.write_str("<unsized-value>"),
661+
}
662+
}
663+
664+
fn render_variant_after_name(
665+
data: &VariantData,
666+
f: &mut HirFormatter<'_>,
667+
field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
668+
krate: CrateId,
669+
layout: &Layout,
670+
subst: &Substitution,
671+
b: &[u8],
672+
memory_map: &MemoryMap,
673+
) -> Result<(), HirDisplayError> {
674+
match data {
675+
VariantData::Record(fields) | VariantData::Tuple(fields) => {
676+
let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
677+
let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
678+
let ty = field_types[id].clone().substitute(Interner, subst);
679+
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
680+
return f.write_str("<layout-error>");
681+
};
682+
let size = layout.size.bytes_usize();
683+
render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
684+
};
685+
let mut it = fields.iter();
686+
if matches!(data, VariantData::Record(_)) {
687+
write!(f, " {{")?;
688+
if let Some((id, data)) = it.next() {
689+
write!(f, " {}: ", data.name.display(f.db.upcast()))?;
690+
render_field(f, id)?;
691+
}
692+
for (id, data) in it {
693+
write!(f, ", {}: ", data.name.display(f.db.upcast()))?;
694+
render_field(f, id)?;
695+
}
696+
write!(f, " }}")?;
697+
} else {
698+
let mut it = it.map(|x| x.0);
699+
write!(f, "(")?;
700+
if let Some(id) = it.next() {
701+
render_field(f, id)?;
702+
}
703+
for id in it {
704+
write!(f, ", ")?;
705+
render_field(f, id)?;
706+
}
707+
write!(f, ")")?;
708+
}
709+
return Ok(());
710+
}
711+
VariantData::Unit => Ok(()),
595712
}
596713
}
597714

crates/hir-ty/src/lib.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ mod tests;
3535
#[cfg(test)]
3636
mod test_db;
3737

38-
use std::{collections::HashMap, hash::Hash};
38+
use std::{
39+
collections::{hash_map::Entry, HashMap},
40+
hash::Hash,
41+
};
3942

4043
use chalk_ir::{
4144
fold::{Shift, TypeFoldable},
@@ -160,7 +163,16 @@ pub struct MemoryMap {
160163

161164
impl MemoryMap {
162165
fn insert(&mut self, addr: usize, x: Vec<u8>) {
163-
self.memory.insert(addr, x);
166+
match self.memory.entry(addr) {
167+
Entry::Occupied(mut e) => {
168+
if e.get().len() < x.len() {
169+
e.insert(x);
170+
}
171+
}
172+
Entry::Vacant(e) => {
173+
e.insert(x);
174+
}
175+
}
164176
}
165177

166178
/// This functions convert each address by a function `f` which gets the byte intervals and assign an address
@@ -172,6 +184,14 @@ impl MemoryMap {
172184
) -> Result<HashMap<usize, usize>, MirEvalError> {
173185
self.memory.iter().map(|x| Ok((*x.0, f(x.1)?))).collect()
174186
}
187+
188+
fn get<'a>(&'a self, addr: usize, size: usize) -> Option<&'a [u8]> {
189+
if size == 0 {
190+
Some(&[])
191+
} else {
192+
self.memory.get(&addr)?.get(0..size)
193+
}
194+
}
175195
}
176196

177197
/// A concrete constant value

0 commit comments

Comments
 (0)