|
1 |
| -use hir::{Adt, Callable, HirDisplay, Semantics, Type}; |
| 1 | +use hir::{known, Adt, AssocItem, Callable, HirDisplay, ModuleDef, Semantics, Type}; |
2 | 2 | use ide_db::RootDatabase;
|
3 | 3 | use stdx::to_lower_snake_case;
|
4 | 4 | use syntax::{
|
@@ -193,14 +193,68 @@ fn get_bind_pat_hints(
|
193 | 193 | return None;
|
194 | 194 | }
|
195 | 195 |
|
196 |
| - acc.push(InlayHint { |
197 |
| - range: pat.syntax().text_range(), |
198 |
| - kind: InlayKind::TypeHint, |
199 |
| - label: ty.display_truncated(sema.db, config.max_length).to_string().into(), |
200 |
| - }); |
| 196 | + let db = sema.db; |
| 197 | + if let Some(hint) = hint_iterator(db, config, &ty, pat.clone()) { |
| 198 | + acc.push(hint); |
| 199 | + } else { |
| 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 | 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>`. |
| 211 | +fn 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 | + |
204 | 258 | fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Type) -> bool {
|
205 | 259 | if let Some(Adt::Enum(enum_data)) = pat_ty.as_adt() {
|
206 | 260 | let pat_text = bind_pat.to_string();
|
@@ -1057,6 +1111,71 @@ fn main() {
|
1057 | 1111 | let _v = Vec::<Box<dyn Display + Sync>>::new();
|
1058 | 1112 | //^^ Vec<Box<dyn Display + Sync>>
|
1059 | 1113 | }
|
| 1114 | +"#, |
| 1115 | + ); |
| 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 |
| 1129 | +use std::{Option::{self, Some, None}, iter}; |
| 1130 | +
|
| 1131 | +fn 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 |
| 1143 | +use core::*; |
| 1144 | +
|
| 1145 | +//- /core.rs crate:core |
| 1146 | +pub enum Option<T> { |
| 1147 | + Some(T), |
| 1148 | + None |
| 1149 | +} |
| 1150 | +
|
| 1151 | +pub 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 | +} |
1060 | 1179 | "#,
|
1061 | 1180 | );
|
1062 | 1181 | }
|
|
0 commit comments