aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-03-26 22:07:26 +0000
committerFlorian Diebold <[email protected]>2019-04-14 10:28:53 +0100
commit413c87f155ab6b389b1cc122b5739716acccb476 (patch)
treeece00ee4bb46d32ec2a3c4124a43e3634eacd007 /crates
parent23b876bc3b00c53ce24b8a99b4f4bf190fc6300e (diff)
Get substs for trait refs in impl blocks
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/generics.rs6
-rw-r--r--crates/ra_hir/src/impl_block.rs18
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/ty/lower.rs95
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs6
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs2
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::{
10use crate::{ 10use 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
20use crate::code_model_api::{Module, ModuleSource};
21
22#[derive(Debug, Default, PartialEq, Eq)] 20#[derive(Debug, Default, PartialEq, Eq)]
23pub struct ImplSourceMap { 21pub 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};
22use super::{Ty, primitive, FnSig, Substs, TypeCtor}; 22use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef};
23 23
24impl Ty { 24impl 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
166pub(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
204impl 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 }