aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2020-10-06 18:07:34 +0100
committerLukas Wirth <[email protected]>2020-10-06 18:20:42 +0100
commitaaa3905fdd18a7981d40ac371099ae9044e833a8 (patch)
treedbacb3b28efc4404f664edd802b1467b2bf57e37
parentec1f4599809b6e1b10418fa78e1d7bfc3c817319 (diff)
Shorten type hints for std::iter Iterators
-rw-r--r--crates/hir/src/code_model.rs37
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/hir_expand/src/name.rs1
-rw-r--r--crates/ide/src/inlay_hints.rs131
4 files changed, 162 insertions, 9 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index c75d46bff..031c91ccf 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -30,8 +30,12 @@ use hir_expand::{
30use hir_ty::{ 30use hir_ty::{
31 autoderef, 31 autoderef,
32 display::{HirDisplayError, HirFormatter}, 32 display::{HirDisplayError, HirFormatter},
33 method_resolution, ApplicationTy, CallableDefId, Canonical, FnSig, GenericPredicate, 33 method_resolution,
34 InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, 34 traits::Solution,
35 traits::SolutionVariables,
36 ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate,
37 InEnvironment, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, Ty,
38 TyDefId, TyKind, TypeCtor,
35}; 39};
36use rustc_hash::FxHashSet; 40use rustc_hash::FxHashSet;
37use stdx::impl_from; 41use stdx::impl_from;
@@ -1362,6 +1366,35 @@ impl Type {
1362 db.trait_solve(self.krate, goal).is_some() 1366 db.trait_solve(self.krate, goal).is_some()
1363 } 1367 }
1364 1368
1369 pub fn normalize_trait_assoc_type(
1370 &self,
1371 db: &dyn HirDatabase,
1372 r#trait: Trait,
1373 args: &[Type],
1374 alias: TypeAlias,
1375 ) -> Option<Ty> {
1376 let subst = Substs::build_for_def(db, r#trait.id)
1377 .push(self.ty.value.clone())
1378 .fill(args.iter().map(|t| t.ty.value.clone()))
1379 .build();
1380 let predicate = ProjectionPredicate {
1381 projection_ty: ProjectionTy { associated_ty: alias.id, parameters: subst },
1382 ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)),
1383 };
1384 let goal = Canonical {
1385 value: InEnvironment::new(
1386 self.ty.environment.clone(),
1387 Obligation::Projection(predicate),
1388 ),
1389 kinds: Arc::new([TyKind::General]),
1390 };
1391
1392 match db.trait_solve(self.krate, goal)? {
1393 Solution::Unique(SolutionVariables(subst)) => subst.value.first().cloned(),
1394 Solution::Ambig(_) => None,
1395 }
1396 }
1397
1365 pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { 1398 pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
1366 let lang_item = db.lang_item(self.krate, SmolStr::new("copy")); 1399 let lang_item = db.lang_item(self.krate, SmolStr::new("copy"));
1367 let copy_trait = match lang_item { 1400 let copy_trait = match lang_item {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 171118d98..4094a76cb 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -55,7 +55,7 @@ pub use hir_def::{
55 type_ref::{Mutability, TypeRef}, 55 type_ref::{Mutability, TypeRef},
56}; 56};
57pub use hir_expand::{ 57pub use hir_expand::{
58 name::AsName, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, 58 name::known, name::AsName, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc,
59 /* FIXME */ MacroDefId, MacroFile, Origin, 59 /* FIXME */ MacroDefId, MacroFile, Origin,
60}; 60};
61pub use hir_ty::display::HirDisplay; 61pub use hir_ty::display::HirDisplay;
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index a5750d829..63f828707 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -164,6 +164,7 @@ pub mod known {
164 result, 164 result,
165 boxed, 165 boxed,
166 // Components of known path (type name) 166 // Components of known path (type name)
167 Iterator,
167 IntoIterator, 168 IntoIterator,
168 Item, 169 Item,
169 Try, 170 Try,
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}