aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/inlay_hints.rs131
1 files changed, 125 insertions, 6 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 3a4dc6a84..d8e67bbd9 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1,4 +1,4 @@
1use hir::{Adt, Callable, HirDisplay, Semantics, Type}; 1use hir::{known, Adt, AssocItem, Callable, HirDisplay, ModuleDef, Semantics, Type};
2use ide_db::RootDatabase; 2use ide_db::RootDatabase;
3use stdx::to_lower_snake_case; 3use stdx::to_lower_snake_case;
4use syntax::{ 4use syntax::{
@@ -193,14 +193,68 @@ fn get_bind_pat_hints(
193 return None; 193 return None;
194 } 194 }
195 195
196 acc.push(InlayHint { 196 let db = sema.db;
197 range: pat.syntax().text_range(), 197 if let Some(hint) = hint_iterator(db, config, &ty, pat.clone()) {
198 kind: InlayKind::TypeHint, 198 acc.push(hint);
199 label: ty.display_truncated(sema.db, config.max_length).to_string().into(), 199 } else {
200 }); 200 acc.push(InlayHint {
201 range: pat.syntax().text_range(),
202 kind: InlayKind::TypeHint,
203 label: ty.display_truncated(db, config.max_length).to_string().into(),
204 });
205 }
206
201 Some(()) 207 Some(())
202} 208}
203 209
210/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
211fn hint_iterator(
212 db: &RootDatabase,
213 config: &InlayHintsConfig,
214 ty: &Type,
215 pat: ast::IdentPat,
216) -> Option<InlayHint> {
217 let strukt = ty.as_adt()?;
218 let krate = strukt.krate(db)?;
219 let module = strukt.module(db);
220 if krate.declaration_name(db).as_deref() != Some("core") {
221 return None;
222 }
223 let module = module
224 .path_to_root(db)
225 .into_iter()
226 .rev()
227 .find(|module| module.name(db) == Some(known::iter))?;
228 let iter_trait = module.scope(db, None).into_iter().find_map(|(name, def)| match def {
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, &[]) {
235 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),
237 _ => None,
238 })?;
239 if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) {
240 return Some(InlayHint {
241 range: pat.syntax().text_range(),
242 kind: InlayKind::TypeHint,
243 label: format!(
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 });
252 }
253 }
254
255 None
256}
257
204fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Type) -> bool { 258fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Type) -> bool {
205 if let Some(Adt::Enum(enum_data)) = pat_ty.as_adt() { 259 if let Some(Adt::Enum(enum_data)) = pat_ty.as_adt() {
206 let pat_text = bind_pat.to_string(); 260 let pat_text = bind_pat.to_string();
@@ -1060,4 +1114,69 @@ fn main() {
1060"#, 1114"#,
1061 ); 1115 );
1062 } 1116 }
1117
1118 #[test]
1119 fn shorten_iterator_hints() {
1120 check_with_config(
1121 InlayHintsConfig {
1122 parameter_hints: false,
1123 type_hints: true,
1124 chaining_hints: true,
1125 max_length: None,
1126 },
1127 r#"
1128//- /main.rs crate:main deps:std
1129use std::{Option::{self, Some, None}, iter};
1130
1131fn main() {
1132 let _x = iter::repeat(0);
1133 //^^ 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) {
1137 let _x = iter::repeat(t);
1138 //^^ impl Iterator<Item = T>
1139 }
1140}
1141
1142//- /std.rs crate:std deps:core
1143use 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"#,
1180 );
1181 }
1063} 1182}