aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/assists/src/utils.rs61
-rw-r--r--crates/ide/src/inlay_hints.rs93
2 files changed, 85 insertions, 69 deletions
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index eb69c49a4..0335969fd 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -274,24 +274,54 @@ impl TryEnum {
274/// somewhat similar to the known paths infra inside hir, but it different; We 274/// somewhat similar to the known paths infra inside hir, but it different; We
275/// want to make sure that IDE specific paths don't become interesting inside 275/// want to make sure that IDE specific paths don't become interesting inside
276/// the compiler itself as well. 276/// the compiler itself as well.
277pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>, pub(crate) Crate); 277pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate);
278 278
279#[allow(non_snake_case)] 279#[allow(non_snake_case)]
280impl FamousDefs<'_, '_> { 280impl FamousDefs<'_, '_> {
281 #[cfg(test)] 281 pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
282 pub(crate) const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
283pub mod convert { 282pub mod convert {
284 pub trait From<T> { 283 pub trait From<T> {
285 fn from(T) -> Self; 284 fn from(T) -> Self;
286 } 285 }
287} 286}
288 287
288pub mod iter {
289 pub use self::traits::iterator::Iterator;
290 mod traits { mod iterator {
291 use crate::option::Option;
292 pub trait Iterator {
293 type Item;
294 fn next(&mut self) -> Option<Self::Item>;
295 }
296 } }
297
298 pub use self::sources::*;
299 mod sources {
300 use super::Iterator;
301 pub struct Repeat<A> {
302 element: A,
303 }
304
305 pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
306 Repeat { element: elt }
307 }
308
309 impl<A: Clone> Iterator for Repeat<A> {
310 type Item = A;
311
312 fn next(&mut self) -> Option<A> {
313 Some(self.element.clone())
314 }
315 }
316 }
317}
318
289pub mod option { 319pub mod option {
290 pub enum Option<T> { None, Some(T)} 320 pub enum Option<T> { None, Some(T)}
291} 321}
292 322
293pub mod prelude { 323pub mod prelude {
294 pub use crate::{convert::From, option::Option::{self, *}}; 324 pub use crate::{convert::From, iter::Iterator, option::Option::{self, *}};
295} 325}
296#[prelude_import] 326#[prelude_import]
297pub use prelude::*; 327pub use prelude::*;
@@ -305,6 +335,10 @@ pub use prelude::*;
305 self.find_enum("core:option:Option") 335 self.find_enum("core:option:Option")
306 } 336 }
307 337
338 pub fn core_iter_Iterator(&self) -> Option<Trait> {
339 self.find_trait("core:iter:traits:iterator:Iterator")
340 }
341
308 fn find_trait(&self, path: &str) -> Option<Trait> { 342 fn find_trait(&self, path: &str) -> Option<Trait> {
309 match self.find_def(path)? { 343 match self.find_def(path)? {
310 hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), 344 hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
@@ -324,18 +358,21 @@ pub use prelude::*;
324 let mut path = path.split(':'); 358 let mut path = path.split(':');
325 let trait_ = path.next_back()?; 359 let trait_ = path.next_back()?;
326 let std_crate = path.next()?; 360 let std_crate = path.next()?;
327 let std_crate = self 361 let std_crate = if self
328 .1 362 .1
329 .dependencies(db) 363 .declaration_name(db)
330 .into_iter() 364 .map(|name| name.to_string() == std_crate)
331 .find(|dep| &dep.name.to_string() == std_crate)? 365 .unwrap_or(false)
332 .krate; 366 {
333 367 self.1
368 } else {
369 self.1.dependencies(db).into_iter().find(|dep| dep.name.to_string() == std_crate)?.krate
370 };
334 let mut module = std_crate.root_module(db); 371 let mut module = std_crate.root_module(db);
335 for segment in path { 372 for segment in path {
336 module = module.children(db).find_map(|child| { 373 module = module.children(db).find_map(|child| {
337 let name = child.name(db)?; 374 let name = child.name(db)?;
338 if &name.to_string() == segment { 375 if name.to_string() == segment {
339 Some(child) 376 Some(child)
340 } else { 377 } else {
341 None 378 None
@@ -343,7 +380,7 @@ pub use prelude::*;
343 })?; 380 })?;
344 } 381 }
345 let def = 382 let def =
346 module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; 383 module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
347 Some(def) 384 Some(def)
348 } 385 }
349} 386}
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index d8e67bbd9..27bd1e37f 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1,4 +1,5 @@
1use hir::{known, Adt, AssocItem, Callable, HirDisplay, ModuleDef, Semantics, Type}; 1use assists::utils::FamousDefs;
2use hir::{known, Adt, AssocItem, Callable, HirDisplay, Semantics, Type};
2use ide_db::RootDatabase; 3use ide_db::RootDatabase;
3use stdx::to_lower_snake_case; 4use stdx::to_lower_snake_case;
4use syntax::{ 5use syntax::{
@@ -194,7 +195,7 @@ fn get_bind_pat_hints(
194 } 195 }
195 196
196 let db = sema.db; 197 let db = sema.db;
197 if let Some(hint) = hint_iterator(db, config, &ty, pat.clone()) { 198 if let Some(hint) = hint_iterator(sema, config, &ty, pat.clone()) {
198 acc.push(hint); 199 acc.push(hint);
199 } else { 200 } else {
200 acc.push(InlayHint { 201 acc.push(InlayHint {
@@ -209,45 +210,44 @@ fn get_bind_pat_hints(
209 210
210/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`. 211/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
211fn hint_iterator( 212fn hint_iterator(
212 db: &RootDatabase, 213 sema: &Semantics<RootDatabase>,
213 config: &InlayHintsConfig, 214 config: &InlayHintsConfig,
214 ty: &Type, 215 ty: &Type,
215 pat: ast::IdentPat, 216 pat: ast::IdentPat,
216) -> Option<InlayHint> { 217) -> Option<InlayHint> {
218 let db = sema.db;
217 let strukt = ty.as_adt()?; 219 let strukt = ty.as_adt()?;
218 let krate = strukt.krate(db)?; 220 let krate = strukt.krate(db)?;
219 let module = strukt.module(db);
220 if krate.declaration_name(db).as_deref() != Some("core") { 221 if krate.declaration_name(db).as_deref() != Some("core") {
221 return None; 222 return None;
222 } 223 }
223 let module = module 224 // assert this type comes from `core::iter`
225 strukt
226 .module(db)
224 .path_to_root(db) 227 .path_to_root(db)
225 .into_iter() 228 .into_iter()
226 .rev() 229 .rev()
227 .find(|module| module.name(db) == Some(known::iter))?; 230 .find(|module| module.name(db) == Some(known::iter))?;
228 let iter_trait = module.scope(db, None).into_iter().find_map(|(name, def)| match def { 231 let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
229 hir::ScopeDef::ModuleDef(ModuleDef::Trait(r#trait)) if name == known::Iterator => {
230 Some(r#trait)
231 }
232 _ => None,
233 })?;
234 if ty.impls_trait(db, iter_trait, &[]) { 232 if ty.impls_trait(db, iter_trait, &[]) {
235 let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item { 233 let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
236 AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), 234 AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
237 _ => None, 235 _ => None,
238 })?; 236 })?;
239 if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) { 237 if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) {
238 const LABEL_START: &str = "impl Iterator<Item = ";
239 const LABEL_END: &str = ">";
240
241 let ty_display = ty.display_truncated(
242 db,
243 config
244 .max_length
245 .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())),
246 );
240 return Some(InlayHint { 247 return Some(InlayHint {
241 range: pat.syntax().text_range(), 248 range: pat.syntax().text_range(),
242 kind: InlayKind::TypeHint, 249 kind: InlayKind::TypeHint,
243 label: format!( 250 label: format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into(),
244 "impl Iterator<Item = {}>",
245 ty.display_truncated(
246 db,
247 config.max_length.map(|len| len - 22 /*len of the template string above*/)
248 )
249 )
250 .into(),
251 }); 251 });
252 } 252 }
253 } 253 }
@@ -401,6 +401,7 @@ fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Call
401 401
402#[cfg(test)] 402#[cfg(test)]
403mod tests { 403mod tests {
404 use assists::utils::FamousDefs;
404 use expect_test::{expect, Expect}; 405 use expect_test::{expect, Expect};
405 use test_utils::extract_annotations; 406 use test_utils::extract_annotations;
406 407
@@ -1124,15 +1125,26 @@ fn main() {
1124 chaining_hints: true, 1125 chaining_hints: true,
1125 max_length: None, 1126 max_length: None,
1126 }, 1127 },
1127 r#" 1128 &format!(
1129 "{}\n{}\n",
1130 r#"
1128//- /main.rs crate:main deps:std 1131//- /main.rs crate:main deps:std
1129use std::{Option::{self, Some, None}, iter}; 1132use std::{Option::{self, Some, None}, iter};
1130 1133
1134struct MyIter;
1135
1136impl iter::Iterator for MyIter {
1137 type Item = ();
1138 fn next(&mut self) -> Option<Self::Item> {
1139 None
1140 }
1141}
1142
1131fn main() { 1143fn main() {
1144 let _x = MyIter;
1145 //^^ MyIter
1132 let _x = iter::repeat(0); 1146 let _x = iter::repeat(0);
1133 //^^ impl Iterator<Item = i32> 1147 //^^ impl Iterator<Item = i32>
1134 let _y = iter::Chain(iter::repeat(0), iter::repeat(0));
1135 //^^ impl Iterator<Item = i32>
1136 fn generic<T: Clone>(t: T) { 1148 fn generic<T: Clone>(t: T) {
1137 let _x = iter::repeat(t); 1149 let _x = iter::repeat(t);
1138 //^^ impl Iterator<Item = T> 1150 //^^ impl Iterator<Item = T>
@@ -1141,42 +1153,9 @@ fn main() {
1141 1153
1142//- /std.rs crate:std deps:core 1154//- /std.rs crate:std deps:core
1143use core::*; 1155use core::*;
1144
1145//- /core.rs crate:core
1146pub enum Option<T> {
1147 Some(T),
1148 None
1149}
1150
1151pub mod iter {
1152 pub use self::traits::iterator::Iterator;
1153 pub mod traits { pub mod iterator {
1154 pub trait Iterator {
1155 type Item;
1156 }
1157 } }
1158
1159 pub use self::sources::*;
1160 pub mod sources {
1161 use super::Iterator;
1162 pub struct Repeat<T: Clone>(pub T);
1163
1164 pub fn repeat<T: Clone>(t: T) -> Repeat<T> {
1165 Repeat(f)
1166 }
1167
1168 impl<T: Clone> Iterator for Repeat<T> {
1169 type Item = T;
1170 }
1171
1172 pub struct Chain<A, B>(pub A, pub B);
1173
1174 impl<T, A, B> Iterator for Chain<A, B> where A: Iterator<Item = T>, B: Iterator<Item = T> {
1175 type Item = T;
1176 }
1177 }
1178}
1179"#, 1156"#,
1157 FamousDefs::FIXTURE
1158 ),
1180 ); 1159 );
1181 } 1160 }
1182} 1161}