From 5208bf8f55e155f4bc84914e32e57175ef5d973f Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Fri, 14 Jul 2023 16:52:36 +0330 Subject: [PATCH 1/2] implement type_name intrinsic --- crates/base-db/src/fixture.rs | 2 +- crates/hir-ty/src/consteval/tests.rs | 64 +++++++++++++++--- .../hir-ty/src/consteval/tests/intrinsics.rs | 30 +++++++++ crates/hir-ty/src/mir/eval.rs | 66 ++++++++++++------- crates/hir-ty/src/mir/eval/shim.rs | 20 ++++++ crates/hir-ty/src/mir/monomorphization.rs | 26 ++------ crates/ide/src/interpret_function.rs | 6 +- 7 files changed, 158 insertions(+), 56 deletions(-) diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 6bfdf402c44..323ee4260e4 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -26,7 +26,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); fixture.change.apply(&mut db); - assert_eq!(fixture.files.len(), 1); + assert_eq!(fixture.files.len(), 1, "Multiple file found in the fixture"); (db, fixture.files[0]) } diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 4ca1d8a2394..db5a43e0673 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -4,7 +4,7 @@ use hir_def::db::DefDatabase; use crate::{ consteval::try_const_usize, db::HirDatabase, mir::pad16, test_db::TestDB, Const, ConstScalar, - Interner, + Interner, MemoryMap, }; use super::{ @@ -36,7 +36,7 @@ fn check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool) { #[track_caller] fn check_number(ra_fixture: &str, answer: i128) { - check_answer(ra_fixture, |b| { + check_answer(ra_fixture, |b, _| { assert_eq!( b, &answer.to_le_bytes()[0..b.len()], @@ -47,8 +47,26 @@ fn check_number(ra_fixture: &str, answer: i128) { } #[track_caller] -fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8])) { - let (db, file_id) = TestDB::with_single_file(ra_fixture); +fn check_str(ra_fixture: &str, answer: &str) { + check_answer(ra_fixture, |b, mm| { + let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); + let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); + let Some(bytes) = mm.get(addr, size) else { + panic!("string data missed in the memory map"); + }; + assert_eq!( + bytes, + answer.as_bytes(), + "Bytes differ. In string form: actual = {}, expected = {answer}", + String::from_utf8_lossy(bytes) + ); + }); +} + +#[track_caller] +fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) { + let (db, file_ids) = TestDB::with_many_files(ra_fixture); + let file_id = *file_ids.last().unwrap(); let r = match eval_goal(&db, file_id) { Ok(t) => t, Err(e) => { @@ -58,8 +76,8 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8])) { }; match &r.data(Interner).value { chalk_ir::ConstValue::Concrete(c) => match &c.interned { - ConstScalar::Bytes(b, _) => { - check(b); + ConstScalar::Bytes(b, mm) => { + check(b, mm); } x => panic!("Expected number but found {:?}", x), }, @@ -224,7 +242,7 @@ const GOAL: usize = { transmute(&x) } "#, - |b| assert_eq!(b[0] % 8, 0), + |b, _| assert_eq!(b[0] % 8, 0), ); check_answer( r#" @@ -233,7 +251,7 @@ use core::mem::transmute; static X: i64 = 12; const GOAL: usize = transmute(&X); "#, - |b| assert_eq!(b[0] % 8, 0), + |b, _| assert_eq!(b[0] % 8, 0), ); } @@ -2067,6 +2085,17 @@ fn array_and_index() { ); } +#[test] +fn string() { + check_str( + r#" + //- minicore: coerce_unsized, index, slice + const GOAL: &str = "hello"; + "#, + "hello", + ); +} + #[test] fn byte_string() { check_number( @@ -2443,6 +2472,25 @@ fn const_trait_assoc() { "#, 32, ); + check_number( + r#" + //- /a/lib.rs crate:a + pub trait ToConst { + const VAL: usize; + } + pub const fn to_const() -> usize { + T::VAL + } + //- /main.rs crate:main deps:a + use a::{ToConst, to_const}; + struct U0; + impl ToConst for U0 { + const VAL: usize = 5; + } + const GOAL: usize = to_const::(); + "#, + 5, + ); check_number( r#" struct S(*mut T); diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs index 30e87661abc..9253e31d77b 100644 --- a/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -149,6 +149,36 @@ fn min_align_of_val() { ); } +#[test] +fn type_name() { + check_str( + r#" + extern "rust-intrinsic" { + pub fn type_name() -> &'static str; + } + + const GOAL: &str = type_name::(); + "#, + "i32", + ); + check_str( + r#" + extern "rust-intrinsic" { + pub fn type_name() -> &'static str; + } + + mod mod1 { + pub mod mod2 { + pub struct Ty; + } + } + + const GOAL: &str = type_name::(); + "#, + "mod1::mod2::Ty", + ); +} + #[test] fn transmute() { check_number( diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 47c93547683..d7820de629a 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -29,7 +29,7 @@ use crate::{ infer::PointerCast, layout::{Layout, LayoutError, RustcEnumVariantIdx}, mapping::from_chalk, - method_resolution::is_dyn_method, + method_resolution::{is_dyn_method, lookup_impl_const}, name, static_lifetime, traits::FnTrait, utils::{detect_variant_from_bytes, ClosureSubst}, @@ -1571,35 +1571,51 @@ impl Evaluator<'_> { let chalk_ir::ConstValue::Concrete(c) = &konst.data(Interner).value else { not_supported!("evaluating non concrete constant"); }; - Ok(match &c.interned { - ConstScalar::Bytes(v, memory_map) => { - let mut v: Cow<'_, [u8]> = Cow::Borrowed(v); - let patch_map = memory_map.transform_addresses(|b, align| { - let addr = self.heap_allocate(b.len(), align)?; - self.write_memory(addr, b)?; - Ok(addr.to_usize()) + let result_owner; + let (v, memory_map) = match &c.interned { + ConstScalar::Bytes(v, mm) => (v, mm), + ConstScalar::UnevaluatedConst(const_id, subst) => 'b: { + let mut const_id = *const_id; + let mut subst = subst.clone(); + if let hir_def::GeneralConstId::ConstId(c) = const_id { + let (c, s) = lookup_impl_const(self.db, self.trait_env.clone(), c, subst); + const_id = hir_def::GeneralConstId::ConstId(c); + subst = s; + } + result_owner = self.db.const_eval(const_id.into(), subst).map_err(|e| { + let name = const_id.name(self.db.upcast()); + MirEvalError::ConstEvalError(name, Box::new(e)) })?; - let (size, align) = self.size_align_of(ty, locals)?.unwrap_or((v.len(), 1)); - if size != v.len() { - // Handle self enum - if size == 16 && v.len() < 16 { - v = Cow::Owned(pad16(&v, false).to_vec()); - } else if size < 16 && v.len() == 16 { - v = Cow::Owned(v[0..size].to_vec()); - } else { - return Err(MirEvalError::InvalidConst(konst.clone())); + if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value { + if let ConstScalar::Bytes(v, mm) = &c.interned { + break 'b (v, mm); } } - let addr = self.heap_allocate(size, align)?; - self.write_memory(addr, &v)?; - self.patch_addresses(&patch_map, &memory_map.vtable, addr, ty, locals)?; - Interval::new(addr, size) - } - ConstScalar::UnevaluatedConst(..) => { - not_supported!("unevaluated const present in monomorphized mir"); + not_supported!("unevaluatable constant"); } ConstScalar::Unknown => not_supported!("evaluating unknown const"), - }) + }; + let mut v: Cow<'_, [u8]> = Cow::Borrowed(v); + let patch_map = memory_map.transform_addresses(|b, align| { + let addr = self.heap_allocate(b.len(), align)?; + self.write_memory(addr, b)?; + Ok(addr.to_usize()) + })?; + let (size, align) = self.size_align_of(ty, locals)?.unwrap_or((v.len(), 1)); + if size != v.len() { + // Handle self enum + if size == 16 && v.len() < 16 { + v = Cow::Owned(pad16(&v, false).to_vec()); + } else if size < 16 && v.len() == 16 { + v = Cow::Owned(v[0..size].to_vec()); + } else { + return Err(MirEvalError::InvalidConst(konst.clone())); + } + } + let addr = self.heap_allocate(size, align)?; + self.write_memory(addr, &v)?; + self.patch_addresses(&patch_map, &memory_map.vtable, addr, ty, locals)?; + Ok(Interval::new(addr, size)) } fn eval_place(&mut self, p: &Place, locals: &Locals) -> Result { diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index cedc4538037..28a5e50a56a 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -602,6 +602,26 @@ impl Evaluator<'_> { destination.write_from_bytes(self, &align.to_le_bytes()) } } + "type_name" => { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + else { + return Err(MirEvalError::TypeError("type_name generic arg is not provided")); + }; + let Ok(ty_name) = ty.display_source_code( + self.db, + locals.body.owner.module(self.db.upcast()), + true, + ) else { + not_supported!("fail in generating type_name using source code display"); + }; + let len = ty_name.len(); + let addr = self.heap_allocate(len, 1)?; + self.write_memory(addr, ty_name.as_bytes())?; + destination.slice(0..self.ptr_size()).write_from_bytes(self, &addr.to_bytes())?; + destination + .slice(self.ptr_size()..2 * self.ptr_size()) + .write_from_bytes(self, &len.to_le_bytes()) + } "needs_drop" => { let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs index e4574c77e23..c565228d91e 100644 --- a/crates/hir-ty/src/mir/monomorphization.rs +++ b/crates/hir-ty/src/mir/monomorphization.rs @@ -13,15 +13,14 @@ use chalk_ir::{ fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}, ConstData, DebruijnIndex, }; -use hir_def::{DefWithBodyId, GeneralConstId}; +use hir_def::DefWithBodyId; use triomphe::Arc; use crate::{ - consteval::unknown_const, + consteval::{intern_const_scalar, unknown_const}, db::HirDatabase, from_placeholder_idx, infer::normalize, - method_resolution::lookup_impl_const, utils::{generics, Generics}, ClosureId, Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind, }; @@ -193,25 +192,12 @@ impl Filler<'_> { | chalk_ir::ConstValue::Placeholder(_) => {} chalk_ir::ConstValue::Concrete(cc) => match &cc.interned { crate::ConstScalar::UnevaluatedConst(const_id, subst) => { - let mut const_id = *const_id; let mut subst = subst.clone(); self.fill_subst(&mut subst)?; - if let GeneralConstId::ConstId(c) = const_id { - let (c, s) = lookup_impl_const( - self.db, - self.db.trait_environment_for_body(self.owner), - c, - subst, - ); - const_id = GeneralConstId::ConstId(c); - subst = s; - } - let result = - self.db.const_eval(const_id.into(), subst).map_err(|e| { - let name = const_id.name(self.db.upcast()); - MirLowerError::ConstEvalError(name, Box::new(e)) - })?; - *c = result; + *c = intern_const_scalar( + crate::ConstScalar::UnevaluatedConst(*const_id, subst), + c.data(Interner).ty.clone(), + ); } crate::ConstScalar::Bytes(_, _) | crate::ConstScalar::Unknown => (), }, diff --git a/crates/ide/src/interpret_function.rs b/crates/ide/src/interpret_function.rs index cbcbb4b09db..d06ffd53575 100644 --- a/crates/ide/src/interpret_function.rs +++ b/crates/ide/src/interpret_function.rs @@ -34,13 +34,15 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option return None, }; let span_formatter = |file_id, text_range: TextRange| { - let line_col = db.line_index(file_id).line_col(text_range.start()); let path = &db .source_root(db.file_source_root(file_id)) .path_for_file(&file_id) .map(|x| x.to_string()); let path = path.as_deref().unwrap_or(""); - format!("file://{path}#{}:{}", line_col.line + 1, line_col.col) + match db.line_index(file_id).try_line_col(text_range.start()) { + Some(line_col) => format!("file://{path}#{}:{}", line_col.line + 1, line_col.col), + None => format!("file://{path} range {:?}", text_range), + } }; Some(def.eval(db, span_formatter)) } From 50559118fbb5d94c5617835bd8c5d294393acaf5 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Fri, 14 Jul 2023 20:15:18 +0330 Subject: [PATCH 2/2] Give real discriminant_type to chalk --- .../builtin_derive_macro.rs | 38 +++++++++++++++++++ crates/hir-expand/src/builtin_derive_macro.rs | 32 ++++++++-------- crates/hir-ty/src/chalk_db.rs | 34 +++++++++++++++-- crates/hir-ty/src/layout/tests.rs | 38 +++++++++++++++++++ crates/ide/src/inlay_hints/chaining.rs | 12 +++--- crates/test-utils/src/minicore.rs | 5 +++ 6 files changed, 135 insertions(+), 24 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs index 145cf8ddd40..abd84c6a46d 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs @@ -416,6 +416,44 @@ fn test_hash_expand() { //- minicore: derive, hash use core::hash::Hash; +#[derive(Hash)] +struct Foo { + x: i32, + y: u64, + z: (i32, u64), +} +"#, + expect![[r#" +use core::hash::Hash; + +#[derive(Hash)] +struct Foo { + x: i32, + y: u64, + z: (i32, u64), +} + +impl < > core::hash::Hash for Foo< > where { + fn hash(&self , ra_expand_state: &mut H) { + match self { + Foo { + x: x, y: y, z: z, + } + => { + x.hash(ra_expand_state); + y.hash(ra_expand_state); + z.hash(ra_expand_state); + } + , + } + } +}"#]], + ); + check( + r#" +//- minicore: derive, hash +use core::hash::Hash; + #[derive(Hash)] enum Command { Move { x: i32, y: i32 }, diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs index c8c3cebb88e..ecc8b407a9c 100644 --- a/crates/hir-expand/src/builtin_derive_macro.rs +++ b/crates/hir-expand/src/builtin_derive_macro.rs @@ -624,9 +624,14 @@ fn hash_expand( } }, ); + let check_discriminant = if matches!(&adt.shape, AdtShape::Enum { .. }) { + quote! { #krate::mem::discriminant(self).hash(ra_expand_state); } + } else { + quote! {} + }; quote! { fn hash(&self, ra_expand_state: &mut H) { - #krate::mem::discriminant(self).hash(ra_expand_state); + #check_discriminant match self { ##arms } @@ -742,9 +747,6 @@ fn ord_expand( // FIXME: Return expand error here return quote!(); } - let left = quote!(#krate::intrinsics::discriminant_value(self)); - let right = quote!(#krate::intrinsics::discriminant_value(other)); - let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name); let arms = izip!(self_patterns, other_patterns, adt.shape.field_names()).map( |(pat1, pat2, fields)| { @@ -759,17 +761,17 @@ fn ord_expand( }, ); let fat_arrow = fat_arrow(); - let body = compare( - krate, - left, - right, - quote! { - match (self, other) { - ##arms - _unused #fat_arrow #krate::cmp::Ordering::Equal - } - }, - ); + let mut body = quote! { + match (self, other) { + ##arms + _unused #fat_arrow #krate::cmp::Ordering::Equal + } + }; + if matches!(&adt.shape, AdtShape::Enum { .. }) { + let left = quote!(#krate::intrinsics::discriminant_value(self)); + let right = quote!(#krate::intrinsics::discriminant_value(other)); + body = compare(krate, left, right, body); + } quote! { fn cmp(&self, other: &Self) -> #krate::cmp::Ordering { #body diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index 50eabc867b8..f4fbace19e3 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -60,9 +60,37 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { // FIXME: keep track of these Arc::new(rust_ir::AdtRepr { c: false, packed: false, int: None }) } - fn discriminant_type(&self, _ty: chalk_ir::Ty) -> chalk_ir::Ty { - // FIXME: keep track of this - chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32)).intern(Interner) + fn discriminant_type(&self, ty: chalk_ir::Ty) -> chalk_ir::Ty { + if let chalk_ir::TyKind::Adt(id, _) = ty.kind(Interner) { + if let hir_def::AdtId::EnumId(e) = id.0 { + let enum_data = self.db.enum_data(e); + let ty = enum_data.repr.unwrap_or_default().discr_type(); + return chalk_ir::TyKind::Scalar(match ty { + hir_def::layout::IntegerType::Pointer(is_signed) => match is_signed { + true => chalk_ir::Scalar::Int(chalk_ir::IntTy::Isize), + false => chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize), + }, + hir_def::layout::IntegerType::Fixed(size, is_signed) => match is_signed { + true => chalk_ir::Scalar::Int(match size { + hir_def::layout::Integer::I8 => chalk_ir::IntTy::I8, + hir_def::layout::Integer::I16 => chalk_ir::IntTy::I16, + hir_def::layout::Integer::I32 => chalk_ir::IntTy::I32, + hir_def::layout::Integer::I64 => chalk_ir::IntTy::I64, + hir_def::layout::Integer::I128 => chalk_ir::IntTy::I128, + }), + false => chalk_ir::Scalar::Uint(match size { + hir_def::layout::Integer::I8 => chalk_ir::UintTy::U8, + hir_def::layout::Integer::I16 => chalk_ir::UintTy::U16, + hir_def::layout::Integer::I32 => chalk_ir::UintTy::U32, + hir_def::layout::Integer::I64 => chalk_ir::UintTy::U64, + hir_def::layout::Integer::I128 => chalk_ir::UintTy::U128, + }), + }, + }) + .intern(Interner); + } + } + chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U8)).intern(Interner) } fn impl_datum(&self, impl_id: ImplId) -> Arc { self.db.impl_datum(self.krate, impl_id) diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index 2b74f1a1a1d..a3ced2bac0a 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -464,3 +464,41 @@ fn enums_with_discriminants() { } } } + +#[test] +fn core_mem_discriminant() { + size_and_align! { + minicore: discriminant; + struct S(i32, u64); + struct Goal(core::mem::Discriminant); + } + size_and_align! { + minicore: discriminant; + #[repr(u32)] + enum S { + A, + B, + C, + } + struct Goal(core::mem::Discriminant); + } + size_and_align! { + minicore: discriminant; + enum S { + A(i32), + B(i64), + C(u8), + } + struct Goal(core::mem::Discriminant); + } + size_and_align! { + minicore: discriminant; + #[repr(C, u16)] + enum S { + A(i32), + B(i64) = 200, + C = 1000, + } + struct Goal(core::mem::Discriminant); + } +} diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index 774383d50d6..b621a8dda7e 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: 9288..9296, + range: 9289..9297, }, ), tooltip: "", @@ -487,7 +487,7 @@ fn main() { file_id: FileId( 1, ), - range: 9320..9324, + range: 9321..9325, }, ), tooltip: "", @@ -511,7 +511,7 @@ fn main() { file_id: FileId( 1, ), - range: 9288..9296, + range: 9289..9297, }, ), tooltip: "", @@ -524,7 +524,7 @@ fn main() { file_id: FileId( 1, ), - range: 9320..9324, + range: 9321..9325, }, ), tooltip: "", @@ -548,7 +548,7 @@ fn main() { file_id: FileId( 1, ), - range: 9288..9296, + range: 9289..9297, }, ), tooltip: "", @@ -561,7 +561,7 @@ fn main() { file_id: FileId( 1, ), - range: 9320..9324, + range: 9321..9325, }, ), tooltip: "", diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index ebde017686d..c765f42447a 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -364,6 +364,11 @@ pub mod mem { pub fn size_of() -> usize; } // endregion:size_of + + // region:discriminant + use crate::marker::DiscriminantKind; + pub struct Discriminant(::Discriminant); + // endregion:discriminant } pub mod ptr {