Skip to content

Commit 0677c20

Browse files
committed
Auto merge of #14947 - HKalbasi:render-const, r=HKalbasi
Add enum, reference, array and slice to `render_const_scalar`
2 parents 0b4c09b + f9e3b18 commit 0677c20

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
@@ -17,21 +17,26 @@ use hir_def::{
1717
path::{Path, PathKind},
1818
type_ref::{TraitBoundModifier, TypeBound, TypeRef},
1919
visibility::Visibility,
20-
HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId,
20+
EnumVariantId, HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId,
21+
TraitId,
2122
};
2223
use hir_expand::{hygiene::Hygiene, name::Name};
2324
use intern::{Internable, Interned};
2425
use itertools::Itertools;
26+
use la_arena::ArenaMap;
2527
use smallvec::SmallVec;
2628
use stdx::never;
2729

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

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)