aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_db/src/lib.rs57
-rw-r--r--crates/ra_hir/src/db.rs14
-rw-r--r--crates/ra_hir_def/src/db.rs18
-rw-r--r--crates/ra_hir_def/src/find_path.rs202
-rw-r--r--crates/ra_hir_def/src/import_map.rs331
-rw-r--r--crates/ra_hir_def/src/item_scope.rs23
-rw-r--r--crates/ra_hir_def/src/lib.rs1
-rw-r--r--crates/ra_hir_def/src/path.rs13
-rw-r--r--crates/ra_hir_def/src/per_ns.rs10
-rw-r--r--crates/ra_hir_def/src/test_db.rs12
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs18
-rw-r--r--crates/ra_hir_expand/src/test_db.rs9
-rw-r--r--crates/ra_hir_ty/src/db.rs20
-rw-r--r--crates/ra_hir_ty/src/display.rs39
-rw-r--r--crates/ra_hir_ty/src/infer.rs23
-rw-r--r--crates/ra_hir_ty/src/lib.rs98
-rw-r--r--crates/ra_hir_ty/src/lower.rs144
-rw-r--r--crates/ra_hir_ty/src/test_db.rs11
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs90
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs52
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/interner.rs2
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/mapping.rs45
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs5
-rw-r--r--crates/ra_ide/src/hover.rs148
-rw-r--r--crates/ra_ide/src/lib.rs2
-rw-r--r--crates/ra_ide_db/src/change.rs2
-rw-r--r--crates/ra_ide_db/src/defs.rs2
-rw-r--r--crates/ra_ide_db/src/lib.rs11
-rw-r--r--crates/rust-analyzer/src/config.rs29
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs32
-rw-r--r--crates/rust-analyzer/src/main_loop.rs2
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs129
32 files changed, 1272 insertions, 322 deletions
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 2e63cb46e..91e0ee619 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -11,8 +11,8 @@ use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize};
11pub use crate::{ 11pub use crate::{
12 cancellation::Canceled, 12 cancellation::Canceled,
13 input::{ 13 input::{
14 CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, ExternSourceId, 14 CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource,
15 FileId, ProcMacroId, SourceRoot, SourceRootId, 15 ExternSourceId, FileId, ProcMacroId, SourceRoot, SourceRootId,
16 }, 16 },
17}; 17};
18pub use relative_path::{RelativePath, RelativePathBuf}; 18pub use relative_path::{RelativePath, RelativePathBuf};
@@ -89,14 +89,13 @@ pub const DEFAULT_LRU_CAP: usize = 128;
89pub trait FileLoader { 89pub trait FileLoader {
90 /// Text of the file. 90 /// Text of the file.
91 fn file_text(&self, file_id: FileId) -> Arc<String>; 91 fn file_text(&self, file_id: FileId) -> Arc<String>;
92 /// Note that we intentionally accept a `&str` and not a `&Path` here. This
93 /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such,
94 /// so the input is guaranteed to be utf-8 string. We might introduce
95 /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we
96 /// get by with a `&str` for the time being.
92 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>; 97 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>;
93 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>; 98 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>;
94
95 fn resolve_extern_path(
96 &self,
97 extern_id: ExternSourceId,
98 relative_path: &RelativePath,
99 ) -> Option<FileId>;
100} 99}
101 100
102/// Database which stores all significant input facts: source code and project 101/// Database which stores all significant input facts: source code and project
@@ -154,34 +153,30 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
154 fn file_text(&self, file_id: FileId) -> Arc<String> { 153 fn file_text(&self, file_id: FileId) -> Arc<String> {
155 SourceDatabaseExt::file_text(self.0, file_id) 154 SourceDatabaseExt::file_text(self.0, file_id)
156 } 155 }
157 /// Note that we intentionally accept a `&str` and not a `&Path` here. This
158 /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such,
159 /// so the input is guaranteed to be utf-8 string. We might introduce
160 /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we
161 /// get by with a `&str` for the time being.
162 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 156 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
163 let rel_path = { 157 // FIXME: this *somehow* should be platform agnostic...
164 let mut rel_path = self.0.file_relative_path(anchor); 158 if std::path::Path::new(path).is_absolute() {
165 assert!(rel_path.pop()); 159 let krate = *self.relevant_crates(anchor).get(0)?;
166 rel_path.push(path); 160 let (extern_source_id, relative_file) =
167 rel_path.normalize() 161 self.0.crate_graph()[krate].extern_source.extern_path(path)?;
168 }; 162
169 let source_root = self.0.file_source_root(anchor); 163 let source_root = self.0.source_root(SourceRootId(extern_source_id.0));
170 let source_root = self.0.source_root(source_root); 164 source_root.file_by_relative_path(&relative_file)
171 source_root.file_by_relative_path(&rel_path) 165 } else {
166 let rel_path = {
167 let mut rel_path = self.0.file_relative_path(anchor);
168 assert!(rel_path.pop());
169 rel_path.push(path);
170 rel_path.normalize()
171 };
172 let source_root = self.0.file_source_root(anchor);
173 let source_root = self.0.source_root(source_root);
174 source_root.file_by_relative_path(&rel_path)
175 }
172 } 176 }
173 177
174 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { 178 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
175 let source_root = self.0.file_source_root(file_id); 179 let source_root = self.0.file_source_root(file_id);
176 self.0.source_root_crates(source_root) 180 self.0.source_root_crates(source_root)
177 } 181 }
178
179 fn resolve_extern_path(
180 &self,
181 extern_id: ExternSourceId,
182 relative_path: &RelativePath,
183 ) -> Option<FileId> {
184 let source_root = self.0.source_root(SourceRootId(extern_id.0));
185 source_root.file_by_relative_path(&relative_path)
186 }
187} 182}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index ec931b34f..b6b665de1 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -3,11 +3,11 @@
3pub use hir_def::db::{ 3pub use hir_def::db::{
4 AttrsQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQueryQuery, 4 AttrsQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQueryQuery,
5 CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, 5 CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery,
6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternConstQuery, 6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery,
7 InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, InternImplQuery, 7 InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery,
8 InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery, 8 InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery,
9 LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, StructDataQuery, 9 InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery,
10 TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, 10 StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
11}; 11};
12pub use hir_expand::db::{ 12pub use hir_expand::db::{
13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, 13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery,
@@ -18,8 +18,8 @@ pub use hir_ty::db::{
18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, 18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase,
19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery, 19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery,
20 ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, 20 ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery,
21 InternTypeCtorQuery, InternTypeParamIdQuery, StructDatumQuery, TraitDatumQuery, 21 InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery,
22 TraitSolveQuery, TyQuery, ValueTyQuery, 22 TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery,
23}; 23};
24 24
25#[test] 25#[test]
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 945a0025e..10cc26480 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -1,7 +1,7 @@
1//! Defines database & queries for name resolution. 1//! Defines database & queries for name resolution.
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use hir_expand::{db::AstDatabase, name::Name, HirFileId}; 4use hir_expand::{db::AstDatabase, HirFileId};
5use ra_db::{salsa, CrateId, SourceDatabase, Upcast}; 5use ra_db::{salsa, CrateId, SourceDatabase, Upcast};
6use ra_prof::profile; 6use ra_prof::profile;
7use ra_syntax::SmolStr; 7use ra_syntax::SmolStr;
@@ -12,13 +12,10 @@ use crate::{
12 body::{scope::ExprScopes, Body, BodySourceMap}, 12 body::{scope::ExprScopes, Body, BodySourceMap},
13 data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, 13 data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData},
14 docs::Documentation, 14 docs::Documentation,
15 find_path,
16 generics::GenericParams, 15 generics::GenericParams,
17 item_scope::ItemInNs, 16 import_map::ImportMap,
18 lang_item::{LangItemTarget, LangItems}, 17 lang_item::{LangItemTarget, LangItems},
19 nameres::{raw::RawItems, CrateDefMap}, 18 nameres::{raw::RawItems, CrateDefMap},
20 path::ModPath,
21 visibility::Visibility,
22 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, 19 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc,
23 GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, 20 GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId,
24 TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, 21 TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
@@ -113,15 +110,8 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
113 #[salsa::invoke(Documentation::documentation_query)] 110 #[salsa::invoke(Documentation::documentation_query)]
114 fn documentation(&self, def: AttrDefId) -> Option<Documentation>; 111 fn documentation(&self, def: AttrDefId) -> Option<Documentation>;
115 112
116 #[salsa::invoke(find_path::importable_locations_of_query)] 113 #[salsa::invoke(ImportMap::import_map_query)]
117 fn importable_locations_of( 114 fn import_map(&self, krate: CrateId) -> Arc<ImportMap>;
118 &self,
119 item: ItemInNs,
120 krate: CrateId,
121 ) -> Arc<[(ModuleId, Name, Visibility)]>;
122
123 #[salsa::invoke(find_path::find_path_inner_query)]
124 fn find_path_inner(&self, item: ItemInNs, from: ModuleId, max_len: usize) -> Option<ModPath>;
125} 115}
126 116
127fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { 117fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> {
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs
index 4db798473..a7f59e028 100644
--- a/crates/ra_hir_def/src/find_path.rs
+++ b/crates/ra_hir_def/src/find_path.rs
@@ -1,9 +1,8 @@
1//! An algorithm to find a path to refer to a certain item. 1//! An algorithm to find a path to refer to a certain item.
2 2
3use std::sync::Arc;
4
5use hir_expand::name::{known, AsName, Name}; 3use hir_expand::name::{known, AsName, Name};
6use ra_prof::profile; 4use ra_prof::profile;
5use rustc_hash::FxHashSet;
7use test_utils::mark; 6use test_utils::mark;
8 7
9use crate::{ 8use crate::{
@@ -11,7 +10,7 @@ use crate::{
11 item_scope::ItemInNs, 10 item_scope::ItemInNs,
12 path::{ModPath, PathKind}, 11 path::{ModPath, PathKind},
13 visibility::Visibility, 12 visibility::Visibility,
14 CrateId, ModuleDefId, ModuleId, 13 ModuleDefId, ModuleId,
15}; 14};
16 15
17// FIXME: handle local items 16// FIXME: handle local items
@@ -20,7 +19,7 @@ use crate::{
20/// *from where* you're referring to the item, hence the `from` parameter. 19/// *from where* you're referring to the item, hence the `from` parameter.
21pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { 20pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
22 let _p = profile("find_path"); 21 let _p = profile("find_path");
23 db.find_path_inner(item, from, MAX_PATH_LEN) 22 find_path_inner(db, item, from, MAX_PATH_LEN)
24} 23}
25 24
26const MAX_PATH_LEN: usize = 15; 25const MAX_PATH_LEN: usize = 15;
@@ -36,20 +35,9 @@ impl ModPath {
36 let first_segment = self.segments.first(); 35 let first_segment = self.segments.first();
37 first_segment == Some(&known::alloc) || first_segment == Some(&known::core) 36 first_segment == Some(&known::alloc) || first_segment == Some(&known::core)
38 } 37 }
39
40 fn len(&self) -> usize {
41 self.segments.len()
42 + match self.kind {
43 PathKind::Plain => 0,
44 PathKind::Super(i) => i as usize,
45 PathKind::Crate => 1,
46 PathKind::Abs => 0,
47 PathKind::DollarCrate(_) => 1,
48 }
49 }
50} 38}
51 39
52pub(crate) fn find_path_inner_query( 40fn find_path_inner(
53 db: &dyn DefDatabase, 41 db: &dyn DefDatabase,
54 item: ItemInNs, 42 item: ItemInNs,
55 from: ModuleId, 43 from: ModuleId,
@@ -133,31 +121,61 @@ pub(crate) fn find_path_inner_query(
133 } 121 }
134 122
135 // - otherwise, look for modules containing (reexporting) it and import it from one of those 123 // - otherwise, look for modules containing (reexporting) it and import it from one of those
124
136 let crate_root = ModuleId { local_id: def_map.root, krate: from.krate }; 125 let crate_root = ModuleId { local_id: def_map.root, krate: from.krate };
137 let crate_attrs = db.attrs(crate_root.into()); 126 let crate_attrs = db.attrs(crate_root.into());
138 let prefer_no_std = crate_attrs.by_key("no_std").exists(); 127 let prefer_no_std = crate_attrs.by_key("no_std").exists();
139 let importable_locations = find_importable_locations(db, item, from);
140 let mut best_path = None; 128 let mut best_path = None;
141 let mut best_path_len = max_len; 129 let mut best_path_len = max_len;
142 for (module_id, name) in importable_locations {
143 let mut path = match db.find_path_inner(
144 ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
145 from,
146 best_path_len - 1,
147 ) {
148 None => continue,
149 Some(path) => path,
150 };
151 path.segments.push(name);
152 130
153 let new_path = if let Some(best_path) = best_path { 131 if item.krate(db) == Some(from.krate) {
154 select_best_path(best_path, path, prefer_no_std) 132 // Item was defined in the same crate that wants to import it. It cannot be found in any
155 } else { 133 // dependency in this case.
156 path 134
157 }; 135 let local_imports = find_local_import_locations(db, item, from);
158 best_path_len = new_path.len(); 136 for (module_id, name) in local_imports {
159 best_path = Some(new_path); 137 if let Some(mut path) = find_path_inner(
138 db,
139 ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
140 from,
141 best_path_len - 1,
142 ) {
143 path.segments.push(name);
144
145 let new_path = if let Some(best_path) = best_path {
146 select_best_path(best_path, path, prefer_no_std)
147 } else {
148 path
149 };
150 best_path_len = new_path.len();
151 best_path = Some(new_path);
152 }
153 }
154 } else {
155 // Item was defined in some upstream crate. This means that it must be exported from one,
156 // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
157 // that wants to import it here, but we always prefer to use the external path here.
158
159 let crate_graph = db.crate_graph();
160 let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| {
161 let import_map = db.import_map(dep.crate_id);
162 import_map.path_of(item).map(|modpath| {
163 let mut modpath = modpath.clone();
164 modpath.segments.insert(0, dep.as_name());
165 modpath
166 })
167 });
168
169 for path in extern_paths {
170 let new_path = if let Some(best_path) = best_path {
171 select_best_path(best_path, path, prefer_no_std)
172 } else {
173 path
174 };
175 best_path = Some(new_path);
176 }
160 } 177 }
178
161 best_path 179 best_path
162} 180}
163 181
@@ -185,69 +203,86 @@ fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -
185 } 203 }
186} 204}
187 205
188fn find_importable_locations( 206/// Finds locations in `from.krate` from which `item` can be imported by `from`.
207fn find_local_import_locations(
189 db: &dyn DefDatabase, 208 db: &dyn DefDatabase,
190 item: ItemInNs, 209 item: ItemInNs,
191 from: ModuleId, 210 from: ModuleId,
192) -> Vec<(ModuleId, Name)> { 211) -> Vec<(ModuleId, Name)> {
193 let crate_graph = db.crate_graph(); 212 let _p = profile("find_local_import_locations");
194 let mut result = Vec::new(); 213
195 // We only look in the crate from which we are importing, and the direct 214 // `from` can import anything below `from` with visibility of at least `from`, and anything
196 // dependencies. We cannot refer to names from transitive dependencies 215 // above `from` with any visibility. That means we do not need to descend into private siblings
197 // directly (only through reexports in direct dependencies). 216 // of `from` (and similar).
198 for krate in Some(from.krate) 217
199 .into_iter() 218 let def_map = db.crate_def_map(from.krate);
200 .chain(crate_graph[from.krate].dependencies.iter().map(|dep| dep.crate_id)) 219
201 { 220 // Compute the initial worklist. We start with all direct child modules of `from` as well as all
202 result.extend( 221 // of its (recursive) parent modules.
203 db.importable_locations_of(item, krate) 222 let data = &def_map.modules[from.local_id];
204 .iter() 223 let mut worklist = data
205 .filter(|(_, _, vis)| vis.is_visible_from(db, from)) 224 .children
206 .map(|(m, n, _)| (*m, n.clone())), 225 .values()
207 ); 226 .map(|child| ModuleId { krate: from.krate, local_id: *child })
208 } 227 .collect::<Vec<_>>();
209 result 228 let mut parent = data.parent;
210} 229 while let Some(p) = parent {
230 worklist.push(ModuleId { krate: from.krate, local_id: p });
231 parent = def_map.modules[p].parent;
232 }
233
234 let mut seen: FxHashSet<_> = FxHashSet::default();
235
236 let mut locations = Vec::new();
237 while let Some(module) = worklist.pop() {
238 if !seen.insert(module) {
239 continue; // already processed this module
240 }
241
242 let ext_def_map;
243 let data = if module.krate == from.krate {
244 &def_map[module.local_id]
245 } else {
246 // The crate might reexport a module defined in another crate.
247 ext_def_map = db.crate_def_map(module.krate);
248 &ext_def_map[module.local_id]
249 };
211 250
212/// Collects all locations from which we might import the item in a particular
213/// crate. These include the original definition of the item, and any
214/// non-private `use`s.
215///
216/// Note that the crate doesn't need to be the one in which the item is defined;
217/// it might be re-exported in other crates.
218pub(crate) fn importable_locations_of_query(
219 db: &dyn DefDatabase,
220 item: ItemInNs,
221 krate: CrateId,
222) -> Arc<[(ModuleId, Name, Visibility)]> {
223 let _p = profile("importable_locations_of_query");
224 let def_map = db.crate_def_map(krate);
225 let mut result = Vec::new();
226 for (local_id, data) in def_map.modules.iter() {
227 if let Some((name, vis)) = data.scope.name_of(item) { 251 if let Some((name, vis)) = data.scope.name_of(item) {
228 let is_private = if let Visibility::Module(private_to) = vis { 252 if vis.is_visible_from(db, from) {
229 private_to.local_id == local_id 253 let is_private = if let Visibility::Module(private_to) = vis {
230 } else { 254 private_to.local_id == module.local_id
231 false 255 } else {
232 }; 256 false
233 let is_original_def = if let Some(module_def_id) = item.as_module_def_id() { 257 };
234 data.scope.declarations().any(|it| it == module_def_id) 258 let is_original_def = if let Some(module_def_id) = item.as_module_def_id() {
235 } else { 259 data.scope.declarations().any(|it| it == module_def_id)
236 false 260 } else {
237 }; 261 false
238 if is_private && !is_original_def { 262 };
263
239 // Ignore private imports. these could be used if we are 264 // Ignore private imports. these could be used if we are
240 // in a submodule of this module, but that's usually not 265 // in a submodule of this module, but that's usually not
241 // what the user wants; and if this module can import 266 // what the user wants; and if this module can import
242 // the item and we're a submodule of it, so can we. 267 // the item and we're a submodule of it, so can we.
243 // Also this keeps the cached data smaller. 268 // Also this keeps the cached data smaller.
244 continue; 269 if !is_private || is_original_def {
270 locations.push((module, name.clone()));
271 }
272 }
273 }
274
275 // Descend into all modules visible from `from`.
276 for (_, per_ns) in data.scope.entries() {
277 if let Some((ModuleDefId::ModuleId(module), vis)) = per_ns.take_types_vis() {
278 if vis.is_visible_from(db, from) {
279 worklist.push(module);
280 }
245 } 281 }
246 result.push((ModuleId { krate, local_id }, name.clone(), vis));
247 } 282 }
248 } 283 }
249 284
250 Arc::from(result) 285 locations
251} 286}
252 287
253#[cfg(test)] 288#[cfg(test)]
@@ -385,6 +420,7 @@ mod tests {
385 420
386 #[test] 421 #[test]
387 fn different_crate_renamed() { 422 fn different_crate_renamed() {
423 // Even if a local path exists, if the item is defined externally, prefer an external path.
388 let code = r#" 424 let code = r#"
389 //- /main.rs crate:main deps:std 425 //- /main.rs crate:main deps:std
390 extern crate std as std_renamed; 426 extern crate std as std_renamed;
@@ -392,7 +428,7 @@ mod tests {
392 //- /std.rs crate:std 428 //- /std.rs crate:std
393 pub struct S; 429 pub struct S;
394 "#; 430 "#;
395 check_found_path(code, "std_renamed::S"); 431 check_found_path(code, "std::S");
396 } 432 }
397 433
398 #[test] 434 #[test]
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs
new file mode 100644
index 000000000..4284a0a91
--- /dev/null
+++ b/crates/ra_hir_def/src/import_map.rs
@@ -0,0 +1,331 @@
1//! A map of all publicly exported items in a crate.
2
3use std::{collections::hash_map::Entry, fmt, sync::Arc};
4
5use ra_db::CrateId;
6use rustc_hash::FxHashMap;
7
8use crate::{
9 db::DefDatabase,
10 item_scope::ItemInNs,
11 path::{ModPath, PathKind},
12 visibility::Visibility,
13 ModuleDefId, ModuleId,
14};
15
16/// A map from publicly exported items to the path needed to import/name them from a downstream
17/// crate.
18///
19/// Reexports of items are taken into account, ie. if something is exported under multiple
20/// names, the one with the shortest import path will be used.
21///
22/// Note that all paths are relative to the containing crate's root, so the crate name still needs
23/// to be prepended to the `ModPath` before the path is valid.
24#[derive(Eq, PartialEq)]
25pub struct ImportMap {
26 map: FxHashMap<ItemInNs, ModPath>,
27}
28
29impl ImportMap {
30 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
31 let _p = ra_prof::profile("import_map_query");
32 let def_map = db.crate_def_map(krate);
33 let mut import_map = FxHashMap::with_capacity_and_hasher(64, Default::default());
34
35 // We look only into modules that are public(ly reexported), starting with the crate root.
36 let empty = ModPath { kind: PathKind::Plain, segments: vec![] };
37 let root = ModuleId { krate, local_id: def_map.root };
38 let mut worklist = vec![(root, empty)];
39 while let Some((module, mod_path)) = worklist.pop() {
40 let ext_def_map;
41 let mod_data = if module.krate == krate {
42 &def_map[module.local_id]
43 } else {
44 // The crate might reexport a module defined in another crate.
45 ext_def_map = db.crate_def_map(module.krate);
46 &ext_def_map[module.local_id]
47 };
48
49 let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| {
50 let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public);
51 if per_ns.is_none() {
52 None
53 } else {
54 Some((name, per_ns))
55 }
56 });
57
58 for (name, per_ns) in visible_items {
59 let mk_path = || {
60 let mut path = mod_path.clone();
61 path.segments.push(name.clone());
62 path
63 };
64
65 for item in per_ns.iter_items() {
66 let path = mk_path();
67 match import_map.entry(item) {
68 Entry::Vacant(entry) => {
69 entry.insert(path);
70 }
71 Entry::Occupied(mut entry) => {
72 // If the new path is shorter, prefer that one.
73 if path.len() < entry.get().len() {
74 *entry.get_mut() = path;
75 } else {
76 continue;
77 }
78 }
79 }
80
81 // If we've just added a path to a module, descend into it. We might traverse
82 // modules multiple times, but only if the new path to it is shorter than the
83 // first (else we `continue` above).
84 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
85 worklist.push((mod_id, mk_path()));
86 }
87 }
88 }
89 }
90
91 Arc::new(Self { map: import_map })
92 }
93
94 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
95 pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> {
96 self.map.get(&item)
97 }
98}
99
100impl fmt::Debug for ImportMap {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 let mut importable_paths: Vec<_> = self
103 .map
104 .iter()
105 .map(|(item, modpath)| {
106 let ns = match item {
107 ItemInNs::Types(_) => "t",
108 ItemInNs::Values(_) => "v",
109 ItemInNs::Macros(_) => "m",
110 };
111 format!("- {} ({})", modpath, ns)
112 })
113 .collect();
114
115 importable_paths.sort();
116 f.write_str(&importable_paths.join("\n"))
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crate::test_db::TestDB;
124 use insta::assert_snapshot;
125 use ra_db::fixture::WithFixture;
126 use ra_db::SourceDatabase;
127
128 fn import_map(ra_fixture: &str) -> String {
129 let db = TestDB::with_files(ra_fixture);
130 let crate_graph = db.crate_graph();
131
132 let import_maps: Vec<_> = crate_graph
133 .iter()
134 .filter_map(|krate| {
135 let cdata = &crate_graph[krate];
136 let name = cdata.display_name.as_ref()?;
137
138 let map = db.import_map(krate);
139
140 Some(format!("{}:\n{:?}", name, map))
141 })
142 .collect();
143
144 import_maps.join("\n")
145 }
146
147 #[test]
148 fn smoke() {
149 let map = import_map(
150 r"
151 //- /main.rs crate:main deps:lib
152
153 mod private {
154 pub use lib::Pub;
155 pub struct InPrivateModule;
156 }
157
158 pub mod publ1 {
159 use lib::Pub;
160 }
161
162 pub mod real_pub {
163 pub use lib::Pub;
164 }
165 pub mod real_pu2 { // same path length as above
166 pub use lib::Pub;
167 }
168
169 //- /lib.rs crate:lib
170 pub struct Pub {}
171 pub struct Pub2; // t + v
172 struct Priv;
173 ",
174 );
175
176 assert_snapshot!(map, @r###"
177 main:
178 - publ1 (t)
179 - real_pu2 (t)
180 - real_pub (t)
181 - real_pub::Pub (t)
182 lib:
183 - Pub (t)
184 - Pub2 (t)
185 - Pub2 (v)
186 "###);
187 }
188
189 #[test]
190 fn prefers_shortest_path() {
191 let map = import_map(
192 r"
193 //- /main.rs crate:main
194
195 pub mod sub {
196 pub mod subsub {
197 pub struct Def {}
198 }
199
200 pub use super::sub::subsub::Def;
201 }
202 ",
203 );
204
205 assert_snapshot!(map, @r###"
206 main:
207 - sub (t)
208 - sub::Def (t)
209 - sub::subsub (t)
210 "###);
211 }
212
213 #[test]
214 fn type_reexport_cross_crate() {
215 // Reexports need to be visible from a crate, even if the original crate exports the item
216 // at a shorter path.
217 let map = import_map(
218 r"
219 //- /main.rs crate:main deps:lib
220 pub mod m {
221 pub use lib::S;
222 }
223 //- /lib.rs crate:lib
224 pub struct S;
225 ",
226 );
227
228 assert_snapshot!(map, @r###"
229 main:
230 - m (t)
231 - m::S (t)
232 - m::S (v)
233 lib:
234 - S (t)
235 - S (v)
236 "###);
237 }
238
239 #[test]
240 fn macro_reexport() {
241 let map = import_map(
242 r"
243 //- /main.rs crate:main deps:lib
244 pub mod m {
245 pub use lib::pub_macro;
246 }
247 //- /lib.rs crate:lib
248 #[macro_export]
249 macro_rules! pub_macro {
250 () => {};
251 }
252 ",
253 );
254
255 assert_snapshot!(map, @r###"
256 main:
257 - m (t)
258 - m::pub_macro (m)
259 lib:
260 - pub_macro (m)
261 "###);
262 }
263
264 #[test]
265 fn module_reexport() {
266 // Reexporting modules from a dependency adds all contents to the import map.
267 let map = import_map(
268 r"
269 //- /main.rs crate:main deps:lib
270 pub use lib::module as reexported_module;
271 //- /lib.rs crate:lib
272 pub mod module {
273 pub struct S;
274 }
275 ",
276 );
277
278 assert_snapshot!(map, @r###"
279 main:
280 - reexported_module (t)
281 - reexported_module::S (t)
282 - reexported_module::S (v)
283 lib:
284 - module (t)
285 - module::S (t)
286 - module::S (v)
287 "###);
288 }
289
290 #[test]
291 fn cyclic_module_reexport() {
292 // A cyclic reexport does not hang.
293 let map = import_map(
294 r"
295 //- /lib.rs crate:lib
296 pub mod module {
297 pub struct S;
298 pub use super::sub::*;
299 }
300
301 pub mod sub {
302 pub use super::module;
303 }
304 ",
305 );
306
307 assert_snapshot!(map, @r###"
308 lib:
309 - module (t)
310 - module::S (t)
311 - module::S (v)
312 - sub (t)
313 "###);
314 }
315
316 #[test]
317 fn private_macro() {
318 let map = import_map(
319 r"
320 //- /lib.rs crate:lib
321 macro_rules! private_macro {
322 () => {};
323 }
324 ",
325 );
326
327 assert_snapshot!(map, @r###"
328 lib:
329 "###);
330 }
331}
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index fc15948ad..b03ba939a 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -3,11 +3,12 @@
3 3
4use hir_expand::name::Name; 4use hir_expand::name::Name;
5use once_cell::sync::Lazy; 5use once_cell::sync::Lazy;
6use ra_db::CrateId;
6use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
7 8
8use crate::{ 9use crate::{
9 per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId, 10 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId,
10 TraitId, 11 Lookup, MacroDefId, ModuleDefId, TraitId,
11}; 12};
12 13
13#[derive(Debug, Default, PartialEq, Eq)] 14#[derive(Debug, Default, PartialEq, Eq)]
@@ -203,4 +204,22 @@ impl ItemInNs {
203 ItemInNs::Macros(_) => None, 204 ItemInNs::Macros(_) => None,
204 } 205 }
205 } 206 }
207
208 /// Returns the crate defining this item (or `None` if `self` is built-in).
209 pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
210 Some(match self {
211 ItemInNs::Types(did) | ItemInNs::Values(did) => match did {
212 ModuleDefId::ModuleId(id) => id.krate,
213 ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate,
214 ModuleDefId::AdtId(id) => id.module(db).krate,
215 ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate,
216 ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate,
217 ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate,
218 ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate,
219 ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate,
220 ModuleDefId::BuiltinType(_) => return None,
221 },
222 ItemInNs::Macros(id) => return id.krate,
223 })
224 }
206} 225}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 5325a2760..de490fcc5 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -43,6 +43,7 @@ pub mod child_by_source;
43 43
44pub mod visibility; 44pub mod visibility;
45pub mod find_path; 45pub mod find_path;
46pub mod import_map;
46 47
47#[cfg(test)] 48#[cfg(test)]
48mod test_db; 49mod test_db;
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 4512448e0..bfa921de2 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -76,6 +76,19 @@ impl ModPath {
76 } 76 }
77 } 77 }
78 78
79 /// Returns the number of segments in the path (counting special segments like `$crate` and
80 /// `super`).
81 pub fn len(&self) -> usize {
82 self.segments.len()
83 + match self.kind {
84 PathKind::Plain => 0,
85 PathKind::Super(i) => i as usize,
86 PathKind::Crate => 1,
87 PathKind::Abs => 0,
88 PathKind::DollarCrate(_) => 1,
89 }
90 }
91
79 pub fn is_ident(&self) -> bool { 92 pub fn is_ident(&self) -> bool {
80 self.kind == PathKind::Plain && self.segments.len() == 1 93 self.kind == PathKind::Plain && self.segments.len() == 1
81 } 94 }
diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs
index 6e435c8c1..74665c588 100644
--- a/crates/ra_hir_def/src/per_ns.rs
+++ b/crates/ra_hir_def/src/per_ns.rs
@@ -5,7 +5,7 @@
5 5
6use hir_expand::MacroDefId; 6use hir_expand::MacroDefId;
7 7
8use crate::{visibility::Visibility, ModuleDefId}; 8use crate::{item_scope::ItemInNs, visibility::Visibility, ModuleDefId};
9 9
10#[derive(Debug, Copy, Clone, PartialEq, Eq)] 10#[derive(Debug, Copy, Clone, PartialEq, Eq)]
11pub struct PerNs { 11pub struct PerNs {
@@ -84,4 +84,12 @@ impl PerNs {
84 macros: self.macros.or(other.macros), 84 macros: self.macros.or(other.macros),
85 } 85 }
86 } 86 }
87
88 pub fn iter_items(self) -> impl Iterator<Item = ItemInNs> {
89 self.types
90 .map(|it| ItemInNs::Types(it.0))
91 .into_iter()
92 .chain(self.values.map(|it| ItemInNs::Values(it.0)).into_iter())
93 .chain(self.macros.map(|it| ItemInNs::Macros(it.0)).into_iter())
94 }
87} 95}
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs
index e7a5182f0..bcfa66ac9 100644
--- a/crates/ra_hir_def/src/test_db.rs
+++ b/crates/ra_hir_def/src/test_db.rs
@@ -6,9 +6,7 @@ use std::{
6}; 6};
7 7
8use hir_expand::db::AstDatabase; 8use hir_expand::db::AstDatabase;
9use ra_db::{ 9use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
10 salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath, Upcast,
11};
12 10
13use crate::db::DefDatabase; 11use crate::db::DefDatabase;
14 12
@@ -64,14 +62,6 @@ impl FileLoader for TestDB {
64 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { 62 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
65 FileLoaderDelegate(self).relevant_crates(file_id) 63 FileLoaderDelegate(self).relevant_crates(file_id)
66 } 64 }
67
68 fn resolve_extern_path(
69 &self,
70 extern_id: ExternSourceId,
71 relative_path: &RelativePath,
72 ) -> Option<FileId> {
73 FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path)
74 }
75} 65}
76 66
77impl TestDB { 67impl TestDB {
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index eec5fb8eb..7579546d2 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -295,19 +295,13 @@ fn concat_expand(
295 295
296fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { 296fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> {
297 let call_site = call_id.as_file().original_file(db); 297 let call_site = call_id.as_file().original_file(db);
298 298 let res = db.resolve_path(call_site, path)?;
299 // Handle trivial case 299 // Prevent include itself
300 if let Some(res) = db.resolve_path(call_site, path) { 300 if res == call_site {
301 // Prevent include itself 301 None
302 return if res == call_site { None } else { Some(res) }; 302 } else {
303 Some(res)
303 } 304 }
304
305 // Extern paths ?
306 let krate = *db.relevant_crates(call_site).get(0)?;
307 let (extern_source_id, relative_file) =
308 db.crate_graph()[krate].extern_source.extern_path(path)?;
309
310 db.resolve_extern_path(extern_source_id, &relative_file)
311} 305}
312 306
313fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> { 307fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> {
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs
index 765a2f6d1..fdf225f55 100644
--- a/crates/ra_hir_expand/src/test_db.rs
+++ b/crates/ra_hir_expand/src/test_db.rs
@@ -5,7 +5,7 @@ use std::{
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use ra_db::{salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; 8use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate};
9 9
10#[salsa::database( 10#[salsa::database(
11 ra_db::SourceDatabaseExtStorage, 11 ra_db::SourceDatabaseExtStorage,
@@ -47,11 +47,4 @@ impl FileLoader for TestDB {
47 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { 47 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
48 FileLoaderDelegate(self).relevant_crates(file_id) 48 FileLoaderDelegate(self).relevant_crates(file_id)
49 } 49 }
50 fn resolve_extern_path(
51 &self,
52 anchor: ExternSourceId,
53 relative_path: &RelativePath,
54 ) -> Option<FileId> {
55 FileLoaderDelegate(self).resolve_extern_path(anchor, relative_path)
56 }
57} 50}
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 0a8bb24ac..bf71d38d6 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -3,8 +3,8 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{ 5use hir_def::{
6 db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalFieldId, TraitId, TypeParamId, 6 db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TraitId,
7 VariantId, 7 TypeParamId, VariantId,
8}; 8};
9use ra_arena::map::ArenaMap; 9use ra_arena::map::ArenaMap;
10use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; 10use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
@@ -13,8 +13,8 @@ use ra_prof::profile;
13use crate::{ 13use crate::{
14 method_resolution::{CrateImplDefs, TyFingerprint}, 14 method_resolution::{CrateImplDefs, TyFingerprint},
15 traits::{chalk, AssocTyValue, Impl}, 15 traits::{chalk, AssocTyValue, Impl},
16 Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty, 16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
17 TyDefId, TypeCtor, ValueTyDefId, 17 ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
18}; 18};
19use hir_expand::name::Name; 19use hir_expand::name::Name;
20 20
@@ -48,6 +48,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
48 #[salsa::invoke(crate::callable_item_sig)] 48 #[salsa::invoke(crate::callable_item_sig)]
49 fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig; 49 fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig;
50 50
51 #[salsa::invoke(crate::lower::return_type_impl_traits)]
52 fn return_type_impl_traits(
53 &self,
54 def: FunctionId,
55 ) -> Option<Arc<Binders<ReturnTypeImplTraits>>>;
56
51 #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] 57 #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
52 #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] 58 #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
53 fn generic_predicates_for_param( 59 fn generic_predicates_for_param(
@@ -80,6 +86,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
80 #[salsa::interned] 86 #[salsa::interned]
81 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; 87 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
82 #[salsa::interned] 88 #[salsa::interned]
89 fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId;
90 #[salsa::interned]
83 fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; 91 fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId;
84 #[salsa::interned] 92 #[salsa::interned]
85 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId; 93 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId;
@@ -142,3 +150,7 @@ fn hir_database_is_object_safe() {
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 150#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
143pub struct GlobalTypeParamId(salsa::InternId); 151pub struct GlobalTypeParamId(salsa::InternId);
144impl_intern_key!(GlobalTypeParamId); 152impl_intern_key!(GlobalTypeParamId);
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
155pub struct InternedOpaqueTyId(salsa::InternId);
156impl_intern_key!(InternedOpaqueTyId);
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index b9c4d2e89..3c97e1354 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -4,7 +4,7 @@ use std::fmt;
4 4
5use crate::{ 5use crate::{
6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, 6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate,
7 Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 7 Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
8}; 8};
9use hir_def::{ 9use hir_def::{
10 find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId, 10 find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId,
@@ -359,6 +359,21 @@ impl HirDisplay for ApplicationTy {
359 write!(f, ">")?; 359 write!(f, ">")?;
360 } 360 }
361 } 361 }
362 TypeCtor::OpaqueType(opaque_ty_id) => {
363 let bounds = match opaque_ty_id {
364 OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
365 let datas =
366 f.db.return_type_impl_traits(func).expect("impl trait id without data");
367 let data = (*datas)
368 .as_ref()
369 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
370 data.clone().subst(&self.parameters)
371 }
372 };
373 write!(f, "impl ")?;
374 write_bounds_like_dyn_trait(&bounds.value, f)?;
375 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
376 }
362 TypeCtor::Closure { .. } => { 377 TypeCtor::Closure { .. } => {
363 let sig = self.parameters[0].callable_sig(f.db); 378 let sig = self.parameters[0].callable_sig(f.db);
364 if let Some(sig) = sig { 379 if let Some(sig) = sig {
@@ -427,14 +442,24 @@ impl HirDisplay for Ty {
427 } 442 }
428 } 443 }
429 Ty::Bound(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?, 444 Ty::Bound(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
430 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 445 Ty::Dyn(predicates) => {
431 match self { 446 write!(f, "dyn ")?;
432 Ty::Dyn(_) => write!(f, "dyn ")?,
433 Ty::Opaque(_) => write!(f, "impl ")?,
434 _ => unreachable!(),
435 };
436 write_bounds_like_dyn_trait(predicates, f)?; 447 write_bounds_like_dyn_trait(predicates, f)?;
437 } 448 }
449 Ty::Opaque(opaque_ty) => {
450 let bounds = match opaque_ty.opaque_ty_id {
451 OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
452 let datas =
453 f.db.return_type_impl_traits(func).expect("impl trait id without data");
454 let data = (*datas)
455 .as_ref()
456 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
457 data.clone().subst(&opaque_ty.parameters)
458 }
459 };
460 write!(f, "impl ")?;
461 write_bounds_like_dyn_trait(&bounds.value, f)?;
462 }
438 Ty::Unknown => write!(f, "{{unknown}}")?, 463 Ty::Unknown => write!(f, "{{unknown}}")?,
439 Ty::Infer(..) => write!(f, "_")?, 464 Ty::Infer(..) => write!(f, "_")?,
440 } 465 }
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index dc77e88e5..d9bf3c2f0 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -39,8 +39,8 @@ use ra_syntax::SmolStr;
39use super::{ 39use super::{
40 primitive::{FloatTy, IntTy}, 40 primitive::{FloatTy, IntTy},
41 traits::{Guidance, Obligation, ProjectionPredicate, Solution}, 41 traits::{Guidance, Obligation, ProjectionPredicate, Solution},
42 ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment, 42 ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
43 TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, 43 TypeWalk, Uncertain,
44}; 44};
45use crate::{ 45use crate::{
46 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, 46 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
@@ -383,25 +383,6 @@ impl<'a> InferenceContext<'a> {
383 ) -> Ty { 383 ) -> Ty {
384 match assoc_ty { 384 match assoc_ty {
385 Some(res_assoc_ty) => { 385 Some(res_assoc_ty) => {
386 // FIXME:
387 // Check if inner_ty is is `impl Trait` and contained input TypeAlias id
388 // this is a workaround while Chalk assoc type projection doesn't always work yet,
389 // but once that is fixed I don't think we should keep this
390 // (we'll probably change how associated types are resolved anyway)
391 if let Ty::Opaque(ref predicates) = inner_ty {
392 for p in predicates.iter() {
393 if let GenericPredicate::Projection(projection) = p {
394 if projection.projection_ty.associated_ty == res_assoc_ty {
395 if let ty_app!(_, params) = &projection.ty {
396 if params.len() == 0 {
397 return projection.ty.clone();
398 }
399 }
400 }
401 }
402 }
403 }
404
405 let ty = self.table.new_type_var(); 386 let ty = self.table.new_type_var();
406 let builder = Substs::build_for_def(self.db, res_assoc_ty) 387 let builder = Substs::build_for_def(self.db, res_assoc_ty)
407 .push(inner_ty) 388 .push(inner_ty)
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 9fa8d3bdc..135976fcd 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -147,6 +147,12 @@ pub enum TypeCtor {
147 /// an **application type** like `(Iterator::Item)<T>`. 147 /// an **application type** like `(Iterator::Item)<T>`.
148 AssociatedType(TypeAliasId), 148 AssociatedType(TypeAliasId),
149 149
150 /// This represents a placeholder for an opaque type in situations where we
151 /// don't know the hidden type (i.e. currently almost always). This is
152 /// analogous to the `AssociatedType` type constructor. As with that one,
153 /// these are only produced by Chalk.
154 OpaqueType(OpaqueTyId),
155
150 /// The type of a specific closure. 156 /// The type of a specific closure.
151 /// 157 ///
152 /// The closure signature is stored in a `FnPtr` type in the first type 158 /// The closure signature is stored in a `FnPtr` type in the first type
@@ -194,6 +200,14 @@ impl TypeCtor {
194 let generic_params = generics(db.upcast(), type_alias.into()); 200 let generic_params = generics(db.upcast(), type_alias.into());
195 generic_params.len() 201 generic_params.len()
196 } 202 }
203 TypeCtor::OpaqueType(opaque_ty_id) => {
204 match opaque_ty_id {
205 OpaqueTyId::ReturnTypeImplTrait(func, _) => {
206 let generic_params = generics(db.upcast(), func.into());
207 generic_params.len()
208 }
209 }
210 }
197 TypeCtor::FnPtr { num_args } => num_args as usize + 1, 211 TypeCtor::FnPtr { num_args } => num_args as usize + 1,
198 TypeCtor::Tuple { cardinality } => cardinality as usize, 212 TypeCtor::Tuple { cardinality } => cardinality as usize,
199 } 213 }
@@ -220,6 +234,11 @@ impl TypeCtor {
220 TypeCtor::AssociatedType(type_alias) => { 234 TypeCtor::AssociatedType(type_alias) => {
221 Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate) 235 Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate)
222 } 236 }
237 TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id {
238 OpaqueTyId::ReturnTypeImplTrait(func, _) => {
239 Some(func.lookup(db.upcast()).module(db.upcast()).krate)
240 }
241 },
223 } 242 }
224 } 243 }
225 244
@@ -241,6 +260,7 @@ impl TypeCtor {
241 TypeCtor::Adt(adt) => Some(adt.into()), 260 TypeCtor::Adt(adt) => Some(adt.into()),
242 TypeCtor::FnDef(callable) => Some(callable.into()), 261 TypeCtor::FnDef(callable) => Some(callable.into()),
243 TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()), 262 TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()),
263 TypeCtor::OpaqueType(_impl_trait_id) => None,
244 } 264 }
245 } 265 }
246} 266}
@@ -254,6 +274,12 @@ pub struct ApplicationTy {
254 pub parameters: Substs, 274 pub parameters: Substs,
255} 275}
256 276
277#[derive(Clone, PartialEq, Eq, Debug, Hash)]
278pub struct OpaqueTy {
279 pub opaque_ty_id: OpaqueTyId,
280 pub parameters: Substs,
281}
282
257/// A "projection" type corresponds to an (unnormalized) 283/// A "projection" type corresponds to an (unnormalized)
258/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the 284/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
259/// trait and all its parameters are fully known. 285/// trait and all its parameters are fully known.
@@ -308,6 +334,12 @@ pub enum Ty {
308 /// trait and all its parameters are fully known. 334 /// trait and all its parameters are fully known.
309 Projection(ProjectionTy), 335 Projection(ProjectionTy),
310 336
337 /// An opaque type (`impl Trait`).
338 ///
339 /// This is currently only used for return type impl trait; each instance of
340 /// `impl Trait` in a return type gets its own ID.
341 Opaque(OpaqueTy),
342
311 /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T) 343 /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
312 /// {}` when we're type-checking the body of that function. In this 344 /// {}` when we're type-checking the body of that function. In this
313 /// situation, we know this stands for *some* type, but don't know the exact 345 /// situation, we know this stands for *some* type, but don't know the exact
@@ -332,12 +364,6 @@ pub enum Ty {
332 /// didn't seem worth the overhead yet. 364 /// didn't seem worth the overhead yet.
333 Dyn(Arc<[GenericPredicate]>), 365 Dyn(Arc<[GenericPredicate]>),
334 366
335 /// An opaque type (`impl Trait`).
336 ///
337 /// The predicates are quantified over the `Self` type; see `Ty::Dyn` for
338 /// more.
339 Opaque(Arc<[GenericPredicate]>),
340
341 /// A placeholder for a type which could not be computed; this is propagated 367 /// A placeholder for a type which could not be computed; this is propagated
342 /// to avoid useless error messages. Doubles as a placeholder where type 368 /// to avoid useless error messages. Doubles as a placeholder where type
343 /// variables are inserted before type checking, since we want to try to 369 /// variables are inserted before type checking, since we want to try to
@@ -490,7 +516,7 @@ impl Deref for Substs {
490 } 516 }
491} 517}
492 518
493#[derive(Copy, Clone, PartialEq, Eq, Debug)] 519#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
494pub struct Binders<T> { 520pub struct Binders<T> {
495 pub num_binders: usize, 521 pub num_binders: usize,
496 pub value: T, 522 pub value: T,
@@ -534,6 +560,20 @@ impl<T: TypeWalk> Binders<T> {
534 } 560 }
535} 561}
536 562
563impl<T: TypeWalk> TypeWalk for Binders<T> {
564 fn walk(&self, f: &mut impl FnMut(&Ty)) {
565 self.value.walk(f);
566 }
567
568 fn walk_mut_binders(
569 &mut self,
570 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
571 binders: DebruijnIndex,
572 ) {
573 self.value.walk_mut_binders(f, binders.shifted_in())
574 }
575}
576
537/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. 577/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
538/// Name to be bikeshedded: TraitBound? TraitImplements? 578/// Name to be bikeshedded: TraitBound? TraitImplements?
539#[derive(Clone, PartialEq, Eq, Debug, Hash)] 579#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -947,11 +987,16 @@ impl TypeWalk for Ty {
947 t.walk(f); 987 t.walk(f);
948 } 988 }
949 } 989 }
950 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 990 Ty::Dyn(predicates) => {
951 for p in predicates.iter() { 991 for p in predicates.iter() {
952 p.walk(f); 992 p.walk(f);
953 } 993 }
954 } 994 }
995 Ty::Opaque(o_ty) => {
996 for t in o_ty.parameters.iter() {
997 t.walk(f);
998 }
999 }
955 Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} 1000 Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
956 } 1001 }
957 f(self); 1002 f(self);
@@ -969,13 +1014,48 @@ impl TypeWalk for Ty {
969 Ty::Projection(p_ty) => { 1014 Ty::Projection(p_ty) => {
970 p_ty.parameters.walk_mut_binders(f, binders); 1015 p_ty.parameters.walk_mut_binders(f, binders);
971 } 1016 }
972 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 1017 Ty::Dyn(predicates) => {
973 for p in make_mut_slice(predicates) { 1018 for p in make_mut_slice(predicates) {
974 p.walk_mut_binders(f, binders.shifted_in()); 1019 p.walk_mut_binders(f, binders.shifted_in());
975 } 1020 }
976 } 1021 }
1022 Ty::Opaque(o_ty) => {
1023 o_ty.parameters.walk_mut_binders(f, binders);
1024 }
977 Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} 1025 Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
978 } 1026 }
979 f(self, binders); 1027 f(self, binders);
980 } 1028 }
981} 1029}
1030
1031impl<T: TypeWalk> TypeWalk for Vec<T> {
1032 fn walk(&self, f: &mut impl FnMut(&Ty)) {
1033 for t in self {
1034 t.walk(f);
1035 }
1036 }
1037 fn walk_mut_binders(
1038 &mut self,
1039 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
1040 binders: DebruijnIndex,
1041 ) {
1042 for t in self {
1043 t.walk_mut_binders(f, binders);
1044 }
1045 }
1046}
1047
1048#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
1049pub enum OpaqueTyId {
1050 ReturnTypeImplTrait(hir_def::FunctionId, u16),
1051}
1052
1053#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1054pub struct ReturnTypeImplTraits {
1055 pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
1056}
1057
1058#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1059pub(crate) struct ReturnTypeImplTrait {
1060 pub(crate) bounds: Binders<Vec<GenericPredicate>>,
1061}
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 35ac86a46..a05cbd7fc 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -21,8 +21,10 @@ use hir_def::{
21 HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, 21 HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
22 UnionId, VariantId, 22 UnionId, VariantId,
23}; 23};
24use hir_expand::name::Name;
24use ra_arena::map::ArenaMap; 25use ra_arena::map::ArenaMap;
25use ra_db::CrateId; 26use ra_db::CrateId;
27use test_utils::mark;
26 28
27use crate::{ 29use crate::{
28 db::HirDatabase, 30 db::HirDatabase,
@@ -31,10 +33,10 @@ use crate::{
31 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, 33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
32 make_mut_slice, variant_data, 34 make_mut_slice, variant_data,
33 }, 35 },
34 Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, 36 Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, OpaqueTy, OpaqueTyId, PolyFnSig,
35 ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, 37 ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, ReturnTypeImplTraits, Substs,
38 TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
36}; 39};
37use hir_expand::name::Name;
38 40
39#[derive(Debug)] 41#[derive(Debug)]
40pub struct TyLoweringContext<'a> { 42pub struct TyLoweringContext<'a> {
@@ -47,7 +49,16 @@ pub struct TyLoweringContext<'a> {
47 /// possible currently, so this should be fine for now. 49 /// possible currently, so this should be fine for now.
48 pub type_param_mode: TypeParamLoweringMode, 50 pub type_param_mode: TypeParamLoweringMode,
49 pub impl_trait_mode: ImplTraitLoweringMode, 51 pub impl_trait_mode: ImplTraitLoweringMode,
50 pub impl_trait_counter: std::cell::Cell<u16>, 52 impl_trait_counter: std::cell::Cell<u16>,
53 /// When turning `impl Trait` into opaque types, we have to collect the
54 /// bounds at the same time to get the IDs correct (without becoming too
55 /// complicated). I don't like using interior mutability (as for the
56 /// counter), but I've tried and failed to make the lifetimes work for
57 /// passing around a `&mut TyLoweringContext`. The core problem is that
58 /// we're grouping the mutable data (the counter and this field) together
59 /// with the immutable context (the references to the DB and resolver).
60 /// Splitting this up would be a possible fix.
61 opaque_type_data: std::cell::RefCell<Vec<ReturnTypeImplTrait>>,
51} 62}
52 63
53impl<'a> TyLoweringContext<'a> { 64impl<'a> TyLoweringContext<'a> {
@@ -56,26 +67,42 @@ impl<'a> TyLoweringContext<'a> {
56 let impl_trait_mode = ImplTraitLoweringMode::Disallowed; 67 let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
57 let type_param_mode = TypeParamLoweringMode::Placeholder; 68 let type_param_mode = TypeParamLoweringMode::Placeholder;
58 let in_binders = DebruijnIndex::INNERMOST; 69 let in_binders = DebruijnIndex::INNERMOST;
59 Self { db, resolver, in_binders, impl_trait_mode, impl_trait_counter, type_param_mode } 70 let opaque_type_data = std::cell::RefCell::new(Vec::new());
71 Self {
72 db,
73 resolver,
74 in_binders,
75 impl_trait_mode,
76 impl_trait_counter,
77 type_param_mode,
78 opaque_type_data,
79 }
60 } 80 }
61 81
62 pub fn with_shifted_in<T>( 82 pub fn with_debruijn<T>(
63 &self, 83 &self,
64 debruijn: DebruijnIndex, 84 debruijn: DebruijnIndex,
65 f: impl FnOnce(&TyLoweringContext) -> T, 85 f: impl FnOnce(&TyLoweringContext) -> T,
66 ) -> T { 86 ) -> T {
87 let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
67 let new_ctx = Self { 88 let new_ctx = Self {
68 in_binders: self.in_binders.shifted_in_from(debruijn), 89 in_binders: debruijn,
69 impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), 90 impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()),
91 opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec),
70 ..*self 92 ..*self
71 }; 93 };
72 let result = f(&new_ctx); 94 let result = f(&new_ctx);
73 self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); 95 self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
96 self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
74 result 97 result
75 } 98 }
76 99
77 pub fn shifted_in(self, debruijn: DebruijnIndex) -> Self { 100 pub fn with_shifted_in<T>(
78 Self { in_binders: self.in_binders.shifted_in_from(debruijn), ..self } 101 &self,
102 debruijn: DebruijnIndex,
103 f: impl FnOnce(&TyLoweringContext) -> T,
104 ) -> T {
105 self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f)
79 } 106 }
80 107
81 pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { 108 pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
@@ -167,20 +194,44 @@ impl Ty {
167 TypeRef::ImplTrait(bounds) => { 194 TypeRef::ImplTrait(bounds) => {
168 match ctx.impl_trait_mode { 195 match ctx.impl_trait_mode {
169 ImplTraitLoweringMode::Opaque => { 196 ImplTraitLoweringMode::Opaque => {
170 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); 197 let idx = ctx.impl_trait_counter.get();
171 let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { 198 ctx.impl_trait_counter.set(idx + 1);
172 bounds 199
173 .iter() 200 assert!(idx as usize == ctx.opaque_type_data.borrow().len());
174 .flat_map(|b| { 201 // this dance is to make sure the data is in the right
175 GenericPredicate::from_type_bound(ctx, b, self_ty.clone()) 202 // place even if we encounter more opaque types while
176 }) 203 // lowering the bounds
177 .collect() 204 ctx.opaque_type_data
178 }); 205 .borrow_mut()
179 Ty::Opaque(predicates) 206 .push(ReturnTypeImplTrait { bounds: Binders::new(1, Vec::new()) });
207 // We don't want to lower the bounds inside the binders
208 // we're currently in, because they don't end up inside
209 // those binders. E.g. when we have `impl Trait<impl
210 // OtherTrait<T>>`, the `impl OtherTrait<T>` can't refer
211 // to the self parameter from `impl Trait`, and the
212 // bounds aren't actually stored nested within each
213 // other, but separately. So if the `T` refers to a type
214 // parameter of the outer function, it's just one binder
215 // away instead of two.
216 let actual_opaque_type_data = ctx
217 .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
218 ReturnTypeImplTrait::from_hir(ctx, &bounds)
219 });
220 ctx.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
221
222 let func = match ctx.resolver.generic_def() {
223 Some(GenericDefId::FunctionId(f)) => f,
224 _ => panic!("opaque impl trait lowering in non-function"),
225 };
226 let impl_trait_id = OpaqueTyId::ReturnTypeImplTrait(func, idx);
227 let generics = generics(ctx.db.upcast(), func.into());
228 let parameters = Substs::bound_vars(&generics, ctx.in_binders);
229 Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters })
180 } 230 }
181 ImplTraitLoweringMode::Param => { 231 ImplTraitLoweringMode::Param => {
182 let idx = ctx.impl_trait_counter.get(); 232 let idx = ctx.impl_trait_counter.get();
183 ctx.impl_trait_counter.set(idx + 1); 233 // FIXME we're probably doing something wrong here
234 ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
184 if let Some(def) = ctx.resolver.generic_def() { 235 if let Some(def) = ctx.resolver.generic_def() {
185 let generics = generics(ctx.db.upcast(), def); 236 let generics = generics(ctx.db.upcast(), def);
186 let param = generics 237 let param = generics
@@ -197,7 +248,8 @@ impl Ty {
197 } 248 }
198 ImplTraitLoweringMode::Variable => { 249 ImplTraitLoweringMode::Variable => {
199 let idx = ctx.impl_trait_counter.get(); 250 let idx = ctx.impl_trait_counter.get();
200 ctx.impl_trait_counter.set(idx + 1); 251 // FIXME we're probably doing something wrong here
252 ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
201 let (parent_params, self_params, list_params, _impl_trait_params) = 253 let (parent_params, self_params, list_params, _impl_trait_params) =
202 if let Some(def) = ctx.resolver.generic_def() { 254 if let Some(def) = ctx.resolver.generic_def() {
203 let generics = generics(ctx.db.upcast(), def); 255 let generics = generics(ctx.db.upcast(), def);
@@ -663,6 +715,30 @@ fn assoc_type_bindings_from_type_bound<'a>(
663 }) 715 })
664} 716}
665 717
718impl ReturnTypeImplTrait {
719 fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self {
720 mark::hit!(lower_rpit);
721 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
722 let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| {
723 bounds
724 .iter()
725 .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone()))
726 .collect()
727 });
728 ReturnTypeImplTrait { bounds: Binders::new(1, predicates) }
729 }
730}
731
732fn count_impl_traits(type_ref: &TypeRef) -> usize {
733 let mut count = 0;
734 type_ref.walk(&mut |type_ref| {
735 if matches!(type_ref, TypeRef::ImplTrait(_)) {
736 count += 1;
737 }
738 });
739 count
740}
741
666/// Build the signature of a callable item (function, struct or enum variant). 742/// Build the signature of a callable item (function, struct or enum variant).
667pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { 743pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig {
668 match def { 744 match def {
@@ -864,7 +940,9 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
864 .with_impl_trait_mode(ImplTraitLoweringMode::Variable) 940 .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
865 .with_type_param_mode(TypeParamLoweringMode::Variable); 941 .with_type_param_mode(TypeParamLoweringMode::Variable);
866 let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::<Vec<_>>(); 942 let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::<Vec<_>>();
867 let ctx_ret = ctx_params.with_impl_trait_mode(ImplTraitLoweringMode::Opaque); 943 let ctx_ret = TyLoweringContext::new(db, &resolver)
944 .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
945 .with_type_param_mode(TypeParamLoweringMode::Variable);
868 let ret = Ty::from_hir(&ctx_ret, &data.ret_type); 946 let ret = Ty::from_hir(&ctx_ret, &data.ret_type);
869 let generics = generics(db.upcast(), def.into()); 947 let generics = generics(db.upcast(), def.into());
870 let num_binders = generics.len(); 948 let num_binders = generics.len();
@@ -1084,3 +1162,25 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
1084 TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value))?, 1162 TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value))?,
1085 )) 1163 ))
1086} 1164}
1165
1166pub(crate) fn return_type_impl_traits(
1167 db: &impl HirDatabase,
1168 def: hir_def::FunctionId,
1169) -> Option<Arc<Binders<ReturnTypeImplTraits>>> {
1170 // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
1171 let data = db.function_data(def);
1172 let resolver = def.resolver(db.upcast());
1173 let ctx_ret = TyLoweringContext::new(db, &resolver)
1174 .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
1175 .with_type_param_mode(TypeParamLoweringMode::Variable);
1176 let _ret = Ty::from_hir(&ctx_ret, &data.ret_type);
1177 let generics = generics(db.upcast(), def.into());
1178 let num_binders = generics.len();
1179 let return_type_impl_traits =
1180 ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() };
1181 if return_type_impl_traits.impl_traits.is_empty() {
1182 None
1183 } else {
1184 Some(Arc::new(Binders::new(num_binders, return_type_impl_traits)))
1185 }
1186}
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index 21a3bdfd1..e484968a0 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -7,9 +7,7 @@ use std::{
7 7
8use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; 8use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId};
9use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; 9use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink};
10use ra_db::{ 10use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
11 salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase, Upcast,
12};
13use stdx::format_to; 11use stdx::format_to;
14 12
15use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; 13use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator};
@@ -78,13 +76,6 @@ impl FileLoader for TestDB {
78 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { 76 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
79 FileLoaderDelegate(self).relevant_crates(file_id) 77 FileLoaderDelegate(self).relevant_crates(file_id)
80 } 78 }
81 fn resolve_extern_path(
82 &self,
83 extern_id: ra_db::ExternSourceId,
84 relative_path: &RelativePath,
85 ) -> Option<FileId> {
86 FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path)
87 }
88} 79}
89 80
90impl TestDB { 81impl TestDB {
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index e8778d419..0c538a62d 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1110,7 +1110,6 @@ fn test() {
1110} 1110}
1111 1111
1112#[test] 1112#[test]
1113#[ignore]
1114fn impl_trait() { 1113fn impl_trait() {
1115 assert_snapshot!( 1114 assert_snapshot!(
1116 infer(r#" 1115 infer(r#"
@@ -1161,6 +1160,95 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
1161} 1160}
1162 1161
1163#[test] 1162#[test]
1163fn simple_return_pos_impl_trait() {
1164 mark::check!(lower_rpit);
1165 assert_snapshot!(
1166 infer(r#"
1167trait Trait<T> {
1168 fn foo(&self) -> T;
1169}
1170fn bar() -> impl Trait<u64> { loop {} }
1171
1172fn test() {
1173 let a = bar();
1174 a.foo();
1175}
1176"#),
1177 @r###"
1178 30..34 'self': &Self
1179 72..83 '{ loop {} }': !
1180 74..81 'loop {}': !
1181 79..81 '{}': ()
1182 95..130 '{ ...o(); }': ()
1183 105..106 'a': impl Trait<u64>
1184 109..112 'bar': fn bar() -> impl Trait<u64>
1185 109..114 'bar()': impl Trait<u64>
1186 120..121 'a': impl Trait<u64>
1187 120..127 'a.foo()': u64
1188 "###
1189 );
1190}
1191
1192#[test]
1193fn more_return_pos_impl_trait() {
1194 assert_snapshot!(
1195 infer(r#"
1196trait Iterator {
1197 type Item;
1198 fn next(&mut self) -> Self::Item;
1199}
1200trait Trait<T> {
1201 fn foo(&self) -> T;
1202}
1203fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} }
1204fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} }
1205
1206fn test() {
1207 let (a, b) = bar();
1208 a.next().foo();
1209 b.foo();
1210 let (c, d) = baz(1u128);
1211 c.next().foo();
1212 d.foo();
1213}
1214"#),
1215 @r###"
1216 50..54 'self': &mut Self
1217 102..106 'self': &Self
1218 185..196 '{ loop {} }': ({unknown}, {unknown})
1219 187..194 'loop {}': !
1220 192..194 '{}': ()
1221 207..208 't': T
1222 269..280 '{ loop {} }': ({unknown}, {unknown})
1223 271..278 'loop {}': !
1224 276..278 '{}': ()
1225 292..414 '{ ...o(); }': ()
1226 302..308 '(a, b)': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
1227 303..304 'a': impl Iterator<Item = impl Trait<u32>>
1228 306..307 'b': impl Trait<u64>
1229 311..314 'bar': fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
1230 311..316 'bar()': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
1231 322..323 'a': impl Iterator<Item = impl Trait<u32>>
1232 322..330 'a.next()': impl Trait<u32>
1233 322..336 'a.next().foo()': u32
1234 342..343 'b': impl Trait<u64>
1235 342..349 'b.foo()': u64
1236 359..365 '(c, d)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
1237 360..361 'c': impl Iterator<Item = impl Trait<u128>>
1238 363..364 'd': impl Trait<u128>
1239 368..371 'baz': fn baz<u128>(u128) -> (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
1240 368..378 'baz(1u128)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
1241 372..377 '1u128': u128
1242 384..385 'c': impl Iterator<Item = impl Trait<u128>>
1243 384..392 'c.next()': impl Trait<u128>
1244 384..398 'c.next().foo()': u128
1245 404..405 'd': impl Trait<u128>
1246 404..411 'd.foo()': u128
1247 "###
1248 );
1249}
1250
1251#[test]
1164fn dyn_trait() { 1252fn dyn_trait() {
1165 assert_snapshot!( 1253 assert_snapshot!(
1166 infer(r#" 1254 infer(r#"
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 61de3cc30..a72a82f5a 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -4,7 +4,7 @@ use std::sync::Arc;
4use log::debug; 4use log::debug;
5 5
6use chalk_ir::{fold::shift::Shift, GenericArg, TypeName}; 6use chalk_ir::{fold::shift::Shift, GenericArg, TypeName};
7use chalk_solve::rust_ir::{self, WellKnownTrait}; 7use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
8 8
9use hir_def::{ 9use hir_def::{
10 lang_item::{lang_attr, LangItemTarget}, 10 lang_item::{lang_attr, LangItemTarget},
@@ -100,6 +100,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
100 fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> { 100 fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> {
101 self.db.associated_ty_value(self.krate, id) 101 self.db.associated_ty_value(self.krate, id)
102 } 102 }
103
103 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<Interner>> { 104 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<Interner>> {
104 vec![] 105 vec![]
105 } 106 }
@@ -130,11 +131,34 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
130 self.db.program_clauses_for_chalk_env(self.krate, environment.clone()) 131 self.db.program_clauses_for_chalk_env(self.krate, environment.clone())
131 } 132 }
132 133
133 fn opaque_ty_data( 134 fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> {
134 &self, 135 let interned_id = crate::db::InternedOpaqueTyId::from(id);
135 _id: chalk_ir::OpaqueTyId<Interner>, 136 let full_id = self.db.lookup_intern_impl_trait_id(interned_id);
136 ) -> Arc<rust_ir::OpaqueTyDatum<Interner>> { 137 let (func, idx) = match full_id {
137 unimplemented!() 138 crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx),
139 };
140 let datas =
141 self.db.return_type_impl_traits(func).expect("impl trait id without impl traits");
142 let data = &datas.value.impl_traits[idx as usize];
143 let bound = OpaqueTyDatumBound {
144 bounds: make_binders(
145 data.bounds
146 .value
147 .iter()
148 .cloned()
149 .filter(|b| !b.is_error())
150 .map(|b| b.to_chalk(self.db))
151 .collect(),
152 1,
153 ),
154 };
155 let num_vars = datas.num_binders;
156 Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) })
157 }
158
159 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
160 // FIXME: actually provide the hidden type; it is relevant for auto traits
161 Ty::Unknown.to_chalk(self.db)
138 } 162 }
139 163
140 fn force_impl_for( 164 fn force_impl_for(
@@ -150,10 +174,6 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
150 // FIXME: implement actual object safety 174 // FIXME: implement actual object safety
151 true 175 true
152 } 176 }
153
154 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
155 Ty::Unknown.to_chalk(self.db)
156 }
157} 177}
158 178
159pub(crate) fn program_clauses_for_chalk_env_query( 179pub(crate) fn program_clauses_for_chalk_env_query(
@@ -460,6 +480,18 @@ impl From<crate::traits::GlobalImplId> for ImplId {
460 } 480 }
461} 481}
462 482
483impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
484 fn from(id: OpaqueTyId) -> Self {
485 InternKey::from_intern_id(id.0)
486 }
487}
488
489impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId {
490 fn from(id: crate::db::InternedOpaqueTyId) -> Self {
491 chalk_ir::OpaqueTyId(id.as_intern_id())
492 }
493}
494
463impl From<rust_ir::AssociatedTyValueId<Interner>> for crate::traits::AssocTyValueId { 495impl From<rust_ir::AssociatedTyValueId<Interner>> for crate::traits::AssocTyValueId {
464 fn from(id: rust_ir::AssociatedTyValueId<Interner>) -> Self { 496 fn from(id: rust_ir::AssociatedTyValueId<Interner>) -> Self {
465 Self::from_intern_id(id.0) 497 Self::from_intern_id(id.0)
diff --git a/crates/ra_hir_ty/src/traits/chalk/interner.rs b/crates/ra_hir_ty/src/traits/chalk/interner.rs
index e27074ba6..56aab640c 100644
--- a/crates/ra_hir_ty/src/traits/chalk/interner.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/interner.rs
@@ -22,6 +22,8 @@ pub type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interne
22pub type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>; 22pub type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>;
23pub type FnDefId = chalk_ir::FnDefId<Interner>; 23pub type FnDefId = chalk_ir::FnDefId<Interner>;
24pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>; 24pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>;
25pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
26pub type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
25 27
26impl chalk_ir::interner::Interner for Interner { 28impl chalk_ir::interner::Interner for Interner {
27 type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc? 29 type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc?
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
index 9150f65d4..28a5fbe3e 100644
--- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
@@ -16,8 +16,8 @@ use crate::{
16 db::HirDatabase, 16 db::HirDatabase,
17 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, 17 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
18 traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, 18 traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
19 ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, 19 ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId,
20 Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, 20 ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
21}; 21};
22 22
23use super::interner::*; 23use super::interner::*;
@@ -68,7 +68,16 @@ impl ToChalk for Ty {
68 let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) }; 68 let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) };
69 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) 69 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner)
70 } 70 }
71 Ty::Opaque(_) | Ty::Unknown => { 71 Ty::Opaque(opaque_ty) => {
72 let opaque_ty_id = opaque_ty.opaque_ty_id.to_chalk(db);
73 let substitution = opaque_ty.parameters.to_chalk(db);
74 chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
75 opaque_ty_id,
76 substitution,
77 }))
78 .intern(&Interner)
79 }
80 Ty::Unknown => {
72 let substitution = chalk_ir::Substitution::empty(&Interner); 81 let substitution = chalk_ir::Substitution::empty(&Interner);
73 let name = TypeName::Error; 82 let name = TypeName::Error;
74 chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) 83 chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
@@ -98,7 +107,11 @@ impl ToChalk for Ty {
98 let parameters = from_chalk(db, proj.substitution); 107 let parameters = from_chalk(db, proj.substitution);
99 Ty::Projection(ProjectionTy { associated_ty, parameters }) 108 Ty::Projection(ProjectionTy { associated_ty, parameters })
100 } 109 }
101 chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(), 110 chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => {
111 let impl_trait_id = from_chalk(db, opaque_ty.opaque_ty_id);
112 let parameters = from_chalk(db, opaque_ty.substitution);
113 Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters })
114 }
102 chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => { 115 chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => {
103 let parameters: Substs = from_chalk(db, substitution); 116 let parameters: Substs = from_chalk(db, substitution);
104 Ty::Apply(ApplicationTy { 117 Ty::Apply(ApplicationTy {
@@ -204,6 +217,21 @@ impl ToChalk for hir_def::TraitId {
204 } 217 }
205} 218}
206 219
220impl ToChalk for OpaqueTyId {
221 type Chalk = chalk_ir::OpaqueTyId<Interner>;
222
223 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::OpaqueTyId<Interner> {
224 db.intern_impl_trait_id(self).into()
225 }
226
227 fn from_chalk(
228 db: &dyn HirDatabase,
229 opaque_ty_id: chalk_ir::OpaqueTyId<Interner>,
230 ) -> OpaqueTyId {
231 db.lookup_intern_impl_trait_id(opaque_ty_id.into())
232 }
233}
234
207impl ToChalk for TypeCtor { 235impl ToChalk for TypeCtor {
208 type Chalk = TypeName<Interner>; 236 type Chalk = TypeName<Interner>;
209 237
@@ -214,6 +242,11 @@ impl ToChalk for TypeCtor {
214 TypeName::AssociatedType(type_id) 242 TypeName::AssociatedType(type_id)
215 } 243 }
216 244
245 TypeCtor::OpaqueType(impl_trait_id) => {
246 let id = impl_trait_id.to_chalk(db);
247 TypeName::OpaqueType(id)
248 }
249
217 TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), 250 TypeCtor::Bool => TypeName::Scalar(Scalar::Bool),
218 TypeCtor::Char => TypeName::Scalar(Scalar::Char), 251 TypeCtor::Char => TypeName::Scalar(Scalar::Char),
219 TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)), 252 TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)),
@@ -252,7 +285,9 @@ impl ToChalk for TypeCtor {
252 match type_name { 285 match type_name {
253 TypeName::Adt(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), 286 TypeName::Adt(struct_id) => db.lookup_intern_type_ctor(struct_id.into()),
254 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), 287 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
255 TypeName::OpaqueType(_) => unreachable!(), 288 TypeName::OpaqueType(opaque_type_id) => {
289 TypeCtor::OpaqueType(from_chalk(db, opaque_type_id))
290 }
256 291
257 TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, 292 TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool,
258 TypeName::Scalar(Scalar::Char) => TypeCtor::Char, 293 TypeName::Scalar(Scalar::Char) => TypeCtor::Char,
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs
index d88828c7c..556af7098 100644
--- a/crates/ra_hir_ty/src/traits/chalk/tls.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs
@@ -69,6 +69,11 @@ impl DebugContext<'_> {
69 let name = self.0.type_alias_data(type_alias).name.clone(); 69 let name = self.0.type_alias_data(type_alias).name.clone();
70 write!(f, "{}::{}", trait_name, name)?; 70 write!(f, "{}::{}", trait_name, name)?;
71 } 71 }
72 TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id {
73 crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
74 write!(f, "{{impl trait {} of {:?}}}", idx, func)?;
75 }
76 },
72 TypeCtor::Closure { def, expr } => { 77 TypeCtor::Closure { def, expr } => {
73 write!(f, "{{closure {:?} in ", expr.into_raw())?; 78 write!(f, "{{closure {:?} in ", expr.into_raw())?;
74 match def { 79 match def {
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 9636cd0d6..62df07459 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -13,14 +13,43 @@ use ra_ide_db::{
13use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; 13use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset};
14 14
15use crate::{ 15use crate::{
16 display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, 16 display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav},
17 FilePosition, RangeInfo, 17 FilePosition, NavigationTarget, RangeInfo,
18}; 18};
19 19
20#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct HoverConfig {
22 pub implementations: bool,
23}
24
25impl Default for HoverConfig {
26 fn default() -> Self {
27 Self { implementations: true }
28 }
29}
30
31impl HoverConfig {
32 pub const NO_ACTIONS: Self = Self { implementations: false };
33
34 pub fn any(&self) -> bool {
35 self.implementations
36 }
37
38 pub fn none(&self) -> bool {
39 !self.any()
40 }
41}
42
43#[derive(Debug, Clone)]
44pub enum HoverAction {
45 Implementaion(FilePosition),
46}
47
20/// Contains the results when hovering over an item 48/// Contains the results when hovering over an item
21#[derive(Debug, Default)] 49#[derive(Debug, Default)]
22pub struct HoverResult { 50pub struct HoverResult {
23 results: Vec<String>, 51 results: Vec<String>,
52 actions: Vec<HoverAction>,
24} 53}
25 54
26impl HoverResult { 55impl HoverResult {
@@ -48,10 +77,20 @@ impl HoverResult {
48 &self.results 77 &self.results
49 } 78 }
50 79
80 pub fn actions(&self) -> &[HoverAction] {
81 &self.actions
82 }
83
84 pub fn push_action(&mut self, action: HoverAction) {
85 self.actions.push(action);
86 }
87
51 /// Returns the results converted into markup 88 /// Returns the results converted into markup
52 /// for displaying in a UI 89 /// for displaying in a UI
90 ///
91 /// Does not process actions!
53 pub fn to_markup(&self) -> String { 92 pub fn to_markup(&self) -> String {
54 self.results.join("\n\n---\n") 93 self.results.join("\n\n___\n")
55 } 94 }
56} 95}
57 96
@@ -82,6 +121,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
82 res.extend(hover_text_from_name_kind(db, name_kind)); 121 res.extend(hover_text_from_name_kind(db, name_kind));
83 122
84 if !res.is_empty() { 123 if !res.is_empty() {
124 if let Some(action) = show_implementations_action(db, name_kind) {
125 res.push_action(action);
126 }
127
85 return Some(RangeInfo::new(range, res)); 128 return Some(RangeInfo::new(range, res));
86 } 129 }
87 } 130 }
@@ -112,6 +155,26 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
112 Some(RangeInfo::new(range, res)) 155 Some(RangeInfo::new(range, res))
113} 156}
114 157
158fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
159 fn to_action(nav_target: NavigationTarget) -> HoverAction {
160 HoverAction::Implementaion(FilePosition {
161 file_id: nav_target.file_id(),
162 offset: nav_target.range().start(),
163 })
164 }
165
166 match def {
167 Definition::ModuleDef(it) => match it {
168 ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))),
169 ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))),
170 ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))),
171 ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))),
172 _ => None,
173 },
174 _ => None,
175 }
176}
177
115fn hover_text( 178fn hover_text(
116 docs: Option<String>, 179 docs: Option<String>,
117 desc: Option<String>, 180 desc: Option<String>,
@@ -228,6 +291,8 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
228 291
229#[cfg(test)] 292#[cfg(test)]
230mod tests { 293mod tests {
294 use super::*;
295
231 use ra_db::FileLoader; 296 use ra_db::FileLoader;
232 use ra_syntax::TextRange; 297 use ra_syntax::TextRange;
233 298
@@ -241,7 +306,14 @@ mod tests {
241 s.map(trim_markup) 306 s.map(trim_markup)
242 } 307 }
243 308
244 fn check_hover_result(fixture: &str, expected: &[&str]) -> String { 309 fn assert_impl_action(action: &HoverAction, position: u32) {
310 let offset = match action {
311 HoverAction::Implementaion(pos) => pos.offset,
312 };
313 assert_eq!(offset, position.into());
314 }
315
316 fn check_hover_result(fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) {
245 let (analysis, position) = analysis_and_position(fixture); 317 let (analysis, position) = analysis_and_position(fixture);
246 let hover = analysis.hover(position).unwrap().unwrap(); 318 let hover = analysis.hover(position).unwrap().unwrap();
247 let mut results = Vec::from(hover.info.results()); 319 let mut results = Vec::from(hover.info.results());
@@ -256,7 +328,7 @@ mod tests {
256 assert_eq!(hover.info.len(), expected.len()); 328 assert_eq!(hover.info.len(), expected.len());
257 329
258 let content = analysis.db.file_text(position.file_id); 330 let content = analysis.db.file_text(position.file_id);
259 content[hover.range].to_string() 331 (content[hover.range].to_string(), hover.info.actions().to_vec())
260 } 332 }
261 333
262 fn check_hover_no_result(fixture: &str) { 334 fn check_hover_no_result(fixture: &str) {
@@ -746,7 +818,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
746 818
747 #[test] 819 #[test]
748 fn test_hover_through_macro() { 820 fn test_hover_through_macro() {
749 let hover_on = check_hover_result( 821 let (hover_on, _) = check_hover_result(
750 " 822 "
751 //- /lib.rs 823 //- /lib.rs
752 macro_rules! id { 824 macro_rules! id {
@@ -767,7 +839,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
767 839
768 #[test] 840 #[test]
769 fn test_hover_through_expr_in_macro() { 841 fn test_hover_through_expr_in_macro() {
770 let hover_on = check_hover_result( 842 let (hover_on, _) = check_hover_result(
771 " 843 "
772 //- /lib.rs 844 //- /lib.rs
773 macro_rules! id { 845 macro_rules! id {
@@ -785,7 +857,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
785 857
786 #[test] 858 #[test]
787 fn test_hover_through_expr_in_macro_recursive() { 859 fn test_hover_through_expr_in_macro_recursive() {
788 let hover_on = check_hover_result( 860 let (hover_on, _) = check_hover_result(
789 " 861 "
790 //- /lib.rs 862 //- /lib.rs
791 macro_rules! id_deep { 863 macro_rules! id_deep {
@@ -806,7 +878,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
806 878
807 #[test] 879 #[test]
808 fn test_hover_through_func_in_macro_recursive() { 880 fn test_hover_through_func_in_macro_recursive() {
809 let hover_on = check_hover_result( 881 let (hover_on, _) = check_hover_result(
810 " 882 "
811 //- /lib.rs 883 //- /lib.rs
812 macro_rules! id_deep { 884 macro_rules! id_deep {
@@ -830,7 +902,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
830 902
831 #[test] 903 #[test]
832 fn test_hover_through_literal_string_in_macro() { 904 fn test_hover_through_literal_string_in_macro() {
833 let hover_on = check_hover_result( 905 let (hover_on, _) = check_hover_result(
834 r#" 906 r#"
835 //- /lib.rs 907 //- /lib.rs
836 macro_rules! arr { 908 macro_rules! arr {
@@ -849,7 +921,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
849 921
850 #[test] 922 #[test]
851 fn test_hover_through_assert_macro() { 923 fn test_hover_through_assert_macro() {
852 let hover_on = check_hover_result( 924 let (hover_on, _) = check_hover_result(
853 r#" 925 r#"
854 //- /lib.rs 926 //- /lib.rs
855 #[rustc_builtin_macro] 927 #[rustc_builtin_macro]
@@ -925,13 +997,14 @@ fn func(foo: i32) { if true { <|>foo; }; }
925 997
926 #[test] 998 #[test]
927 fn test_hover_trait_show_qualifiers() { 999 fn test_hover_trait_show_qualifiers() {
928 check_hover_result( 1000 let (_, actions) = check_hover_result(
929 " 1001 "
930 //- /lib.rs 1002 //- /lib.rs
931 unsafe trait foo<|>() {} 1003 unsafe trait foo<|>() {}
932 ", 1004 ",
933 &["unsafe trait foo"], 1005 &["unsafe trait foo"],
934 ); 1006 );
1007 assert_impl_action(&actions[0], 13);
935 } 1008 }
936 1009
937 #[test] 1010 #[test]
@@ -1052,4 +1125,55 @@ fn func(foo: i32) { if true { <|>foo; }; }
1052 &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], 1125 &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"],
1053 ); 1126 );
1054 } 1127 }
1128
1129 #[test]
1130 fn test_hover_trait_has_impl_action() {
1131 let (_, actions) = check_hover_result(
1132 "
1133 //- /lib.rs
1134 trait foo<|>() {}
1135 ",
1136 &["trait foo"],
1137 );
1138 assert_impl_action(&actions[0], 6);
1139 }
1140
1141 #[test]
1142 fn test_hover_struct_has_impl_action() {
1143 let (_, actions) = check_hover_result(
1144 "
1145 //- /lib.rs
1146 struct foo<|>() {}
1147 ",
1148 &["struct foo"],
1149 );
1150 assert_impl_action(&actions[0], 7);
1151 }
1152
1153 #[test]
1154 fn test_hover_union_has_impl_action() {
1155 let (_, actions) = check_hover_result(
1156 "
1157 //- /lib.rs
1158 union foo<|>() {}
1159 ",
1160 &["union foo"],
1161 );
1162 assert_impl_action(&actions[0], 6);
1163 }
1164
1165 #[test]
1166 fn test_hover_enum_has_impl_action() {
1167 let (_, actions) = check_hover_result(
1168 "
1169 //- /lib.rs
1170 enum foo<|>() {
1171 A,
1172 B
1173 }
1174 ",
1175 &["enum foo"],
1176 );
1177 assert_impl_action(&actions[0], 5);
1178 }
1055} 1179}
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 34c2d75fe..a56718d3f 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -66,7 +66,7 @@ pub use crate::{
66 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, 66 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode},
67 expand_macro::ExpandedMacro, 67 expand_macro::ExpandedMacro,
68 folding_ranges::{Fold, FoldKind}, 68 folding_ranges::{Fold, FoldKind},
69 hover::HoverResult, 69 hover::{HoverAction, HoverConfig, HoverResult},
70 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 70 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
71 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, 71 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
72 runnables::{Runnable, RunnableKind, TestId}, 72 runnables::{Runnable, RunnableKind, TestId},
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index 8446ef88e..5dbe1c1b7 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -334,6 +334,7 @@ impl RootDatabase {
334 hir::db::CrateLangItemsQuery 334 hir::db::CrateLangItemsQuery
335 hir::db::LangItemQuery 335 hir::db::LangItemQuery
336 hir::db::DocumentationQuery 336 hir::db::DocumentationQuery
337 hir::db::ImportMapQuery
337 338
338 // InternDatabase 339 // InternDatabase
339 hir::db::InternFunctionQuery 340 hir::db::InternFunctionQuery
@@ -369,6 +370,7 @@ impl RootDatabase {
369 hir::db::ImplDatumQuery 370 hir::db::ImplDatumQuery
370 hir::db::AssociatedTyValueQuery 371 hir::db::AssociatedTyValueQuery
371 hir::db::TraitSolveQuery 372 hir::db::TraitSolveQuery
373 hir::db::ReturnTypeImplTraitsQuery
372 374
373 // SymbolsDatabase 375 // SymbolsDatabase
374 crate::symbol_index::FileSymbolsQuery 376 crate::symbol_index::FileSymbolsQuery
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index 8b06cbfc5..1db60b87f 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -18,7 +18,7 @@ use ra_syntax::{
18use crate::RootDatabase; 18use crate::RootDatabase;
19 19
20// FIXME: a more precise name would probably be `Symbol`? 20// FIXME: a more precise name would probably be `Symbol`?
21#[derive(Debug, PartialEq, Eq)] 21#[derive(Debug, PartialEq, Eq, Copy, Clone)]
22pub enum Definition { 22pub enum Definition {
23 Macro(MacroDef), 23 Macro(MacroDef),
24 Field(Field), 24 Field(Field),
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index 93d5891a0..727d743b5 100644
--- a/crates/ra_ide_db/src/lib.rs
+++ b/crates/ra_ide_db/src/lib.rs
@@ -16,8 +16,8 @@ use std::sync::Arc;
16use hir::db::{AstDatabase, DefDatabase}; 16use hir::db::{AstDatabase, DefDatabase};
17use ra_db::{ 17use ra_db::{
18 salsa::{self, Database, Durability}, 18 salsa::{self, Database, Durability},
19 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, 19 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
20 SourceDatabase, SourceRootId, Upcast, 20 SourceRootId, Upcast,
21}; 21};
22use rustc_hash::FxHashMap; 22use rustc_hash::FxHashMap;
23 23
@@ -63,13 +63,6 @@ impl FileLoader for RootDatabase {
63 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { 63 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
64 FileLoaderDelegate(self).relevant_crates(file_id) 64 FileLoaderDelegate(self).relevant_crates(file_id)
65 } 65 }
66 fn resolve_extern_path(
67 &self,
68 extern_id: ra_db::ExternSourceId,
69 relative_path: &RelativePath,
70 ) -> Option<FileId> {
71 FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path)
72 }
73} 66}
74 67
75impl salsa::Database for RootDatabase { 68impl salsa::Database for RootDatabase {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 23168c3ae..8d6efdbe8 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -11,7 +11,7 @@ use std::{ffi::OsString, path::PathBuf};
11 11
12use lsp_types::ClientCapabilities; 12use lsp_types::ClientCapabilities;
13use ra_flycheck::FlycheckConfig; 13use ra_flycheck::FlycheckConfig;
14use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig}; 14use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig};
15use ra_project_model::{CargoConfig, JsonProject, ProjectManifest}; 15use ra_project_model::{CargoConfig, JsonProject, ProjectManifest};
16use serde::Deserialize; 16use serde::Deserialize;
17 17
@@ -34,6 +34,7 @@ pub struct Config {
34 pub assist: AssistConfig, 34 pub assist: AssistConfig,
35 pub call_info_full: bool, 35 pub call_info_full: bool,
36 pub lens: LensConfig, 36 pub lens: LensConfig,
37 pub hover: HoverConfig,
37 38
38 pub with_sysroot: bool, 39 pub with_sysroot: bool,
39 pub linked_projects: Vec<LinkedProject>, 40 pub linked_projects: Vec<LinkedProject>,
@@ -124,6 +125,7 @@ pub struct ClientCapsConfig {
124 pub work_done_progress: bool, 125 pub work_done_progress: bool,
125 pub code_action_group: bool, 126 pub code_action_group: bool,
126 pub resolve_code_action: bool, 127 pub resolve_code_action: bool,
128 pub hover_actions: bool,
127} 129}
128 130
129impl Default for Config { 131impl Default for Config {
@@ -162,6 +164,7 @@ impl Default for Config {
162 assist: AssistConfig::default(), 164 assist: AssistConfig::default(),
163 call_info_full: true, 165 call_info_full: true,
164 lens: LensConfig::default(), 166 lens: LensConfig::default(),
167 hover: HoverConfig::default(),
165 linked_projects: Vec::new(), 168 linked_projects: Vec::new(),
166 } 169 }
167 } 170 }
@@ -278,6 +281,14 @@ impl Config {
278 } 281 }
279 } 282 }
280 283
284 let mut use_hover_actions = false;
285 set(value, "/hoverActions/enable", &mut use_hover_actions);
286 if use_hover_actions {
287 set(value, "/hoverActions/implementations", &mut self.hover.implementations);
288 } else {
289 self.hover = HoverConfig::NO_ACTIONS;
290 }
291
281 log::info!("Config::update() = {:#?}", self); 292 log::info!("Config::update() = {:#?}", self);
282 293
283 fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> { 294 fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
@@ -331,17 +342,15 @@ impl Config {
331 342
332 self.assist.allow_snippets(false); 343 self.assist.allow_snippets(false);
333 if let Some(experimental) = &caps.experimental { 344 if let Some(experimental) = &caps.experimental {
334 let snippet_text_edit = 345 let get_bool =
335 experimental.get("snippetTextEdit").and_then(|it| it.as_bool()) == Some(true); 346 |index: &str| experimental.get(index).and_then(|it| it.as_bool()) == Some(true);
336 self.assist.allow_snippets(snippet_text_edit);
337 347
338 let code_action_group = 348 let snippet_text_edit = get_bool("snippetTextEdit");
339 experimental.get("codeActionGroup").and_then(|it| it.as_bool()) == Some(true); 349 self.assist.allow_snippets(snippet_text_edit);
340 self.client_caps.code_action_group = code_action_group;
341 350
342 let resolve_code_action = 351 self.client_caps.code_action_group = get_bool("codeActionGroup");
343 experimental.get("resolveCodeAction").and_then(|it| it.as_bool()) == Some(true); 352 self.client_caps.resolve_code_action = get_bool("resolveCodeAction");
344 self.client_caps.resolve_code_action = resolve_code_action; 353 self.client_caps.hover_actions = get_bool("hoverActions");
345 } 354 }
346 } 355 }
347} 356}
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 3b957534d..1371f6cb4 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -260,3 +260,35 @@ pub struct SnippetTextEdit {
260 #[serde(skip_serializing_if = "Option::is_none")] 260 #[serde(skip_serializing_if = "Option::is_none")]
261 pub insert_text_format: Option<lsp_types::InsertTextFormat>, 261 pub insert_text_format: Option<lsp_types::InsertTextFormat>,
262} 262}
263
264pub enum HoverRequest {}
265
266impl Request for HoverRequest {
267 type Params = lsp_types::HoverParams;
268 type Result = Option<Hover>;
269 const METHOD: &'static str = "textDocument/hover";
270}
271
272#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
273pub struct Hover {
274 #[serde(flatten)]
275 pub hover: lsp_types::Hover,
276 #[serde(skip_serializing_if = "Vec::is_empty")]
277 pub actions: Vec<CommandLinkGroup>,
278}
279
280#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
281pub struct CommandLinkGroup {
282 #[serde(skip_serializing_if = "Option::is_none")]
283 pub title: Option<String>,
284 pub commands: Vec<CommandLink>,
285}
286
287// LSP v3.15 Command does not have a `tooltip` field, vscode supports one.
288#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
289pub struct CommandLink {
290 #[serde(flatten)]
291 pub command: lsp_types::Command,
292 #[serde(skip_serializing_if = "Option::is_none")]
293 pub tooltip: Option<String>,
294}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index e60337b8e..752dbf145 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -510,6 +510,7 @@ fn on_request(
510 .on::<lsp_ext::InlayHints>(handlers::handle_inlay_hints)? 510 .on::<lsp_ext::InlayHints>(handlers::handle_inlay_hints)?
511 .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)? 511 .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)?
512 .on::<lsp_ext::ResolveCodeActionRequest>(handlers::handle_resolve_code_action)? 512 .on::<lsp_ext::ResolveCodeActionRequest>(handlers::handle_resolve_code_action)?
513 .on::<lsp_ext::HoverRequest>(handlers::handle_hover)?
513 .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)? 514 .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)?
514 .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)? 515 .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)?
515 .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol)? 516 .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol)?
@@ -521,7 +522,6 @@ fn on_request(
521 .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)? 522 .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)?
522 .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)? 523 .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)?
523 .on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)? 524 .on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)?
524 .on::<lsp_types::request::HoverRequest>(handlers::handle_hover)?
525 .on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)? 525 .on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)?
526 .on::<lsp_types::request::Rename>(handlers::handle_rename)? 526 .on::<lsp_types::request::Rename>(handlers::handle_rename)?
527 .on::<lsp_types::request::References>(handlers::handle_references)? 527 .on::<lsp_types::request::References>(handlers::handle_references)?
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index 6acf80c58..3ff779702 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -12,13 +12,14 @@ use lsp_types::{
12 CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, 12 CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
13 CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, 13 CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
14 CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight, 14 CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight,
15 DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, 15 DocumentSymbol, FoldingRange, FoldingRangeParams, HoverContents, Location, MarkupContent,
16 MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, 16 MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensParams,
17 SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, 17 SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
18 SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, 18 TextDocumentIdentifier, Url, WorkspaceEdit,
19}; 19};
20use ra_ide::{ 20use ra_ide::{
21 FileId, FilePosition, FileRange, Query, RangeInfo, RunnableKind, SearchScope, TextEdit, 21 FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, RunnableKind, SearchScope,
22 TextEdit,
22}; 23};
23use ra_prof::profile; 24use ra_prof::profile;
24use ra_project_model::TargetKind; 25use ra_project_model::TargetKind;
@@ -537,7 +538,7 @@ pub fn handle_signature_help(
537pub fn handle_hover( 538pub fn handle_hover(
538 snap: GlobalStateSnapshot, 539 snap: GlobalStateSnapshot,
539 params: lsp_types::HoverParams, 540 params: lsp_types::HoverParams,
540) -> Result<Option<Hover>> { 541) -> Result<Option<lsp_ext::Hover>> {
541 let _p = profile("handle_hover"); 542 let _p = profile("handle_hover");
542 let position = from_proto::file_position(&snap, params.text_document_position_params)?; 543 let position = from_proto::file_position(&snap, params.text_document_position_params)?;
543 let info = match snap.analysis().hover(position)? { 544 let info = match snap.analysis().hover(position)? {
@@ -546,14 +547,18 @@ pub fn handle_hover(
546 }; 547 };
547 let line_index = snap.analysis.file_line_index(position.file_id)?; 548 let line_index = snap.analysis.file_line_index(position.file_id)?;
548 let range = to_proto::range(&line_index, info.range); 549 let range = to_proto::range(&line_index, info.range);
549 let res = Hover { 550 let hover = lsp_ext::Hover {
550 contents: HoverContents::Markup(MarkupContent { 551 hover: lsp_types::Hover {
551 kind: MarkupKind::Markdown, 552 contents: HoverContents::Markup(MarkupContent {
552 value: crate::markdown::format_docs(&info.info.to_markup()), 553 kind: MarkupKind::Markdown,
553 }), 554 value: crate::markdown::format_docs(&info.info.to_markup()),
554 range: Some(range), 555 }),
556 range: Some(range),
557 },
558 actions: prepare_hover_actions(&snap, info.info.actions()),
555 }; 559 };
556 Ok(Some(res)) 560
561 Ok(Some(hover))
557} 562}
558 563
559pub fn handle_prepare_rename( 564pub fn handle_prepare_rename(
@@ -924,24 +929,13 @@ pub fn handle_code_lens_resolve(
924 _ => vec![], 929 _ => vec![],
925 }; 930 };
926 931
927 let title = if locations.len() == 1 { 932 let title = implementation_title(locations.len());
928 "1 implementation".into() 933 let cmd = show_references_command(
929 } else {
930 format!("{} implementations", locations.len())
931 };
932
933 // We cannot use the 'editor.action.showReferences' command directly
934 // because that command requires vscode types which we convert in the handler
935 // on the client side.
936 let cmd = Command {
937 title, 934 title,
938 command: "rust-analyzer.showReferences".into(), 935 &lens_params.text_document_position_params.text_document.uri,
939 arguments: Some(vec![ 936 code_lens.range.start,
940 to_value(&lens_params.text_document_position_params.text_document.uri).unwrap(), 937 locations,
941 to_value(code_lens.range.start).unwrap(), 938 );
942 to_value(locations).unwrap(),
943 ]),
944 };
945 Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None }) 939 Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None })
946 } 940 }
947 None => Ok(CodeLens { 941 None => Ok(CodeLens {
@@ -1145,3 +1139,78 @@ pub fn handle_semantic_tokens_range(
1145 let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); 1139 let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
1146 Ok(Some(semantic_tokens.into())) 1140 Ok(Some(semantic_tokens.into()))
1147} 1141}
1142
1143fn implementation_title(count: usize) -> String {
1144 if count == 1 {
1145 "1 implementation".into()
1146 } else {
1147 format!("{} implementations", count)
1148 }
1149}
1150
1151fn show_references_command(
1152 title: String,
1153 uri: &lsp_types::Url,
1154 position: lsp_types::Position,
1155 locations: Vec<lsp_types::Location>,
1156) -> Command {
1157 // We cannot use the 'editor.action.showReferences' command directly
1158 // because that command requires vscode types which we convert in the handler
1159 // on the client side.
1160
1161 Command {
1162 title,
1163 command: "rust-analyzer.showReferences".into(),
1164 arguments: Some(vec![
1165 to_value(uri).unwrap(),
1166 to_value(position).unwrap(),
1167 to_value(locations).unwrap(),
1168 ]),
1169 }
1170}
1171
1172fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink {
1173 lsp_ext::CommandLink { tooltip: Some(tooltip), command }
1174}
1175
1176fn show_impl_command_link(
1177 snap: &GlobalStateSnapshot,
1178 position: &FilePosition,
1179) -> Option<lsp_ext::CommandLinkGroup> {
1180 if snap.config.hover.implementations {
1181 if let Some(nav_data) = snap.analysis().goto_implementation(*position).unwrap_or(None) {
1182 let uri = to_proto::url(snap, position.file_id).ok()?;
1183 let line_index = snap.analysis().file_line_index(position.file_id).ok()?;
1184 let position = to_proto::position(&line_index, position.offset);
1185 let locations: Vec<_> = nav_data
1186 .info
1187 .iter()
1188 .filter_map(|it| to_proto::location(snap, it.file_range()).ok())
1189 .collect();
1190 let title = implementation_title(locations.len());
1191 let command = show_references_command(title, &uri, position, locations);
1192
1193 return Some(lsp_ext::CommandLinkGroup {
1194 commands: vec![to_command_link(command, "Go to implementations".into())],
1195 ..Default::default()
1196 });
1197 }
1198 }
1199 None
1200}
1201
1202fn prepare_hover_actions(
1203 snap: &GlobalStateSnapshot,
1204 actions: &[HoverAction],
1205) -> Vec<lsp_ext::CommandLinkGroup> {
1206 if snap.config.hover.none() || !snap.config.client_caps.hover_actions {
1207 return Vec::new();
1208 }
1209
1210 actions
1211 .iter()
1212 .filter_map(|it| match it {
1213 HoverAction::Implementaion(position) => show_impl_command_link(snap, position),
1214 })
1215 .collect()
1216}