Repository: rust-analyzer/rust-analyzer
Pull request #4849 (2020-06-11 14:23:49)

Make known paths use `core` instead of `std`
I'm not sure if this causes problems today, but it seems like it easily could, if rust-analyzer processes the libstd sources for the right `--target` and that target is a `#![no_std]`-only target.


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 308e36836f..2cb34fa207 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -247,13 +247,12 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-queue"
-version = "0.2.3"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
+checksum = "ab6bffe714b6bb07e42f201352c34f51fefd355ace793f9e638ebd52d23f98d2"
 dependencies = [
  "cfg-if",
  "crossbeam-utils",
- "maybe-uninit",
 ]
 
 [[package]]
@@ -566,9 +565,9 @@ dependencies = [
 
 [[package]]
 name = "jod-thread"
-version = "0.1.2"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae"
+checksum = "4022656272c3e564a7cdebcaaba6518d844b0d0c1836597196efb5bfeb98bb49"
 
 [[package]]
 name = "kernel32-sys"
@@ -1521,9 +1520,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.55"
+version = "1.0.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226"
+checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2"
 dependencies = [
  "itoa",
  "ryu",
@@ -1543,9 +1542,9 @@ dependencies = [
 
 [[package]]
 name = "serde_yaml"
-version = "0.8.13"
+version = "0.8.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
+checksum = "16c7a592a1ec97c9c1c68d75b6e537dcbf60c7618e038e7841e00af1d9ccf0c4"
 dependencies = [
  "dtoa",
  "linked-hash-map",
@@ -1586,9 +1585,9 @@ checksum = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
 
 [[package]]
 name = "syn"
-version = "1.0.31"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6"
+checksum = "93a56fabc59dce20fe48b6c832cc249c713e7ed88fa28b0ee0a3bfcaae5fe4e2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1597,9 +1596,9 @@ dependencies = [
 
 [[package]]
 name = "synstructure"
-version = "0.12.4"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
+checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 807195d25a..53599e74a2 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -99,7 +99,7 @@ impl FunctionData {
 }
 
 fn desugar_future_path(orig: TypeRef) -> Path {
-    let path = path![std::future::Future];
+    let path = path![core::future::Future];
     let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
     let mut last = GenericArgs::empty();
     last.bindings.push(AssociatedTypeBinding {
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index bfa921de22..ba16442bd5 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -323,16 +323,16 @@ pub use hir_expand::name as __name;
 
 #[macro_export]
 macro_rules! __known_path {
-    (std::iter::IntoIterator) => {};
-    (std::result::Result) => {};
-    (std::ops::Range) => {};
-    (std::ops::RangeFrom) => {};
-    (std::ops::RangeFull) => {};
-    (std::ops::RangeTo) => {};
-    (std::ops::RangeToInclusive) => {};
-    (std::ops::RangeInclusive) => {};
-    (std::future::Future) => {};
-    (std::ops::Try) => {};
+    (core::iter::IntoIterator) => {};
+    (core::result::Result) => {};
+    (core::ops::Range) => {};
+    (core::ops::RangeFrom) => {};
+    (core::ops::RangeFull) => {};
+    (core::ops::RangeTo) => {};
+    (core::ops::RangeToInclusive) => {};
+    (core::ops::RangeInclusive) => {};
+    (core::future::Future) => {};
+    (core::ops::Try) => {};
     ($path:path) => {
         compile_error!("Please register your known path in the path module")
     };
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index f04968e145..7db928dded 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -226,17 +226,19 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
             None => return,
         };
 
-        let std_result_path = path![std::result::Result];
+        let core_result_path = path![core::result::Result];
 
         let resolver = self.func.resolver(db.upcast());
-        let std_result_enum = match resolver.resolve_known_enum(db.upcast(), &std_result_path) {
+        let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) {
             Some(it) => it,
             _ => return,
         };
 
-        let std_result_ctor = TypeCtor::Adt(AdtId::EnumId(std_result_enum));
+        let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum));
         let params = match &mismatch.expected {
-            Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters,
+            Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => {
+                parameters
+            }
             _ => return,
         };
 
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index f965eb2b5c..3719f76a6e 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -555,13 +555,13 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
-        let path = path![std::iter::IntoIterator];
+        let path = path![core::iter::IntoIterator];
         let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Item])
     }
 
     fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
-        let path = path![std::ops::Try];
+        let path = path![core::ops::Try];
         let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Ok])
     }
@@ -587,37 +587,37 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_range_full(&self) -> Option<AdtId> {
-        let path = path![std::ops::RangeFull];
+        let path = path![core::ops::RangeFull];
         let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
         Some(struct_.into())
     }
 
     fn resolve_range(&self) -> Option<AdtId> {
-        let path = path![std::ops::Range];
+        let path = path![core::ops::Range];
         let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
         Some(struct_.into())
     }
 
     fn resolve_range_inclusive(&self) -> Option<AdtId> {
-        let path = path![std::ops::RangeInclusive];
+        let path = path![core::ops::RangeInclusive];
         let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
         Some(struct_.into())
     }
 
     fn resolve_range_from(&self) -> Option<AdtId> {
-        let path = path![std::ops::RangeFrom];
+        let path = path![core::ops::RangeFrom];
         let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
         Some(struct_.into())
     }
 
     fn resolve_range_to(&self) -> Option<AdtId> {
-        let path = path![std::ops::RangeTo];
+        let path = path![core::ops::RangeTo];
         let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
         Some(struct_.into())
     }
 
     fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
-        let path = path![std::ops::RangeToInclusive];
+        let path = path![core::ops::RangeToInclusive];
         let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
         Some(struct_.into())
     }
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index bf14a467f8..f44feaf697 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -321,29 +321,26 @@ mod tests {
     fn test_wrap_return_type() {
         let before = r#"
             //- /main.rs
-            use std::{string::String, result::Result::{self, Ok, Err}};
+            use core::result::Result::{self, Ok, Err};
 
-            fn div(x: i32, y: i32) -> Result<i32, String> {
+            fn div(x: i32, y: i32) -> Result<i32, ()> {
                 if y == 0 {
-                    return Err("div by zero".into());
+                    return Err(());
                 }
                 x / y<|>
             }
 
-            //- /std/lib.rs
-            pub mod string {
-                pub struct String { }
-            }
+            //- /core/lib.rs
             pub mod result {
                 pub enum Result<T, E> { Ok(T), Err(E) }
             }
         "#;
         let after = r#"
-            use std::{string::String, result::Result::{self, Ok, Err}};
+            use core::result::Result::{self, Ok, Err};
 
-            fn div(x: i32, y: i32) -> Result<i32, String> {
+            fn div(x: i32, y: i32) -> Result<i32, ()> {
                 if y == 0 {
-                    return Err("div by zero".into());
+                    return Err(());
                 }
                 Ok(x / y)
             }
@@ -355,7 +352,7 @@ mod tests {
     fn test_wrap_return_type_handles_generic_functions() {
         let before = r#"
             //- /main.rs
-            use std::result::Result::{self, Ok, Err};
+            use core::result::Result::{self, Ok, Err};
 
             fn div<T>(x: T) -> Result<T, i32> {
                 if x == 0 {
@@ -364,13 +361,13 @@ mod tests {
                 <|>x
             }
 
-            //- /std/lib.rs
+            //- /core/lib.rs
             pub mod result {
                 pub enum Result<T, E> { Ok(T), Err(E) }
             }
         "#;
         let after = r#"
-            use std::result::Result::{self, Ok, Err};
+            use core::result::Result::{self, Ok, Err};
 
             fn div<T>(x: T) -> Result<T, i32> {
                 if x == 0 {
@@ -386,32 +383,29 @@ mod tests {
     fn test_wrap_return_type_handles_type_aliases() {
         let before = r#"
             //- /main.rs
-            use std::{string::String, result::Result::{self, Ok, Err}};
+            use core::result::Result::{self, Ok, Err};
 
-            type MyResult<T> = Result<T, String>;
+            type MyResult<T> = Result<T, ()>;
 
             fn div(x: i32, y: i32) -> MyResult<i32> {
                 if y == 0 {
-                    return Err("div by zero".into());
+                    return Err(());
                 }
                 x <|>/ y
             }
 
-            //- /std/lib.rs
-            pub mod string {
-                pub struct String { }
-            }
+            //- /core/lib.rs
             pub mod result {
                 pub enum Result<T, E> { Ok(T), Err(E) }
             }
         "#;
         let after = r#"
-            use std::{string::String, result::Result::{self, Ok, Err}};
+            use core::result::Result::{self, Ok, Err};
 
-            type MyResult<T> = Result<T, String>;
+            type MyResult<T> = Result<T, ()>;
             fn div(x: i32, y: i32) -> MyResult<i32> {
                 if y == 0 {
-                    return Err("div by zero".into());
+                    return Err(());
                 }
                 Ok(x / y)
             }
@@ -423,16 +417,13 @@ mod tests {
     fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
         let content = r#"
             //- /main.rs
-            use std::{string::String, result::Result::{self, Ok, Err}};
+            use core::result::Result::{self, Ok, Err};
 
-            fn foo() -> Result<String, i32> {
+            fn foo() -> Result<(), i32> {
                 0<|>
             }
 
-            //- /std/lib.rs
-            pub mod string {
-                pub struct String { }
-            }
+            //- /core/lib.rs
             pub mod result {
                 pub enum Result<T, E> { Ok(T), Err(E) }
             }
@@ -444,7 +435,7 @@ mod tests {
     fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() {
         let content = r#"
             //- /main.rs
-            use std::{string::String, result::Result::{self, Ok, Err}};
+            use core::result::Result::{self, Ok, Err};
 
             enum SomeOtherEnum {
                 Ok(i32),
@@ -455,10 +446,7 @@ mod tests {
                 0<|>
             }
 
-            //- /std/lib.rs
-            pub mod string {
-                pub struct String { }
-            }
+            //- /core/lib.rs
             pub mod result {
                 pub enum Result<T, E> { Ok(T), Err(E) }
             }
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index 2fc796a859..5dbe1c1b7e 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -16,7 +16,7 @@ use rustc_hash::FxHashMap;
 
 use crate::{
     symbol_index::{SymbolIndex, SymbolsDatabase},
-    RootDatabase,
+    DebugData, RootDatabase,
 };
 
 #[derive(Default)]
@@ -26,6 +26,7 @@ pub struct AnalysisChange {
     files_changed: Vec<(FileId, Arc<String>)>,
     libraries_added: Vec<LibraryData>,
     crate_graph: Option<CrateGraph>,
+    debug_data: DebugData,
 }
 
 impl fmt::Debug for AnalysisChange {
@@ -86,6 +87,10 @@ impl AnalysisChange {
     pub fn set_crate_graph(&mut self, graph: CrateGraph) {
         self.crate_graph = Some(graph);
     }
+
+    pub fn set_debug_root_path(&mut self, source_root_id: SourceRootId, path: String) {
+        self.debug_data.root_paths.insert(source_root_id, path);
+    }
 }
 
 #[derive(Debug)]
@@ -213,6 +218,8 @@ impl RootDatabase {
         if let Some(crate_graph) = change.crate_graph {
             self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
         }
+
+        Arc::make_mut(&mut self.debug_data).merge(change.debug_data)
     }
 
     fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index a808de4f11..480fd45764 100644
--- a/crates/ra_ide_db/src/lib.rs
+++ b/crates/ra_ide_db/src/lib.rs
@@ -17,9 +17,9 @@ use hir::db::{AstDatabase, DefDatabase};
 use ra_db::{
     salsa::{self, Database, Durability},
     Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
-    Upcast,
+    SourceRootId, Upcast,
 };
-use rustc_hash::FxHashSet;
+use rustc_hash::{FxHashMap, FxHashSet};
 
 use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
 
@@ -36,6 +36,7 @@ use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
 #[derive(Debug)]
 pub struct RootDatabase {
     runtime: salsa::Runtime<RootDatabase>,
+    pub(crate) debug_data: Arc<DebugData>,
     pub last_gc: crate::wasm_shims::Instant,
     pub last_gc_check: crate::wasm_shims::Instant,
 }
@@ -97,6 +98,7 @@ impl RootDatabase {
             runtime: salsa::Runtime::default(),
             last_gc: crate::wasm_shims::Instant::now(),
             last_gc_check: crate::wasm_shims::Instant::now(),
+            debug_data: Default::default(),
         };
         db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
         db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
@@ -119,6 +121,7 @@ impl salsa::ParallelDatabase for RootDatabase {
             runtime: self.runtime.snapshot(self),
             last_gc: self.last_gc,
             last_gc_check: self.last_gc_check,
+            debug_data: Arc::clone(&self.debug_data),
         })
     }
 }
@@ -132,3 +135,14 @@ fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
     let text = db.file_text(file_id);
     Arc::new(LineIndex::new(&*text))
 }
+
+#[derive(Debug, Default, Clone)]
+pub(crate) struct DebugData {
+    pub(crate) root_paths: FxHashMap<SourceRootId, String>,
+}
+
+impl DebugData {
+    pub(crate) fn merge(&mut self, other: DebugData) {
+        self.root_paths.extend(other.root_paths.into_iter());
+    }
+}
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index 97367d7c60..45af963179 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -111,6 +111,10 @@ pub(crate) fn load(
                         vfs.root2path(root)
                     );
                     analysis_change.add_root(source_root_id, is_local);
+                    analysis_change.set_debug_root_path(
+                        source_root_id,
+                        source_roots[&source_root_id].path().display().to_string(),
+                    );
 
                     let vfs_root_path = vfs.root2path(root);
                     if extern_dirs.contains(&vfs_root_path) {
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 21116e165e..96d91b12d9 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -126,6 +126,7 @@ impl GlobalState {
             let vfs_root_path = vfs.root2path(r);
             let is_local = local_roots.iter().any(|it| vfs_root_path.starts_with(it));
             change.add_root(SourceRootId(r.0), is_local);
+            change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string());
 
             // FIXME: add path2root in vfs to simpily this logic
             if extern_dirs.contains(&vfs_root_path) {


Test patch:
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 8a5031756f..37659cd02c 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -95,7 +95,7 @@ fn foo() {
 fn infer_ranges() {
     let (db, pos) = TestDB::with_position(
         r#"
-//- /main.rs crate:main deps:std
+//- /main.rs crate:main deps:core
 fn test() {
     let a = ..;
     let b = 1..;
@@ -108,7 +108,7 @@ fn test() {
     t<|>;
 }
 
-//- /std.rs crate:std
+//- /core.rs crate:core
 #[prelude_import] use prelude::*;
 mod prelude {}
 
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 133fb5f398..e81193a3c3 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -10,7 +10,7 @@ use super::{infer, infer_with_mismatches, type_at, type_at_pos};
 fn infer_await() {
     let (db, pos) = TestDB::with_position(
         r#"
-//- /main.rs crate:main deps:std
+//- /main.rs crate:main deps:core
 
 struct IntFuture;
 
@@ -24,7 +24,7 @@ fn test() {
     v<|>;
 }
 
-//- /std.rs crate:std
+//- /core.rs crate:core
 #[prelude_import] use future::*;
 mod future {
     #[lang = "future_trait"]
@@ -42,7 +42,7 @@ mod future {
 fn infer_async() {
     let (db, pos) = TestDB::with_position(
         r#"
-//- /main.rs crate:main deps:std
+//- /main.rs crate:main deps:core
 
 async fn foo() -> u64 {
     128
@@ -54,7 +54,7 @@ fn test() {
     v<|>;
 }
 
-//- /std.rs crate:std
+//- /core.rs crate:core
 #[prelude_import] use future::*;
 mod future {
     #[lang = "future_trait"]
@@ -72,7 +72,7 @@ mod future {
 fn infer_desugar_async() {
     let (db, pos) = TestDB::with_position(
         r#"
-//- /main.rs crate:main deps:std
+//- /main.rs crate:main deps:core
 
 async fn foo() -> u64 {
     128
@@ -83,7 +83,7 @@ fn test() {
     r<|>;
 }
 
-//- /std.rs crate:std
+//- /core.rs crate:core
 #[prelude_import] use future::*;
 mod future {
     trait Future {
@@ -100,7 +100,7 @@ mod future {
 fn infer_try() {
     let (db, pos) = TestDB::with_position(
         r#"
-//- /main.rs crate:main deps:std
+//- /main.rs crate:main deps:core
 
 fn test() {
     let r: Result<i32, u64> = Result::Ok(1);
@@ -108,7 +108,7 @@ fn test() {
     v<|>;
 }
 
-//- /std.rs crate:std
+//- /core.rs crate:core
 
 #[prelude_import] use ops::*;
 mod ops {
@@ -140,9 +140,9 @@ mod result {
 fn infer_for_loop() {
     let (db, pos) = TestDB::with_position(
         r#"
-//- /main.rs crate:main deps:std
+//- /main.rs crate:main deps:core,alloc
 
-use std::collections::Vec;
+use alloc::collections::Vec;
 
 fn test() {
     let v = Vec::new();
@@ -152,7 +152,7 @@ fn test() {
     }
 }
 
-//- /std.rs crate:std
+//- /core.rs crate:core
 
 #[prelude_import] use iter::*;
 mod iter {
@@ -161,6 +161,8 @@ mod iter {
     }
 }
 
+//- /alloc.rs crate:alloc deps:core
+
 mod collections {
     struct Vec<T> {}
     impl<T> Vec<T> {
@@ -168,7 +170,7 @@ mod collections {
         fn push(&mut self, t: T) { }
     }
 
-    impl<T> crate::iter::IntoIterator for Vec<T> {
+    impl<T> IntoIterator for Vec<T> {
         type Item=T;
     }
 }
@@ -2846,12 +2848,12 @@ fn test() {
 fn integer_range_iterate() {
     let t = type_at(
         r#"
-//- /main.rs crate:main deps:std
+//- /main.rs crate:main deps:core
 fn test() {
     for x in 0..100 { x<|>; }
 }
 
-//- /std.rs crate:std
+//- /core.rs crate:core
 pub mod ops {
     pub struct Range<Idx> {
         pub start: Idx,