about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-07-14 16:46:35 +0000
committerbors <bors@rust-lang.org>2023-07-14 16:46:35 +0000
commit8e5f944317cfefc8fb17b57ff7b7ccc7326f4642 (patch)
tree3112e73995582c308d1961be93c877f2f71fb5f5
parentc7ce8add143571eed89215dccbbe28c45b0d551d (diff)
parent50559118fbb5d94c5617835bd8c5d294393acaf5 (diff)
downloadrust-8e5f944317cfefc8fb17b57ff7b7ccc7326f4642.tar.gz
rust-8e5f944317cfefc8fb17b57ff7b7ccc7326f4642.zip
Auto merge of #15282 - HKalbasi:mir, r=HKalbasi
Give real discriminant_type to chalk
-rw-r--r--crates/base-db/src/fixture.rs2
-rw-r--r--crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs38
-rw-r--r--crates/hir-expand/src/builtin_derive_macro.rs32
-rw-r--r--crates/hir-ty/src/chalk_db.rs34
-rw-r--r--crates/hir-ty/src/consteval/tests.rs64
-rw-r--r--crates/hir-ty/src/consteval/tests/intrinsics.rs30
-rw-r--r--crates/hir-ty/src/layout/tests.rs38
-rw-r--r--crates/hir-ty/src/mir/eval.rs66
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs20
-rw-r--r--crates/hir-ty/src/mir/monomorphization.rs26
-rw-r--r--crates/ide/src/inlay_hints/chaining.rs12
-rw-r--r--crates/ide/src/interpret_function.rs6
-rw-r--r--crates/test-utils/src/minicore.rs5
13 files changed, 293 insertions, 80 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-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
@@ -417,6 +417,44 @@ fn test_hash_expand() {
 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<H: core::hash::Hasher>(&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 },
     Do(&'static str),
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<H: #krate::hash::Hasher>(&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<Interner> 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<Interner>) -> chalk_ir::Ty<Interner> {
-        // 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<Interner>) -> chalk_ir::Ty<Interner> {
+        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<ImplDatum> {
         self.db.impl_datum(self.krate, impl_id)
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index e32ae8b2680..5bb327606d3 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -5,7 +5,7 @@ use test_utils::skip_slow_tests;
 
 use crate::{
     consteval::try_const_usize, db::HirDatabase, mir::pad16, test_db::TestDB, Const, ConstScalar,
-    Interner,
+    Interner, MemoryMap,
 };
 
 use super::{
@@ -37,7 +37,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()],
@@ -48,8 +48,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) => {
@@ -59,8 +77,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),
         },
@@ -225,7 +243,7 @@ const GOAL: usize = {
     transmute(&x)
 }
         "#,
-        |b| assert_eq!(b[0] % 8, 0),
+        |b, _| assert_eq!(b[0] % 8, 0),
     );
     check_answer(
         r#"
@@ -234,7 +252,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),
     );
 }
 
@@ -2069,6 +2087,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(
         r#"
@@ -2446,6 +2475,25 @@ fn const_trait_assoc() {
     );
     check_number(
         r#"
+    //- /a/lib.rs crate:a
+    pub trait ToConst {
+        const VAL: usize;
+    }
+    pub const fn to_const<T: ToConst>() -> 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::<U0>();
+    "#,
+        5,
+    );
+    check_number(
+        r#"
     struct S<T>(*mut T);
 
     trait MySized: Sized {
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
@@ -150,6 +150,36 @@ fn min_align_of_val() {
 }
 
 #[test]
+fn type_name() {
+    check_str(
+        r#"
+        extern "rust-intrinsic" {
+            pub fn type_name<T: ?Sized>() -> &'static str;
+        }
+
+        const GOAL: &str = type_name::<i32>();
+        "#,
+        "i32",
+    );
+    check_str(
+        r#"
+        extern "rust-intrinsic" {
+            pub fn type_name<T: ?Sized>() -> &'static str;
+        }
+
+        mod mod1 {
+            pub mod mod2 {
+                pub struct Ty;
+            }
+        }
+
+        const GOAL: &str = type_name::<mod1::mod2::Ty>();
+        "#,
+        "mod1::mod2::Ty",
+    );
+}
+
+#[test]
 fn transmute() {
     check_number(
         r#"
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<S>);
+    }
+    size_and_align! {
+        minicore: discriminant;
+        #[repr(u32)]
+        enum S {
+            A,
+            B,
+            C,
+        }
+        struct Goal(core::mem::Discriminant<S>);
+    }
+    size_and_align! {
+        minicore: discriminant;
+        enum S {
+            A(i32),
+            B(i64),
+            C(u8),
+        }
+        struct Goal(core::mem::Discriminant<S>);
+    }
+    size_and_align! {
+        minicore: discriminant;
+        #[repr(C, u16)]
+        enum S {
+            A(i32),
+            B(i64) = 200,
+            C = 1000,
+        }
+        struct Goal(core::mem::Discriminant<S>);
+    }
+}
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<Interval> {
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/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/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<Strin
         _ => 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("<unknown file>");
-        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))
 }
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<T>() -> usize;
     }
     // endregion:size_of
+
+    // region:discriminant
+    use crate::marker::DiscriminantKind;
+    pub struct Discriminant<T>(<T as DiscriminantKind>::Discriminant);
+    // endregion:discriminant
 }
 
 pub mod ptr {