diff options
-rw-r--r-- | crates/hir/src/lib.rs | 58 | ||||
-rw-r--r-- | crates/hir_ty/src/method_resolution.rs | 10 | ||||
-rw-r--r-- | crates/ide/src/goto_implementation.rs | 130 | ||||
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 2 |
4 files changed, 136 insertions, 64 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 25e5bfb01..c5161dadd 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -51,7 +51,8 @@ use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; | |||
51 | use hir_ty::{ | 51 | use hir_ty::{ |
52 | autoderef, | 52 | autoderef, |
53 | display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter}, | 53 | display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter}, |
54 | method_resolution, to_assoc_type_id, | 54 | method_resolution::{self, TyFingerprint}, |
55 | to_assoc_type_id, | ||
55 | traits::{FnTrait, Solution, SolutionVariables}, | 56 | traits::{FnTrait, Solution, SolutionVariables}, |
56 | AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, | 57 | AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, |
57 | InEnvironment, Interner, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, Ty, | 58 | InEnvironment, Interner, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, Ty, |
@@ -695,8 +696,8 @@ impl Adt { | |||
695 | } | 696 | } |
696 | } | 697 | } |
697 | 698 | ||
698 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | 699 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { |
699 | Some(self.module(db).krate()) | 700 | self.module(db).krate() |
700 | } | 701 | } |
701 | 702 | ||
702 | pub fn name(self, db: &dyn HirDatabase) -> Name { | 703 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
@@ -1018,8 +1019,8 @@ impl TypeAlias { | |||
1018 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | 1019 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } |
1019 | } | 1020 | } |
1020 | 1021 | ||
1021 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | 1022 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { |
1022 | Some(self.module(db).krate()) | 1023 | self.module(db).krate() |
1023 | } | 1024 | } |
1024 | 1025 | ||
1025 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { | 1026 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { |
@@ -1482,9 +1483,44 @@ impl Impl { | |||
1482 | 1483 | ||
1483 | inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() | 1484 | inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() |
1484 | } | 1485 | } |
1485 | pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> { | 1486 | |
1486 | let impls = db.trait_impls_in_crate(krate.id); | 1487 | pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty }: Type) -> Vec<Impl> { |
1487 | impls.for_trait(trait_.id).map(Self::from).collect() | 1488 | let def_crates = match ty.value.def_crates(db, krate) { |
1489 | Some(def_crates) => def_crates, | ||
1490 | None => return Vec::new(), | ||
1491 | }; | ||
1492 | |||
1493 | let filter = |impl_def: &Impl| { | ||
1494 | let target_ty = impl_def.target_ty(db); | ||
1495 | let rref = target_ty.remove_ref(); | ||
1496 | ty.value.equals_ctor(rref.as_ref().map_or(&target_ty.ty.value, |it| &it.ty.value)) | ||
1497 | }; | ||
1498 | |||
1499 | let mut all = Vec::new(); | ||
1500 | def_crates.into_iter().for_each(|id| { | ||
1501 | all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter)) | ||
1502 | }); | ||
1503 | let fp = TyFingerprint::for_impl(&ty.value); | ||
1504 | for id in db.crate_graph().iter() { | ||
1505 | match fp { | ||
1506 | Some(fp) => all.extend( | ||
1507 | db.trait_impls_in_crate(id).for_self_ty(fp).map(Self::from).filter(filter), | ||
1508 | ), | ||
1509 | None => all | ||
1510 | .extend(db.trait_impls_in_crate(id).all_impls().map(Self::from).filter(filter)), | ||
1511 | } | ||
1512 | } | ||
1513 | all | ||
1514 | } | ||
1515 | |||
1516 | pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> { | ||
1517 | let krate = trait_.module(db).krate(); | ||
1518 | let mut all = Vec::new(); | ||
1519 | for Crate { id } in krate.reverse_dependencies(db).into_iter().chain(Some(krate)) { | ||
1520 | let impls = db.trait_impls_in_crate(id); | ||
1521 | all.extend(impls.for_trait(trait_.id).map(Self::from)) | ||
1522 | } | ||
1523 | all | ||
1488 | } | 1524 | } |
1489 | 1525 | ||
1490 | // FIXME: the return type is wrong. This should be a hir version of | 1526 | // FIXME: the return type is wrong. This should be a hir version of |
@@ -1932,12 +1968,6 @@ impl Type { | |||
1932 | self.ty.value.associated_type_parent_trait(db).map(Into::into) | 1968 | self.ty.value.associated_type_parent_trait(db).map(Into::into) |
1933 | } | 1969 | } |
1934 | 1970 | ||
1935 | // FIXME: provide required accessors such that it becomes implementable from outside. | ||
1936 | pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { | ||
1937 | let rref = other.remove_ref(); | ||
1938 | self.ty.value.equals_ctor(rref.as_ref().map_or(&other.ty.value, |it| &it.ty.value)) | ||
1939 | } | ||
1940 | |||
1941 | fn derived(&self, ty: Ty) -> Type { | 1971 | fn derived(&self, ty: Ty) -> Type { |
1942 | Type { | 1972 | Type { |
1943 | krate: self.krate, | 1973 | krate: self.krate, |
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index 741440006..be72c4a1c 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -44,7 +44,7 @@ impl TyFingerprint { | |||
44 | /// Creates a TyFingerprint for looking up an impl. Only certain types can | 44 | /// Creates a TyFingerprint for looking up an impl. Only certain types can |
45 | /// have impls: if we have some `struct S`, we can have an `impl S`, but not | 45 | /// have impls: if we have some `struct S`, we can have an `impl S`, but not |
46 | /// `impl &S`. Hence, this will return `None` for reference types and such. | 46 | /// `impl &S`. Hence, this will return `None` for reference types and such. |
47 | pub(crate) fn for_impl(ty: &Ty) -> Option<TyFingerprint> { | 47 | pub fn for_impl(ty: &Ty) -> Option<TyFingerprint> { |
48 | let fp = match *ty.interned(&Interner) { | 48 | let fp = match *ty.interned(&Interner) { |
49 | TyKind::Str => TyFingerprint::Str, | 49 | TyKind::Str => TyFingerprint::Str, |
50 | TyKind::Never => TyFingerprint::Never, | 50 | TyKind::Never => TyFingerprint::Never, |
@@ -141,6 +141,14 @@ impl TraitImpls { | |||
141 | } | 141 | } |
142 | } | 142 | } |
143 | 143 | ||
144 | /// Queries all trait impls for the given type. | ||
145 | pub fn for_self_ty(&self, fp: TyFingerprint) -> impl Iterator<Item = ImplId> + '_ { | ||
146 | self.map | ||
147 | .values() | ||
148 | .flat_map(move |impls| impls.get(&None).into_iter().chain(impls.get(&Some(fp)))) | ||
149 | .flat_map(|it| it.iter().copied()) | ||
150 | } | ||
151 | |||
144 | /// Queries all impls of the given trait. | 152 | /// Queries all impls of the given trait. |
145 | pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ { | 153 | pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ { |
146 | self.map | 154 | self.map |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 3990305fc..f4d7c14a6 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | use hir::{Crate, Impl, Semantics}; | 1 | use hir::{Impl, Semantics}; |
2 | use ide_db::RootDatabase; | 2 | use ide_db::{ |
3 | use syntax::{algo::find_node_at_offset, ast, AstNode}; | 3 | defs::{Definition, NameClass, NameRefClass}, |
4 | RootDatabase, | ||
5 | }; | ||
6 | use syntax::{ast, AstNode}; | ||
4 | 7 | ||
5 | use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; | 8 | use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; |
6 | 9 | ||
@@ -21,55 +24,42 @@ pub(crate) fn goto_implementation( | |||
21 | let source_file = sema.parse(position.file_id); | 24 | let source_file = sema.parse(position.file_id); |
22 | let syntax = source_file.syntax().clone(); | 25 | let syntax = source_file.syntax().clone(); |
23 | 26 | ||
24 | let krate = sema.to_module_def(position.file_id)?.krate(); | 27 | let node = sema.find_node_at_offset_with_descend(&syntax, position.offset)?; |
25 | 28 | let def = match &node { | |
26 | if let Some(nominal_def) = find_node_at_offset::<ast::Adt>(&syntax, position.offset) { | 29 | ast::NameLike::Name(name) => { |
27 | return Some(RangeInfo::new( | 30 | NameClass::classify(&sema, name).map(|class| class.referenced_or_defined(sema.db)) |
28 | nominal_def.syntax().text_range(), | 31 | } |
29 | impls_for_def(&sema, &nominal_def, krate)?, | 32 | ast::NameLike::NameRef(name_ref) => { |
30 | )); | 33 | NameRefClass::classify(&sema, name_ref).map(|class| class.referenced(sema.db)) |
31 | } else if let Some(trait_def) = find_node_at_offset::<ast::Trait>(&syntax, position.offset) { | 34 | } |
32 | return Some(RangeInfo::new( | 35 | ast::NameLike::Lifetime(_) => None, |
33 | trait_def.syntax().text_range(), | 36 | }?; |
34 | impls_for_trait(&sema, &trait_def, krate)?, | 37 | let def = match def { |
35 | )); | 38 | Definition::ModuleDef(def) => def, |
36 | } | 39 | _ => return None, |
37 | |||
38 | None | ||
39 | } | ||
40 | |||
41 | fn impls_for_def( | ||
42 | sema: &Semantics<RootDatabase>, | ||
43 | node: &ast::Adt, | ||
44 | krate: Crate, | ||
45 | ) -> Option<Vec<NavigationTarget>> { | ||
46 | let ty = match node { | ||
47 | ast::Adt::Struct(def) => sema.to_def(def)?.ty(sema.db), | ||
48 | ast::Adt::Enum(def) => sema.to_def(def)?.ty(sema.db), | ||
49 | ast::Adt::Union(def) => sema.to_def(def)?.ty(sema.db), | ||
50 | }; | 40 | }; |
51 | 41 | let navs = match def { | |
52 | let impls = Impl::all_in_crate(sema.db, krate); | 42 | hir::ModuleDef::Trait(trait_) => impls_for_trait(&sema, trait_), |
53 | 43 | hir::ModuleDef::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)), | |
54 | Some( | 44 | hir::ModuleDef::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)), |
55 | impls | 45 | hir::ModuleDef::BuiltinType(builtin) => { |
56 | .into_iter() | 46 | let module = sema.to_module_def(position.file_id)?; |
57 | .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) | 47 | impls_for_ty(&sema, builtin.ty(sema.db, module)) |
58 | .filter_map(|imp| imp.try_to_nav(sema.db)) | 48 | } |
59 | .collect(), | 49 | _ => return None, |
60 | ) | 50 | }; |
51 | Some(RangeInfo { range: node.syntax().text_range(), info: navs }) | ||
61 | } | 52 | } |
62 | 53 | ||
63 | fn impls_for_trait( | 54 | fn impls_for_ty(sema: &Semantics<RootDatabase>, ty: hir::Type) -> Vec<NavigationTarget> { |
64 | sema: &Semantics<RootDatabase>, | 55 | Impl::all_for_type(sema.db, ty).into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect() |
65 | node: &ast::Trait, | 56 | } |
66 | krate: Crate, | ||
67 | ) -> Option<Vec<NavigationTarget>> { | ||
68 | let tr = sema.to_def(node)?; | ||
69 | |||
70 | let impls = Impl::for_trait(sema.db, krate, tr); | ||
71 | 57 | ||
72 | Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect()) | 58 | fn impls_for_trait(sema: &Semantics<RootDatabase>, trait_: hir::Trait) -> Vec<NavigationTarget> { |
59 | Impl::all_for_trait(sema.db, trait_) | ||
60 | .into_iter() | ||
61 | .filter_map(|imp| imp.try_to_nav(sema.db)) | ||
62 | .collect() | ||
73 | } | 63 | } |
74 | 64 | ||
75 | #[cfg(test)] | 65 | #[cfg(test)] |
@@ -226,4 +216,48 @@ macro Copy {} | |||
226 | "#, | 216 | "#, |
227 | ); | 217 | ); |
228 | } | 218 | } |
219 | |||
220 | #[test] | ||
221 | fn goto_implementation_type_alias() { | ||
222 | check( | ||
223 | r#" | ||
224 | struct Foo; | ||
225 | |||
226 | type Bar$0 = Foo; | ||
227 | |||
228 | impl Foo {} | ||
229 | //^^^ | ||
230 | impl Bar {} | ||
231 | //^^^ | ||
232 | "#, | ||
233 | ); | ||
234 | } | ||
235 | |||
236 | #[test] | ||
237 | fn goto_implementation_adt_generic() { | ||
238 | check( | ||
239 | r#" | ||
240 | struct Foo$0<T>; | ||
241 | |||
242 | impl<T> Foo<T> {} | ||
243 | //^^^^^^ | ||
244 | impl Foo<str> {} | ||
245 | //^^^^^^^^ | ||
246 | "#, | ||
247 | ); | ||
248 | } | ||
249 | |||
250 | #[test] | ||
251 | fn goto_implementation_builtin() { | ||
252 | check( | ||
253 | r#" | ||
254 | //- /lib.rs crate:main deps:core | ||
255 | fn foo(_: bool$0) {{}} | ||
256 | //- /libcore.rs crate:core | ||
257 | #[lang = "bool"] | ||
258 | impl bool {} | ||
259 | //^^^^ | ||
260 | "#, | ||
261 | ); | ||
262 | } | ||
229 | } | 263 | } |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 4ceb20742..16c04eeee 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -219,7 +219,7 @@ fn hint_iterator( | |||
219 | let strukt = std::iter::successors(Some(ty.clone()), |ty| ty.remove_ref()) | 219 | let strukt = std::iter::successors(Some(ty.clone()), |ty| ty.remove_ref()) |
220 | .last() | 220 | .last() |
221 | .and_then(|strukt| strukt.as_adt())?; | 221 | .and_then(|strukt| strukt.as_adt())?; |
222 | let krate = strukt.krate(db)?; | 222 | let krate = strukt.krate(db); |
223 | if krate != famous_defs.core()? { | 223 | if krate != famous_defs.core()? { |
224 | return None; | 224 | return None; |
225 | } | 225 | } |