Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 5208bf8

Browse files
committed
implement type_name intrinsic
1 parent 274e830 commit 5208bf8

File tree

7 files changed

+158
-56
lines changed

7 files changed

+158
-56
lines changed

crates/base-db/src/fixture.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
2626
let fixture = ChangeFixture::parse(ra_fixture);
2727
let mut db = Self::default();
2828
fixture.change.apply(&mut db);
29-
assert_eq!(fixture.files.len(), 1);
29+
assert_eq!(fixture.files.len(), 1, "Multiple file found in the fixture");
3030
(db, fixture.files[0])
3131
}
3232

crates/hir-ty/src/consteval/tests.rs

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use hir_def::db::DefDatabase;
44

55
use crate::{
66
consteval::try_const_usize, db::HirDatabase, mir::pad16, test_db::TestDB, Const, ConstScalar,
7-
Interner,
7+
Interner, MemoryMap,
88
};
99

1010
use super::{
@@ -36,7 +36,7 @@ fn check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool) {
3636

3737
#[track_caller]
3838
fn check_number(ra_fixture: &str, answer: i128) {
39-
check_answer(ra_fixture, |b| {
39+
check_answer(ra_fixture, |b, _| {
4040
assert_eq!(
4141
b,
4242
&answer.to_le_bytes()[0..b.len()],
@@ -47,8 +47,26 @@ fn check_number(ra_fixture: &str, answer: i128) {
4747
}
4848

4949
#[track_caller]
50-
fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8])) {
51-
let (db, file_id) = TestDB::with_single_file(ra_fixture);
50+
fn check_str(ra_fixture: &str, answer: &str) {
51+
check_answer(ra_fixture, |b, mm| {
52+
let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
53+
let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
54+
let Some(bytes) = mm.get(addr, size) else {
55+
panic!("string data missed in the memory map");
56+
};
57+
assert_eq!(
58+
bytes,
59+
answer.as_bytes(),
60+
"Bytes differ. In string form: actual = {}, expected = {answer}",
61+
String::from_utf8_lossy(bytes)
62+
);
63+
});
64+
}
65+
66+
#[track_caller]
67+
fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) {
68+
let (db, file_ids) = TestDB::with_many_files(ra_fixture);
69+
let file_id = *file_ids.last().unwrap();
5270
let r = match eval_goal(&db, file_id) {
5371
Ok(t) => t,
5472
Err(e) => {
@@ -58,8 +76,8 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8])) {
5876
};
5977
match &r.data(Interner).value {
6078
chalk_ir::ConstValue::Concrete(c) => match &c.interned {
61-
ConstScalar::Bytes(b, _) => {
62-
check(b);
79+
ConstScalar::Bytes(b, mm) => {
80+
check(b, mm);
6381
}
6482
x => panic!("Expected number but found {:?}", x),
6583
},
@@ -224,7 +242,7 @@ const GOAL: usize = {
224242
transmute(&x)
225243
}
226244
"#,
227-
|b| assert_eq!(b[0] % 8, 0),
245+
|b, _| assert_eq!(b[0] % 8, 0),
228246
);
229247
check_answer(
230248
r#"
@@ -233,7 +251,7 @@ use core::mem::transmute;
233251
static X: i64 = 12;
234252
const GOAL: usize = transmute(&X);
235253
"#,
236-
|b| assert_eq!(b[0] % 8, 0),
254+
|b, _| assert_eq!(b[0] % 8, 0),
237255
);
238256
}
239257

@@ -2067,6 +2085,17 @@ fn array_and_index() {
20672085
);
20682086
}
20692087

2088+
#[test]
2089+
fn string() {
2090+
check_str(
2091+
r#"
2092+
//- minicore: coerce_unsized, index, slice
2093+
const GOAL: &str = "hello";
2094+
"#,
2095+
"hello",
2096+
);
2097+
}
2098+
20702099
#[test]
20712100
fn byte_string() {
20722101
check_number(
@@ -2443,6 +2472,25 @@ fn const_trait_assoc() {
24432472
"#,
24442473
32,
24452474
);
2475+
check_number(
2476+
r#"
2477+
//- /a/lib.rs crate:a
2478+
pub trait ToConst {
2479+
const VAL: usize;
2480+
}
2481+
pub const fn to_const<T: ToConst>() -> usize {
2482+
T::VAL
2483+
}
2484+
//- /main.rs crate:main deps:a
2485+
use a::{ToConst, to_const};
2486+
struct U0;
2487+
impl ToConst for U0 {
2488+
const VAL: usize = 5;
2489+
}
2490+
const GOAL: usize = to_const::<U0>();
2491+
"#,
2492+
5,
2493+
);
24462494
check_number(
24472495
r#"
24482496
struct S<T>(*mut T);

crates/hir-ty/src/consteval/tests/intrinsics.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,36 @@ fn min_align_of_val() {
149149
);
150150
}
151151

152+
#[test]
153+
fn type_name() {
154+
check_str(
155+
r#"
156+
extern "rust-intrinsic" {
157+
pub fn type_name<T: ?Sized>() -> &'static str;
158+
}
159+
160+
const GOAL: &str = type_name::<i32>();
161+
"#,
162+
"i32",
163+
);
164+
check_str(
165+
r#"
166+
extern "rust-intrinsic" {
167+
pub fn type_name<T: ?Sized>() -> &'static str;
168+
}
169+
170+
mod mod1 {
171+
pub mod mod2 {
172+
pub struct Ty;
173+
}
174+
}
175+
176+
const GOAL: &str = type_name::<mod1::mod2::Ty>();
177+
"#,
178+
"mod1::mod2::Ty",
179+
);
180+
}
181+
152182
#[test]
153183
fn transmute() {
154184
check_number(

crates/hir-ty/src/mir/eval.rs

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::{
2929
infer::PointerCast,
3030
layout::{Layout, LayoutError, RustcEnumVariantIdx},
3131
mapping::from_chalk,
32-
method_resolution::is_dyn_method,
32+
method_resolution::{is_dyn_method, lookup_impl_const},
3333
name, static_lifetime,
3434
traits::FnTrait,
3535
utils::{detect_variant_from_bytes, ClosureSubst},
@@ -1571,35 +1571,51 @@ impl Evaluator<'_> {
15711571
let chalk_ir::ConstValue::Concrete(c) = &konst.data(Interner).value else {
15721572
not_supported!("evaluating non concrete constant");
15731573
};
1574-
Ok(match &c.interned {
1575-
ConstScalar::Bytes(v, memory_map) => {
1576-
let mut v: Cow<'_, [u8]> = Cow::Borrowed(v);
1577-
let patch_map = memory_map.transform_addresses(|b, align| {
1578-
let addr = self.heap_allocate(b.len(), align)?;
1579-
self.write_memory(addr, b)?;
1580-
Ok(addr.to_usize())
1574+
let result_owner;
1575+
let (v, memory_map) = match &c.interned {
1576+
ConstScalar::Bytes(v, mm) => (v, mm),
1577+
ConstScalar::UnevaluatedConst(const_id, subst) => 'b: {
1578+
let mut const_id = *const_id;
1579+
let mut subst = subst.clone();
1580+
if let hir_def::GeneralConstId::ConstId(c) = const_id {
1581+
let (c, s) = lookup_impl_const(self.db, self.trait_env.clone(), c, subst);
1582+
const_id = hir_def::GeneralConstId::ConstId(c);
1583+
subst = s;
1584+
}
1585+
result_owner = self.db.const_eval(const_id.into(), subst).map_err(|e| {
1586+
let name = const_id.name(self.db.upcast());
1587+
MirEvalError::ConstEvalError(name, Box::new(e))
15811588
})?;
1582-
let (size, align) = self.size_align_of(ty, locals)?.unwrap_or((v.len(), 1));
1583-
if size != v.len() {
1584-
// Handle self enum
1585-
if size == 16 && v.len() < 16 {
1586-
v = Cow::Owned(pad16(&v, false).to_vec());
1587-
} else if size < 16 && v.len() == 16 {
1588-
v = Cow::Owned(v[0..size].to_vec());
1589-
} else {
1590-
return Err(MirEvalError::InvalidConst(konst.clone()));
1589+
if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value {
1590+
if let ConstScalar::Bytes(v, mm) = &c.interned {
1591+
break 'b (v, mm);
15911592
}
15921593
}
1593-
let addr = self.heap_allocate(size, align)?;
1594-
self.write_memory(addr, &v)?;
1595-
self.patch_addresses(&patch_map, &memory_map.vtable, addr, ty, locals)?;
1596-
Interval::new(addr, size)
1597-
}
1598-
ConstScalar::UnevaluatedConst(..) => {
1599-
not_supported!("unevaluated const present in monomorphized mir");
1594+
not_supported!("unevaluatable constant");
16001595
}
16011596
ConstScalar::Unknown => not_supported!("evaluating unknown const"),
1602-
})
1597+
};
1598+
let mut v: Cow<'_, [u8]> = Cow::Borrowed(v);
1599+
let patch_map = memory_map.transform_addresses(|b, align| {
1600+
let addr = self.heap_allocate(b.len(), align)?;
1601+
self.write_memory(addr, b)?;
1602+
Ok(addr.to_usize())
1603+
})?;
1604+
let (size, align) = self.size_align_of(ty, locals)?.unwrap_or((v.len(), 1));
1605+
if size != v.len() {
1606+
// Handle self enum
1607+
if size == 16 && v.len() < 16 {
1608+
v = Cow::Owned(pad16(&v, false).to_vec());
1609+
} else if size < 16 && v.len() == 16 {
1610+
v = Cow::Owned(v[0..size].to_vec());
1611+
} else {
1612+
return Err(MirEvalError::InvalidConst(konst.clone()));
1613+
}
1614+
}
1615+
let addr = self.heap_allocate(size, align)?;
1616+
self.write_memory(addr, &v)?;
1617+
self.patch_addresses(&patch_map, &memory_map.vtable, addr, ty, locals)?;
1618+
Ok(Interval::new(addr, size))
16031619
}
16041620

16051621
fn eval_place(&mut self, p: &Place, locals: &Locals) -> Result<Interval> {

crates/hir-ty/src/mir/eval/shim.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,26 @@ impl Evaluator<'_> {
602602
destination.write_from_bytes(self, &align.to_le_bytes())
603603
}
604604
}
605+
"type_name" => {
606+
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
607+
else {
608+
return Err(MirEvalError::TypeError("type_name generic arg is not provided"));
609+
};
610+
let Ok(ty_name) = ty.display_source_code(
611+
self.db,
612+
locals.body.owner.module(self.db.upcast()),
613+
true,
614+
) else {
615+
not_supported!("fail in generating type_name using source code display");
616+
};
617+
let len = ty_name.len();
618+
let addr = self.heap_allocate(len, 1)?;
619+
self.write_memory(addr, ty_name.as_bytes())?;
620+
destination.slice(0..self.ptr_size()).write_from_bytes(self, &addr.to_bytes())?;
621+
destination
622+
.slice(self.ptr_size()..2 * self.ptr_size())
623+
.write_from_bytes(self, &len.to_le_bytes())
624+
}
605625
"needs_drop" => {
606626
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
607627
else {

crates/hir-ty/src/mir/monomorphization.rs

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@ use chalk_ir::{
1313
fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable},
1414
ConstData, DebruijnIndex,
1515
};
16-
use hir_def::{DefWithBodyId, GeneralConstId};
16+
use hir_def::DefWithBodyId;
1717
use triomphe::Arc;
1818

1919
use crate::{
20-
consteval::unknown_const,
20+
consteval::{intern_const_scalar, unknown_const},
2121
db::HirDatabase,
2222
from_placeholder_idx,
2323
infer::normalize,
24-
method_resolution::lookup_impl_const,
2524
utils::{generics, Generics},
2625
ClosureId, Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind,
2726
};
@@ -193,25 +192,12 @@ impl Filler<'_> {
193192
| chalk_ir::ConstValue::Placeholder(_) => {}
194193
chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
195194
crate::ConstScalar::UnevaluatedConst(const_id, subst) => {
196-
let mut const_id = *const_id;
197195
let mut subst = subst.clone();
198196
self.fill_subst(&mut subst)?;
199-
if let GeneralConstId::ConstId(c) = const_id {
200-
let (c, s) = lookup_impl_const(
201-
self.db,
202-
self.db.trait_environment_for_body(self.owner),
203-
c,
204-
subst,
205-
);
206-
const_id = GeneralConstId::ConstId(c);
207-
subst = s;
208-
}
209-
let result =
210-
self.db.const_eval(const_id.into(), subst).map_err(|e| {
211-
let name = const_id.name(self.db.upcast());
212-
MirLowerError::ConstEvalError(name, Box::new(e))
213-
})?;
214-
*c = result;
197+
*c = intern_const_scalar(
198+
crate::ConstScalar::UnevaluatedConst(*const_id, subst),
199+
c.data(Interner).ty.clone(),
200+
);
215201
}
216202
crate::ConstScalar::Bytes(_, _) | crate::ConstScalar::Unknown => (),
217203
},

crates/ide/src/interpret_function.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<Strin
3434
_ => return None,
3535
};
3636
let span_formatter = |file_id, text_range: TextRange| {
37-
let line_col = db.line_index(file_id).line_col(text_range.start());
3837
let path = &db
3938
.source_root(db.file_source_root(file_id))
4039
.path_for_file(&file_id)
4140
.map(|x| x.to_string());
4241
let path = path.as_deref().unwrap_or("<unknown file>");
43-
format!("file://{path}#{}:{}", line_col.line + 1, line_col.col)
42+
match db.line_index(file_id).try_line_col(text_range.start()) {
43+
Some(line_col) => format!("file://{path}#{}:{}", line_col.line + 1, line_col.col),
44+
None => format!("file://{path} range {:?}", text_range),
45+
}
4446
};
4547
Some(def.eval(db, span_formatter))
4648
}

0 commit comments

Comments
 (0)