diff options
author | Florian Diebold <[email protected]> | 2019-03-26 22:07:26 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-04-14 10:28:53 +0100 |
commit | 413c87f155ab6b389b1cc122b5739716acccb476 (patch) | |
tree | ece00ee4bb46d32ec2a3c4124a43e3634eacd007 /crates | |
parent | 23b876bc3b00c53ce24b8a99b4f4bf190fc6300e (diff) |
Get substs for trait refs in impl blocks
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/generics.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/impl_block.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 95 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 2 |
6 files changed, 85 insertions, 44 deletions
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 84fe94289..4d82fe25f 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs | |||
@@ -56,7 +56,11 @@ impl GenericParams { | |||
56 | GenericDef::Function(it) => generics.fill(&*it.source(db).1, start), | 56 | GenericDef::Function(it) => generics.fill(&*it.source(db).1, start), |
57 | GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start), | 57 | GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start), |
58 | GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start), | 58 | GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start), |
59 | GenericDef::Trait(it) => generics.fill(&*it.source(db).1, start), | 59 | GenericDef::Trait(it) => { |
60 | // traits get the Self type as an implicit first type parameter | ||
61 | generics.params.push(GenericParam { idx: start, name: Name::self_type() }); | ||
62 | generics.fill(&*it.source(db).1, start + 1); | ||
63 | } | ||
60 | GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start), | 64 | GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start), |
61 | GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start), | 65 | GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start), |
62 | } | 66 | } |
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index b306874cc..822a1a0db 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -10,15 +10,13 @@ use ra_syntax::{ | |||
10 | use crate::{ | 10 | use crate::{ |
11 | Const, TypeAlias, Function, HirFileId, | 11 | Const, TypeAlias, Function, HirFileId, |
12 | HirDatabase, DefDatabase, | 12 | HirDatabase, DefDatabase, |
13 | ModuleDef, Trait, Resolution, | ||
14 | type_ref::TypeRef, | 13 | type_ref::TypeRef, |
15 | ids::LocationCtx, | 14 | ids::LocationCtx, |
16 | resolve::Resolver, | 15 | resolve::Resolver, |
17 | ty::Ty, generics::GenericParams, | 16 | ty::Ty, generics::GenericParams, |
17 | TraitRef, code_model_api::{Module, ModuleSource} | ||
18 | }; | 18 | }; |
19 | 19 | ||
20 | use crate::code_model_api::{Module, ModuleSource}; | ||
21 | |||
22 | #[derive(Debug, Default, PartialEq, Eq)] | 20 | #[derive(Debug, Default, PartialEq, Eq)] |
23 | pub struct ImplSourceMap { | 21 | pub struct ImplSourceMap { |
24 | map: ArenaMap<ImplId, AstPtr<ast::ImplBlock>>, | 22 | map: ArenaMap<ImplId, AstPtr<ast::ImplBlock>>, |
@@ -73,7 +71,7 @@ impl ImplBlock { | |||
73 | self.module | 71 | self.module |
74 | } | 72 | } |
75 | 73 | ||
76 | pub fn target_trait_ref(&self, db: &impl DefDatabase) -> Option<TypeRef> { | 74 | pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> { |
77 | db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned() | 75 | db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned() |
78 | } | 76 | } |
79 | 77 | ||
@@ -85,16 +83,8 @@ impl ImplBlock { | |||
85 | Ty::from_hir(db, &self.resolver(db), &self.target_type(db)) | 83 | Ty::from_hir(db, &self.resolver(db), &self.target_type(db)) |
86 | } | 84 | } |
87 | 85 | ||
88 | pub fn target_trait(&self, db: &impl HirDatabase) -> Option<Trait> { | 86 | pub fn target_trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> { |
89 | if let Some(TypeRef::Path(path)) = self.target_trait_ref(db) { | 87 | TraitRef::from_hir(db, &self.resolver(db), &self.target_trait(db)?) |
90 | let resolver = self.resolver(db); | ||
91 | if let Some(Resolution::Def(ModuleDef::Trait(tr))) = | ||
92 | resolver.resolve_path(db, &path).take_types() | ||
93 | { | ||
94 | return Some(tr); | ||
95 | } | ||
96 | } | ||
97 | None | ||
98 | } | 88 | } |
99 | 89 | ||
100 | pub fn items(&self, db: &impl DefDatabase) -> Vec<ImplItem> { | 90 | pub fn items(&self, db: &impl DefDatabase) -> Vec<ImplItem> { |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index a9db23060..c284d1693 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -61,7 +61,7 @@ pub use self::{ | |||
61 | source_id::{AstIdMap, ErasedFileAstId}, | 61 | source_id::{AstIdMap, ErasedFileAstId}, |
62 | ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc}, | 62 | ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc}, |
63 | nameres::{PerNs, Namespace, ImportId}, | 63 | nameres::{PerNs, Namespace, ImportId}, |
64 | ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay, CallableDef}, | 64 | ty::{Ty, ApplicationTy, TypeCtor, TraitRef, Substs, display::HirDisplay, CallableDef}, |
65 | impl_block::{ImplBlock, ImplItem}, | 65 | impl_block::{ImplBlock, ImplItem}, |
66 | docs::{Docs, Documentation}, | 66 | docs::{Docs, Documentation}, |
67 | adt::AdtDef, | 67 | adt::AdtDef, |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 003a89f0d..4523b3954 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -17,9 +17,9 @@ use crate::{ | |||
17 | resolve::{Resolver, Resolution}, | 17 | resolve::{Resolver, Resolution}, |
18 | path::{ PathSegment, GenericArg}, | 18 | path::{ PathSegment, GenericArg}, |
19 | generics::GenericParams, | 19 | generics::GenericParams, |
20 | adt::VariantDef, | 20 | adt::VariantDef, Trait |
21 | }; | 21 | }; |
22 | use super::{Ty, primitive, FnSig, Substs, TypeCtor}; | 22 | use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef}; |
23 | 23 | ||
24 | impl Ty { | 24 | impl Ty { |
25 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { | 25 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { |
@@ -115,7 +115,6 @@ impl Ty { | |||
115 | segment: &PathSegment, | 115 | segment: &PathSegment, |
116 | resolved: TypableDef, | 116 | resolved: TypableDef, |
117 | ) -> Substs { | 117 | ) -> Substs { |
118 | let mut substs = Vec::new(); | ||
119 | let def_generics = match resolved { | 118 | let def_generics = match resolved { |
120 | TypableDef::Function(func) => func.generic_params(db), | 119 | TypableDef::Function(func) => func.generic_params(db), |
121 | TypableDef::Struct(s) => s.generic_params(db), | 120 | TypableDef::Struct(s) => s.generic_params(db), |
@@ -124,28 +123,7 @@ impl Ty { | |||
124 | TypableDef::TypeAlias(t) => t.generic_params(db), | 123 | TypableDef::TypeAlias(t) => t.generic_params(db), |
125 | TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), | 124 | TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), |
126 | }; | 125 | }; |
127 | let parent_param_count = def_generics.count_parent_params(); | 126 | substs_from_path_segment(db, resolver, segment, &def_generics, false) |
128 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); | ||
129 | if let Some(generic_args) = &segment.args_and_bindings { | ||
130 | // if args are provided, it should be all of them, but we can't rely on that | ||
131 | let param_count = def_generics.params.len(); | ||
132 | for arg in generic_args.args.iter().take(param_count) { | ||
133 | match arg { | ||
134 | GenericArg::Type(type_ref) => { | ||
135 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
136 | substs.push(ty); | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | // add placeholders for args that were not provided | ||
142 | // FIXME: handle defaults | ||
143 | let supplied_params = substs.len(); | ||
144 | for _ in supplied_params..def_generics.count_params_including_parent() { | ||
145 | substs.push(Ty::Unknown); | ||
146 | } | ||
147 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | ||
148 | Substs(substs.into()) | ||
149 | } | 127 | } |
150 | 128 | ||
151 | /// Collect generic arguments from a path into a `Substs`. See also | 129 | /// Collect generic arguments from a path into a `Substs`. See also |
@@ -185,6 +163,73 @@ impl Ty { | |||
185 | } | 163 | } |
186 | } | 164 | } |
187 | 165 | ||
166 | pub(super) fn substs_from_path_segment( | ||
167 | db: &impl HirDatabase, | ||
168 | resolver: &Resolver, | ||
169 | segment: &PathSegment, | ||
170 | def_generics: &GenericParams, | ||
171 | add_self_param: bool, | ||
172 | ) -> Substs { | ||
173 | let mut substs = Vec::new(); | ||
174 | let parent_param_count = def_generics.count_parent_params(); | ||
175 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); | ||
176 | if add_self_param { | ||
177 | // FIXME this add_self_param argument is kind of a hack: Traits have the | ||
178 | // Self type as an implicit first type parameter, but it can't be | ||
179 | // actually provided in the type arguments | ||
180 | substs.push(Ty::Unknown); | ||
181 | } | ||
182 | if let Some(generic_args) = &segment.args_and_bindings { | ||
183 | // if args are provided, it should be all of them, but we can't rely on that | ||
184 | let param_count = def_generics.params.len(); | ||
185 | for arg in generic_args.args.iter().take(param_count) { | ||
186 | match arg { | ||
187 | GenericArg::Type(type_ref) => { | ||
188 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
189 | substs.push(ty); | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | // add placeholders for args that were not provided | ||
195 | // FIXME: handle defaults | ||
196 | let supplied_params = substs.len(); | ||
197 | for _ in supplied_params..def_generics.count_params_including_parent() { | ||
198 | substs.push(Ty::Unknown); | ||
199 | } | ||
200 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | ||
201 | Substs(substs.into()) | ||
202 | } | ||
203 | |||
204 | impl TraitRef { | ||
205 | pub(crate) fn from_hir( | ||
206 | db: &impl HirDatabase, | ||
207 | resolver: &Resolver, | ||
208 | type_ref: &TypeRef, | ||
209 | ) -> Option<Self> { | ||
210 | let path = match type_ref { | ||
211 | TypeRef::Path(path) => path, | ||
212 | _ => return None, | ||
213 | }; | ||
214 | let resolved = match resolver.resolve_path(db, &path).take_types()? { | ||
215 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | ||
216 | _ => return None, | ||
217 | }; | ||
218 | let substs = Self::substs_from_path(db, resolver, path, resolved); | ||
219 | Some(TraitRef { trait_: resolved, substs }) | ||
220 | } | ||
221 | |||
222 | fn substs_from_path( | ||
223 | db: &impl HirDatabase, | ||
224 | resolver: &Resolver, | ||
225 | path: &Path, | ||
226 | resolved: Trait, | ||
227 | ) -> Substs { | ||
228 | let segment = path.segments.last().expect("path should have at least one segment"); | ||
229 | substs_from_path_segment(db, resolver, segment, &resolved.generic_params(db), true) | ||
230 | } | ||
231 | } | ||
232 | |||
188 | /// Build the declared type of an item. This depends on the namespace; e.g. for | 233 | /// Build the declared type of an item. This depends on the namespace; e.g. for |
189 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | 234 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and |
190 | /// the constructor function `(usize) -> Foo` which lives in the values | 235 | /// the constructor function `(usize) -> Foo` which lives in the values |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index bb23246a6..aac7d6384 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -72,9 +72,9 @@ impl CrateImplBlocks { | |||
72 | 72 | ||
73 | let target_ty = impl_block.target_ty(db); | 73 | let target_ty = impl_block.target_ty(db); |
74 | 74 | ||
75 | if let Some(tr) = impl_block.target_trait(db) { | 75 | if let Some(tr) = impl_block.target_trait_ref(db) { |
76 | self.impls_by_trait | 76 | self.impls_by_trait |
77 | .entry(tr) | 77 | .entry(tr.trait_) |
78 | .or_insert_with(Vec::new) | 78 | .or_insert_with(Vec::new) |
79 | .push((module.module_id, impl_id)); | 79 | .push((module.module_id, impl_id)); |
80 | } else { | 80 | } else { |
@@ -185,6 +185,8 @@ impl Ty { | |||
185 | // well (in fact, the 'implements' condition could just be considered a | 185 | // well (in fact, the 'implements' condition could just be considered a |
186 | // 'where Self: Trait' clause) | 186 | // 'where Self: Trait' clause) |
187 | candidates.retain(|(t, _m)| { | 187 | candidates.retain(|(t, _m)| { |
188 | // FIXME construct substs of the correct length for the trait | ||
189 | // - check in rustc whether it does anything smarter than putting variables for everything | ||
188 | let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) }; | 190 | let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) }; |
189 | db.implements(trait_ref) | 191 | db.implements(trait_ref) |
190 | }); | 192 | }); |
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 517dffbca..40a2bd148 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -104,7 +104,7 @@ pub(crate) fn reference_definition( | |||
104 | } | 104 | } |
105 | } | 105 | } |
106 | hir::PathResolution::AssocItem(assoc) => { | 106 | hir::PathResolution::AssocItem(assoc) => { |
107 | return Exact(NavigationTarget::from_impl_item(db, assoc)) | 107 | return Exact(NavigationTarget::from_impl_item(db, assoc)); |
108 | } | 108 | } |
109 | } | 109 | } |
110 | } | 110 | } |