Repository: rust-analyzer/rust-analyzer
Pull request #4689 (2020-06-01 15:58:46)

Implement return position impl trait / opaque type support
This is working, but I'm not that happy with how the lowering works. We might need an additional representation between `TypeRef` and `Ty` where names are resolved and `impl Trait` bounds are separated out, but things like inference variables don't exist and `impl Trait` is always represented the same way.

Also note that this doesn't implement correct handling of RPIT *inside* the function (which involves turning the `impl Trait`s into variables and creating obligations for them). That intermediate representation might help there as well.

matklad: >We might need an additional representation between TypeRef and Ty where names are resolved

Makes sense to me. More generally, after we do ItemTree work, it might makes sense to only store resolved things in `StructData` and such. 

Patch:
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 91e0ee6194..2e63cb46e9 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};
 pub use crate::{
     cancellation::Canceled,
     input::{
-        CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource,
-        ExternSourceId, FileId, ProcMacroId, SourceRoot, SourceRootId,
+        CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, ExternSourceId,
+        FileId, ProcMacroId, SourceRoot, SourceRootId,
     },
 };
 pub use relative_path::{RelativePath, RelativePathBuf};
@@ -89,13 +89,14 @@ pub const DEFAULT_LRU_CAP: usize = 128;
 pub trait FileLoader {
     /// Text of the file.
     fn file_text(&self, file_id: FileId) -> Arc<String>;
-    /// Note that we intentionally accept a `&str` and not a `&Path` here. This
-    /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such,
-    /// so the input is guaranteed to be utf-8 string. We might introduce
-    /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we
-    /// get by with a `&str` for the time being.
     fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>;
     fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>;
+
+    fn resolve_extern_path(
+        &self,
+        extern_id: ExternSourceId,
+        relative_path: &RelativePath,
+    ) -> Option<FileId>;
 }
 
 /// Database which stores all significant input facts: source code and project
@@ -153,30 +154,34 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
     fn file_text(&self, file_id: FileId) -> Arc<String> {
         SourceDatabaseExt::file_text(self.0, file_id)
     }
+    /// Note that we intentionally accept a `&str` and not a `&Path` here. This
+    /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such,
+    /// so the input is guaranteed to be utf-8 string. We might introduce
+    /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we
+    /// get by with a `&str` for the time being.
     fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
-        // FIXME: this *somehow* should be platform agnostic...
-        if std::path::Path::new(path).is_absolute() {
-            let krate = *self.relevant_crates(anchor).get(0)?;
-            let (extern_source_id, relative_file) =
-                self.0.crate_graph()[krate].extern_source.extern_path(path)?;
-
-            let source_root = self.0.source_root(SourceRootId(extern_source_id.0));
-            source_root.file_by_relative_path(&relative_file)
-        } else {
-            let rel_path = {
-                let mut rel_path = self.0.file_relative_path(anchor);
-                assert!(rel_path.pop());
-                rel_path.push(path);
-                rel_path.normalize()
-            };
-            let source_root = self.0.file_source_root(anchor);
-            let source_root = self.0.source_root(source_root);
-            source_root.file_by_relative_path(&rel_path)
-        }
+        let rel_path = {
+            let mut rel_path = self.0.file_relative_path(anchor);
+            assert!(rel_path.pop());
+            rel_path.push(path);
+            rel_path.normalize()
+        };
+        let source_root = self.0.file_source_root(anchor);
+        let source_root = self.0.source_root(source_root);
+        source_root.file_by_relative_path(&rel_path)
     }
 
     fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
         let source_root = self.0.file_source_root(file_id);
         self.0.source_root_crates(source_root)
     }
+
+    fn resolve_extern_path(
+        &self,
+        extern_id: ExternSourceId,
+        relative_path: &RelativePath,
+    ) -> Option<FileId> {
+        let source_root = self.0.source_root(SourceRootId(extern_id.0));
+        source_root.file_by_relative_path(&relative_path)
+    }
 }
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 098b665292..693cd40cf3 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -3,11 +3,11 @@
 pub use hir_def::db::{
     AttrsQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQueryQuery,
     CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery,
-    ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery,
-    InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery,
-    InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery,
-    InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery,
-    StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
+    ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternConstQuery,
+    InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, InternImplQuery,
+    InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery,
+    LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, StructDataQuery,
+    TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
 };
 pub use hir_expand::db::{
     AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery,
@@ -18,8 +18,8 @@ pub use hir_ty::db::{
     GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase,
     HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery,
     ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery,
-    InternTypeCtorQuery, InternTypeParamIdQuery, StructDatumQuery, TraitDatumQuery,
-    TraitSolveQuery, TyQuery, ValueTyQuery,
+    InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery,
+    TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery,
 };
 
 #[test]
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 10cc26480f..945a0025e5 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -1,7 +1,7 @@
 //! Defines database & queries for name resolution.
 use std::sync::Arc;
 
-use hir_expand::{db::AstDatabase, HirFileId};
+use hir_expand::{db::AstDatabase, name::Name, HirFileId};
 use ra_db::{salsa, CrateId, SourceDatabase, Upcast};
 use ra_prof::profile;
 use ra_syntax::SmolStr;
@@ -12,10 +12,13 @@ use crate::{
     body::{scope::ExprScopes, Body, BodySourceMap},
     data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData},
     docs::Documentation,
+    find_path,
     generics::GenericParams,
-    import_map::ImportMap,
+    item_scope::ItemInNs,
     lang_item::{LangItemTarget, LangItems},
     nameres::{raw::RawItems, CrateDefMap},
+    path::ModPath,
+    visibility::Visibility,
     AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc,
     GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId,
     TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
@@ -110,8 +113,15 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
     #[salsa::invoke(Documentation::documentation_query)]
     fn documentation(&self, def: AttrDefId) -> Option<Documentation>;
 
-    #[salsa::invoke(ImportMap::import_map_query)]
-    fn import_map(&self, krate: CrateId) -> Arc<ImportMap>;
+    #[salsa::invoke(find_path::importable_locations_of_query)]
+    fn importable_locations_of(
+        &self,
+        item: ItemInNs,
+        krate: CrateId,
+    ) -> Arc<[(ModuleId, Name, Visibility)]>;
+
+    #[salsa::invoke(find_path::find_path_inner_query)]
+    fn find_path_inner(&self, item: ItemInNs, from: ModuleId, max_len: usize) -> Option<ModPath>;
 }
 
 fn 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 a7f59e0287..4db7984730 100644
--- a/crates/ra_hir_def/src/find_path.rs
+++ b/crates/ra_hir_def/src/find_path.rs
@@ -1,8 +1,9 @@
 //! An algorithm to find a path to refer to a certain item.
 
+use std::sync::Arc;
+
 use hir_expand::name::{known, AsName, Name};
 use ra_prof::profile;
-use rustc_hash::FxHashSet;
 use test_utils::mark;
 
 use crate::{
@@ -10,7 +11,7 @@ use crate::{
     item_scope::ItemInNs,
     path::{ModPath, PathKind},
     visibility::Visibility,
-    ModuleDefId, ModuleId,
+    CrateId, ModuleDefId, ModuleId,
 };
 
 // FIXME: handle local items
@@ -19,7 +20,7 @@ use crate::{
 /// *from where* you're referring to the item, hence the `from` parameter.
 pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
     let _p = profile("find_path");
-    find_path_inner(db, item, from, MAX_PATH_LEN)
+    db.find_path_inner(item, from, MAX_PATH_LEN)
 }
 
 const MAX_PATH_LEN: usize = 15;
@@ -35,9 +36,20 @@ impl ModPath {
         let first_segment = self.segments.first();
         first_segment == Some(&known::alloc) || first_segment == Some(&known::core)
     }
+
+    fn len(&self) -> usize {
+        self.segments.len()
+            + match self.kind {
+                PathKind::Plain => 0,
+                PathKind::Super(i) => i as usize,
+                PathKind::Crate => 1,
+                PathKind::Abs => 0,
+                PathKind::DollarCrate(_) => 1,
+            }
+    }
 }
 
-fn find_path_inner(
+pub(crate) fn find_path_inner_query(
     db: &dyn DefDatabase,
     item: ItemInNs,
     from: ModuleId,
@@ -121,61 +133,31 @@ fn find_path_inner(
     }
 
     // - otherwise, look for modules containing (reexporting) it and import it from one of those
-
     let crate_root = ModuleId { local_id: def_map.root, krate: from.krate };
     let crate_attrs = db.attrs(crate_root.into());
     let prefer_no_std = crate_attrs.by_key("no_std").exists();
+    let importable_locations = find_importable_locations(db, item, from);
     let mut best_path = None;
     let mut best_path_len = max_len;
+    for (module_id, name) in importable_locations {
+        let mut path = match db.find_path_inner(
+            ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
+            from,
+            best_path_len - 1,
+        ) {
+            None => continue,
+            Some(path) => path,
+        };
+        path.segments.push(name);
 
-    if item.krate(db) == Some(from.krate) {
-        // Item was defined in the same crate that wants to import it. It cannot be found in any
-        // dependency in this case.
-
-        let local_imports = find_local_import_locations(db, item, from);
-        for (module_id, name) in local_imports {
-            if let Some(mut path) = find_path_inner(
-                db,
-                ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
-                from,
-                best_path_len - 1,
-            ) {
-                path.segments.push(name);
-
-                let new_path = if let Some(best_path) = best_path {
-                    select_best_path(best_path, path, prefer_no_std)
-                } else {
-                    path
-                };
-                best_path_len = new_path.len();
-                best_path = Some(new_path);
-            }
-        }
-    } else {
-        // Item was defined in some upstream crate. This means that it must be exported from one,
-        // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
-        // that wants to import it here, but we always prefer to use the external path here.
-
-        let crate_graph = db.crate_graph();
-        let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| {
-            let import_map = db.import_map(dep.crate_id);
-            import_map.path_of(item).map(|modpath| {
-                let mut modpath = modpath.clone();
-                modpath.segments.insert(0, dep.as_name());
-                modpath
-            })
-        });
-
-        for path in extern_paths {
-            let new_path = if let Some(best_path) = best_path {
-                select_best_path(best_path, path, prefer_no_std)
-            } else {
-                path
-            };
-            best_path = Some(new_path);
-        }
+        let new_path = if let Some(best_path) = best_path {
+            select_best_path(best_path, path, prefer_no_std)
+        } else {
+            path
+        };
+        best_path_len = new_path.len();
+        best_path = Some(new_path);
     }
-
     best_path
 }
 
@@ -203,86 +185,69 @@ fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -
     }
 }
 
-/// Finds locations in `from.krate` from which `item` can be imported by `from`.
-fn find_local_import_locations(
+fn find_importable_locations(
     db: &dyn DefDatabase,
     item: ItemInNs,
     from: ModuleId,
 ) -> Vec<(ModuleId, Name)> {
-    let _p = profile("find_local_import_locations");
-
-    // `from` can import anything below `from` with visibility of at least `from`, and anything
-    // above `from` with any visibility. That means we do not need to descend into private siblings
-    // of `from` (and similar).
-
-    let def_map = db.crate_def_map(from.krate);
-
-    // Compute the initial worklist. We start with all direct child modules of `from` as well as all
-    // of its (recursive) parent modules.
-    let data = &def_map.modules[from.local_id];
-    let mut worklist = data
-        .children
-        .values()
-        .map(|child| ModuleId { krate: from.krate, local_id: *child })
-        .collect::<Vec<_>>();
-    let mut parent = data.parent;
-    while let Some(p) = parent {
-        worklist.push(ModuleId { krate: from.krate, local_id: p });
-        parent = def_map.modules[p].parent;
-    }
-
-    let mut seen: FxHashSet<_> = FxHashSet::default();
-
-    let mut locations = Vec::new();
-    while let Some(module) = worklist.pop() {
-        if !seen.insert(module) {
-            continue; // already processed this module
-        }
-
-        let ext_def_map;
-        let data = if module.krate == from.krate {
-            &def_map[module.local_id]
-        } else {
-            // The crate might reexport a module defined in another crate.
-            ext_def_map = db.crate_def_map(module.krate);
-            &ext_def_map[module.local_id]
-        };
+    let crate_graph = db.crate_graph();
+    let mut result = Vec::new();
+    // We only look in the crate from which we are importing, and the direct
+    // dependencies. We cannot refer to names from transitive dependencies
+    // directly (only through reexports in direct dependencies).
+    for krate in Some(from.krate)
+        .into_iter()
+        .chain(crate_graph[from.krate].dependencies.iter().map(|dep| dep.crate_id))
+    {
+        result.extend(
+            db.importable_locations_of(item, krate)
+                .iter()
+                .filter(|(_, _, vis)| vis.is_visible_from(db, from))
+                .map(|(m, n, _)| (*m, n.clone())),
+        );
+    }
+    result
+}
 
+/// Collects all locations from which we might import the item in a particular
+/// crate. These include the original definition of the item, and any
+/// non-private `use`s.
+///
+/// Note that the crate doesn't need to be the one in which the item is defined;
+/// it might be re-exported in other crates.
+pub(crate) fn importable_locations_of_query(
+    db: &dyn DefDatabase,
+    item: ItemInNs,
+    krate: CrateId,
+) -> Arc<[(ModuleId, Name, Visibility)]> {
+    let _p = profile("importable_locations_of_query");
+    let def_map = db.crate_def_map(krate);
+    let mut result = Vec::new();
+    for (local_id, data) in def_map.modules.iter() {
         if let Some((name, vis)) = data.scope.name_of(item) {
-            if vis.is_visible_from(db, from) {
-                let is_private = if let Visibility::Module(private_to) = vis {
-                    private_to.local_id == module.local_id
-                } else {
-                    false
-                };
-                let is_original_def = if let Some(module_def_id) = item.as_module_def_id() {
-                    data.scope.declarations().any(|it| it == module_def_id)
-                } else {
-                    false
-                };
-
+            let is_private = if let Visibility::Module(private_to) = vis {
+                private_to.local_id == local_id
+            } else {
+                false
+            };
+            let is_original_def = if let Some(module_def_id) = item.as_module_def_id() {
+                data.scope.declarations().any(|it| it == module_def_id)
+            } else {
+                false
+            };
+            if is_private && !is_original_def {
                 // Ignore private imports. these could be used if we are
                 // in a submodule of this module, but that's usually not
                 // what the user wants; and if this module can import
                 // the item and we're a submodule of it, so can we.
                 // Also this keeps the cached data smaller.
-                if !is_private || is_original_def {
-                    locations.push((module, name.clone()));
-                }
-            }
-        }
-
-        // Descend into all modules visible from `from`.
-        for (_, per_ns) in data.scope.entries() {
-            if let Some((ModuleDefId::ModuleId(module), vis)) = per_ns.take_types_vis() {
-                if vis.is_visible_from(db, from) {
-                    worklist.push(module);
-                }
+                continue;
             }
+            result.push((ModuleId { krate, local_id }, name.clone(), vis));
         }
     }
 
-    locations
+    Arc::from(result)
 }
 
 #[cfg(test)]
@@ -420,7 +385,6 @@ mod tests {
 
     #[test]
     fn different_crate_renamed() {
-        // Even if a local path exists, if the item is defined externally, prefer an external path.
         let code = r#"
             //- /main.rs crate:main deps:std
             extern crate std as std_renamed;
@@ -428,7 +392,7 @@ mod tests {
             //- /std.rs crate:std
             pub struct S;
         "#;
-        check_found_path(code, "std::S");
+        check_found_path(code, "std_renamed::S");
     }
 
     #[test]
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs
deleted file mode 100644
index 4284a0a912..0000000000
--- a/crates/ra_hir_def/src/import_map.rs
+++ /dev/null
@@ -1,331 +0,0 @@
-//! A map of all publicly exported items in a crate.
-
-use std::{collections::hash_map::Entry, fmt, sync::Arc};
-
-use ra_db::CrateId;
-use rustc_hash::FxHashMap;
-
-use crate::{
-    db::DefDatabase,
-    item_scope::ItemInNs,
-    path::{ModPath, PathKind},
-    visibility::Visibility,
-    ModuleDefId, ModuleId,
-};
-
-/// A map from publicly exported items to the path needed to import/name them from a downstream
-/// crate.
-///
-/// Reexports of items are taken into account, ie. if something is exported under multiple
-/// names, the one with the shortest import path will be used.
-///
-/// Note that all paths are relative to the containing crate's root, so the crate name still needs
-/// to be prepended to the `ModPath` before the path is valid.
-#[derive(Eq, PartialEq)]
-pub struct ImportMap {
-    map: FxHashMap<ItemInNs, ModPath>,
-}
-
-impl ImportMap {
-    pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
-        let _p = ra_prof::profile("import_map_query");
-        let def_map = db.crate_def_map(krate);
-        let mut import_map = FxHashMap::with_capacity_and_hasher(64, Default::default());
-
-        // We look only into modules that are public(ly reexported), starting with the crate root.
-        let empty = ModPath { kind: PathKind::Plain, segments: vec![] };
-        let root = ModuleId { krate, local_id: def_map.root };
-        let mut worklist = vec![(root, empty)];
-        while let Some((module, mod_path)) = worklist.pop() {
-            let ext_def_map;
-            let mod_data = if module.krate == krate {
-                &def_map[module.local_id]
-            } else {
-                // The crate might reexport a module defined in another crate.
-                ext_def_map = db.crate_def_map(module.krate);
-                &ext_def_map[module.local_id]
-            };
-
-            let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| {
-                let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public);
-                if per_ns.is_none() {
-                    None
-                } else {
-                    Some((name, per_ns))
-                }
-            });
-
-            for (name, per_ns) in visible_items {
-                let mk_path = || {
-                    let mut path = mod_path.clone();
-                    path.segments.push(name.clone());
-                    path
-                };
-
-                for item in per_ns.iter_items() {
-                    let path = mk_path();
-                    match import_map.entry(item) {
-                        Entry::Vacant(entry) => {
-                            entry.insert(path);
-                        }
-                        Entry::Occupied(mut entry) => {
-                            // If the new path is shorter, prefer that one.
-                            if path.len() < entry.get().len() {
-                                *entry.get_mut() = path;
-                            } else {
-                                continue;
-                            }
-                        }
-                    }
-
-                    // If we've just added a path to a module, descend into it. We might traverse
-                    // modules multiple times, but only if the new path to it is shorter than the
-                    // first (else we `continue` above).
-                    if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
-                        worklist.push((mod_id, mk_path()));
-                    }
-                }
-            }
-        }
-
-        Arc::new(Self { map: import_map })
-    }
-
-    /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
-    pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> {
-        self.map.get(&item)
-    }
-}
-
-impl fmt::Debug for ImportMap {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut importable_paths: Vec<_> = self
-            .map
-            .iter()
-            .map(|(item, modpath)| {
-                let ns = match item {
-                    ItemInNs::Types(_) => "t",
-                    ItemInNs::Values(_) => "v",
-                    ItemInNs::Macros(_) => "m",
-                };
-                format!("- {} ({})", modpath, ns)
-            })
-            .collect();
-
-        importable_paths.sort();
-        f.write_str(&importable_paths.join("\n"))
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::test_db::TestDB;
-    use insta::assert_snapshot;
-    use ra_db::fixture::WithFixture;
-    use ra_db::SourceDatabase;
-
-    fn import_map(ra_fixture: &str) -> String {
-        let db = TestDB::with_files(ra_fixture);
-        let crate_graph = db.crate_graph();
-
-        let import_maps: Vec<_> = crate_graph
-            .iter()
-            .filter_map(|krate| {
-                let cdata = &crate_graph[krate];
-                let name = cdata.display_name.as_ref()?;
-
-                let map = db.import_map(krate);
-
-                Some(format!("{}:\n{:?}", name, map))
-            })
-            .collect();
-
-        import_maps.join("\n")
-    }
-
-    #[test]
-    fn smoke() {
-        let map = import_map(
-            r"
-            //- /main.rs crate:main deps:lib
-
-            mod private {
-                pub use lib::Pub;
-                pub struct InPrivateModule;
-            }
-
-            pub mod publ1 {
-                use lib::Pub;
-            }
-
-            pub mod real_pub {
-                pub use lib::Pub;
-            }
-            pub mod real_pu2 { // same path length as above
-                pub use lib::Pub;
-            }
-
-            //- /lib.rs crate:lib
-            pub struct Pub {}
-            pub struct Pub2; // t + v
-            struct Priv;
-        ",
-        );
-
-        assert_snapshot!(map, @r###"
-        main:
-        - publ1 (t)
-        - real_pu2 (t)
-        - real_pub (t)
-        - real_pub::Pub (t)
-        lib:
-        - Pub (t)
-        - Pub2 (t)
-        - Pub2 (v)
-        "###);
-    }
-
-    #[test]
-    fn prefers_shortest_path() {
-        let map = import_map(
-            r"
-            //- /main.rs crate:main
-
-            pub mod sub {
-                pub mod subsub {
-                    pub struct Def {}
-                }
-
-                pub use super::sub::subsub::Def;
-            }
-        ",
-        );
-
-        assert_snapshot!(map, @r###"
-        main:
-        - sub (t)
-        - sub::Def (t)
-        - sub::subsub (t)
-        "###);
-    }
-
-    #[test]
-    fn type_reexport_cross_crate() {
-        // Reexports need to be visible from a crate, even if the original crate exports the item
-        // at a shorter path.
-        let map = import_map(
-            r"
-            //- /main.rs crate:main deps:lib
-            pub mod m {
-                pub use lib::S;
-            }
-            //- /lib.rs crate:lib
-            pub struct S;
-        ",
-        );
-
-        assert_snapshot!(map, @r###"
-        main:
-        - m (t)
-        - m::S (t)
-        - m::S (v)
-        lib:
-        - S (t)
-        - S (v)
-        "###);
-    }
-
-    #[test]
-    fn macro_reexport() {
-        let map = import_map(
-            r"
-            //- /main.rs crate:main deps:lib
-            pub mod m {
-                pub use lib::pub_macro;
-            }
-            //- /lib.rs crate:lib
-            #[macro_export]
-            macro_rules! pub_macro {
-                () => {};
-            }
-        ",
-        );
-
-        assert_snapshot!(map, @r###"
-        main:
-        - m (t)
-        - m::pub_macro (m)
-        lib:
-        - pub_macro (m)
-        "###);
-    }
-
-    #[test]
-    fn module_reexport() {
-        // Reexporting modules from a dependency adds all contents to the import map.
-        let map = import_map(
-            r"
-            //- /main.rs crate:main deps:lib
-            pub use lib::module as reexported_module;
-            //- /lib.rs crate:lib
-            pub mod module {
-                pub struct S;
-            }
-        ",
-        );
-
-        assert_snapshot!(map, @r###"
-        main:
-        - reexported_module (t)
-        - reexported_module::S (t)
-        - reexported_module::S (v)
-        lib:
-        - module (t)
-        - module::S (t)
-        - module::S (v)
-        "###);
-    }
-
-    #[test]
-    fn cyclic_module_reexport() {
-        // A cyclic reexport does not hang.
-        let map = import_map(
-            r"
-            //- /lib.rs crate:lib
-            pub mod module {
-                pub struct S;
-                pub use super::sub::*;
-            }
-
-            pub mod sub {
-                pub use super::module;
-            }
-        ",
-        );
-
-        assert_snapshot!(map, @r###"
-        lib:
-        - module (t)
-        - module::S (t)
-        - module::S (v)
-        - sub (t)
-        "###);
-    }
-
-    #[test]
-    fn private_macro() {
-        let map = import_map(
-            r"
-            //- /lib.rs crate:lib
-            macro_rules! private_macro {
-                () => {};
-            }
-        ",
-        );
-
-        assert_snapshot!(map, @r###"
-        lib:
-        "###);
-    }
-}
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index b03ba939a5..fc15948adf 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -3,12 +3,11 @@
 
 use hir_expand::name::Name;
 use once_cell::sync::Lazy;
-use ra_db::CrateId;
 use rustc_hash::FxHashMap;
 
 use crate::{
-    db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId,
-    Lookup, MacroDefId, ModuleDefId, TraitId,
+    per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId,
+    TraitId,
 };
 
 #[derive(Debug, Default, PartialEq, Eq)]
@@ -204,22 +203,4 @@ impl ItemInNs {
             ItemInNs::Macros(_) => None,
         }
     }
-
-    /// Returns the crate defining this item (or `None` if `self` is built-in).
-    pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
-        Some(match self {
-            ItemInNs::Types(did) | ItemInNs::Values(did) => match did {
-                ModuleDefId::ModuleId(id) => id.krate,
-                ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate,
-                ModuleDefId::AdtId(id) => id.module(db).krate,
-                ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate,
-                ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate,
-                ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate,
-                ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate,
-                ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate,
-                ModuleDefId::BuiltinType(_) => return None,
-            },
-            ItemInNs::Macros(id) => return id.krate,
-        })
-    }
 }
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index de490fcc58..5325a27608 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -43,7 +43,6 @@ pub mod child_by_source;
 
 pub mod visibility;
 pub mod find_path;
-pub mod import_map;
 
 #[cfg(test)]
 mod test_db;
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index bfa921de22..4512448e02 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -76,19 +76,6 @@ impl ModPath {
         }
     }
 
-    /// Returns the number of segments in the path (counting special segments like `$crate` and
-    /// `super`).
-    pub fn len(&self) -> usize {
-        self.segments.len()
-            + match self.kind {
-                PathKind::Plain => 0,
-                PathKind::Super(i) => i as usize,
-                PathKind::Crate => 1,
-                PathKind::Abs => 0,
-                PathKind::DollarCrate(_) => 1,
-            }
-    }
-
     pub fn is_ident(&self) -> bool {
         self.kind == PathKind::Plain && self.segments.len() == 1
     }
diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs
index 74665c5885..6e435c8c12 100644
--- a/crates/ra_hir_def/src/per_ns.rs
+++ b/crates/ra_hir_def/src/per_ns.rs
@@ -5,7 +5,7 @@
 
 use hir_expand::MacroDefId;
 
-use crate::{item_scope::ItemInNs, visibility::Visibility, ModuleDefId};
+use crate::{visibility::Visibility, ModuleDefId};
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub struct PerNs {
@@ -84,12 +84,4 @@ impl PerNs {
             macros: self.macros.or(other.macros),
         }
     }
-
-    pub fn iter_items(self) -> impl Iterator<Item = ItemInNs> {
-        self.types
-            .map(|it| ItemInNs::Types(it.0))
-            .into_iter()
-            .chain(self.values.map(|it| ItemInNs::Values(it.0)).into_iter())
-            .chain(self.macros.map(|it| ItemInNs::Macros(it.0)).into_iter())
-    }
 }
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index 7579546d2f..eec5fb8ebf 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -295,13 +295,19 @@ fn concat_expand(
 
 fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> {
     let call_site = call_id.as_file().original_file(db);
-    let res = db.resolve_path(call_site, path)?;
-    // Prevent include itself
-    if res == call_site {
-        None
-    } else {
-        Some(res)
+
+    // Handle trivial case
+    if let Some(res) = db.resolve_path(call_site, path) {
+        // Prevent include itself
+        return if res == call_site { None } else { Some(res) };
     }
+
+    // Extern paths ?
+    let krate = *db.relevant_crates(call_site).get(0)?;
+    let (extern_source_id, relative_file) =
+        db.crate_graph()[krate].extern_source.extern_path(path)?;
+
+    db.resolve_extern_path(extern_source_id, &relative_file)
 }
 
 fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> {
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 0a8bb24ac2..bf71d38d6b 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -3,8 +3,8 @@
 use std::sync::Arc;
 
 use hir_def::{
-    db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalFieldId, TraitId, TypeParamId,
-    VariantId,
+    db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TraitId,
+    TypeParamId, VariantId,
 };
 use ra_arena::map::ArenaMap;
 use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
@@ -13,8 +13,8 @@ use ra_prof::profile;
 use crate::{
     method_resolution::{CrateImplDefs, TyFingerprint},
     traits::{chalk, AssocTyValue, Impl},
-    Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty,
-    TyDefId, TypeCtor, ValueTyDefId,
+    Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
+    ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
 };
 use hir_expand::name::Name;
 
@@ -48,6 +48,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::invoke(crate::callable_item_sig)]
     fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig;
 
+    #[salsa::invoke(crate::lower::return_type_impl_traits)]
+    fn return_type_impl_traits(
+        &self,
+        def: FunctionId,
+    ) -> Option<Arc<Binders<ReturnTypeImplTraits>>>;
+
     #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
     #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
     fn generic_predicates_for_param(
@@ -80,6 +86,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::interned]
     fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
     #[salsa::interned]
+    fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId;
+    #[salsa::interned]
     fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId;
     #[salsa::interned]
     fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId;
@@ -142,3 +150,7 @@ fn hir_database_is_object_safe() {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct GlobalTypeParamId(salsa::InternId);
 impl_intern_key!(GlobalTypeParamId);
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct InternedOpaqueTyId(salsa::InternId);
+impl_intern_key!(InternedOpaqueTyId);
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index b9c4d2e897..3c97e13545 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -4,7 +4,7 @@ use std::fmt;
 
 use crate::{
     db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate,
-    Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
+    Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
 };
 use hir_def::{
     find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId,
@@ -359,6 +359,21 @@ impl HirDisplay for ApplicationTy {
                     write!(f, ">")?;
                 }
             }
+            TypeCtor::OpaqueType(opaque_ty_id) => {
+                let bounds = match opaque_ty_id {
+                    OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
+                        let datas =
+                            f.db.return_type_impl_traits(func).expect("impl trait id without data");
+                        let data = (*datas)
+                            .as_ref()
+                            .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
+                        data.clone().subst(&self.parameters)
+                    }
+                };
+                write!(f, "impl ")?;
+                write_bounds_like_dyn_trait(&bounds.value, f)?;
+                // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
+            }
             TypeCtor::Closure { .. } => {
                 let sig = self.parameters[0].callable_sig(f.db);
                 if let Some(sig) = sig {
@@ -427,14 +442,24 @@ impl HirDisplay for Ty {
                 }
             }
             Ty::Bound(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
-            Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
-                match self {
-                    Ty::Dyn(_) => write!(f, "dyn ")?,
-                    Ty::Opaque(_) => write!(f, "impl ")?,
-                    _ => unreachable!(),
-                };
+            Ty::Dyn(predicates) => {
+                write!(f, "dyn ")?;
                 write_bounds_like_dyn_trait(predicates, f)?;
             }
+            Ty::Opaque(opaque_ty) => {
+                let bounds = match opaque_ty.opaque_ty_id {
+                    OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
+                        let datas =
+                            f.db.return_type_impl_traits(func).expect("impl trait id without data");
+                        let data = (*datas)
+                            .as_ref()
+                            .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
+                        data.clone().subst(&opaque_ty.parameters)
+                    }
+                };
+                write!(f, "impl ")?;
+                write_bounds_like_dyn_trait(&bounds.value, f)?;
+            }
             Ty::Unknown => write!(f, "{{unknown}}")?,
             Ty::Infer(..) => write!(f, "_")?,
         }
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index dc77e88e50..d9bf3c2f0f 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;
 use super::{
     primitive::{FloatTy, IntTy},
     traits::{Guidance, Obligation, ProjectionPredicate, Solution},
-    ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment,
-    TraitRef, Ty, TypeCtor, TypeWalk, Uncertain,
+    ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
+    TypeWalk, Uncertain,
 };
 use crate::{
     db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
@@ -383,25 +383,6 @@ impl<'a> InferenceContext<'a> {
     ) -> Ty {
         match assoc_ty {
             Some(res_assoc_ty) => {
-                // FIXME:
-                // Check if inner_ty is is `impl Trait` and contained input TypeAlias id
-                // this is a workaround while Chalk assoc type projection doesn't always work yet,
-                // but once that is fixed I don't think we should keep this
-                // (we'll probably change how associated types are resolved anyway)
-                if let Ty::Opaque(ref predicates) = inner_ty {
-                    for p in predicates.iter() {
-                        if let GenericPredicate::Projection(projection) = p {
-                            if projection.projection_ty.associated_ty == res_assoc_ty {
-                                if let ty_app!(_, params) = &projection.ty {
-                                    if params.len() == 0 {
-                                        return projection.ty.clone();
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-
                 let ty = self.table.new_type_var();
                 let builder = Substs::build_for_def(self.db, res_assoc_ty)
                     .push(inner_ty)
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 9fa8d3bdc3..135976fcda 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -147,6 +147,12 @@ pub enum TypeCtor {
     /// an **application type** like `(Iterator::Item)<T>`.
     AssociatedType(TypeAliasId),
 
+    /// This represents a placeholder for an opaque type in situations where we
+    /// don't know the hidden type (i.e. currently almost always). This is
+    /// analogous to the `AssociatedType` type constructor. As with that one,
+    /// these are only produced by Chalk.
+    OpaqueType(OpaqueTyId),
+
     /// The type of a specific closure.
     ///
     /// The closure signature is stored in a `FnPtr` type in the first type
@@ -194,6 +200,14 @@ impl TypeCtor {
                 let generic_params = generics(db.upcast(), type_alias.into());
                 generic_params.len()
             }
+            TypeCtor::OpaqueType(opaque_ty_id) => {
+                match opaque_ty_id {
+                    OpaqueTyId::ReturnTypeImplTrait(func, _) => {
+                        let generic_params = generics(db.upcast(), func.into());
+                        generic_params.len()
+                    }
+                }
+            }
             TypeCtor::FnPtr { num_args } => num_args as usize + 1,
             TypeCtor::Tuple { cardinality } => cardinality as usize,
         }
@@ -220,6 +234,11 @@ impl TypeCtor {
             TypeCtor::AssociatedType(type_alias) => {
                 Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate)
             }
+            TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id {
+                OpaqueTyId::ReturnTypeImplTrait(func, _) => {
+                    Some(func.lookup(db.upcast()).module(db.upcast()).krate)
+                }
+            },
         }
     }
 
@@ -241,6 +260,7 @@ impl TypeCtor {
             TypeCtor::Adt(adt) => Some(adt.into()),
             TypeCtor::FnDef(callable) => Some(callable.into()),
             TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()),
+            TypeCtor::OpaqueType(_impl_trait_id) => None,
         }
     }
 }
@@ -254,6 +274,12 @@ pub struct ApplicationTy {
     pub parameters: Substs,
 }
 
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct OpaqueTy {
+    pub opaque_ty_id: OpaqueTyId,
+    pub parameters: Substs,
+}
+
 /// A "projection" type corresponds to an (unnormalized)
 /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
 /// trait and all its parameters are fully known.
@@ -308,6 +334,12 @@ pub enum Ty {
     /// trait and all its parameters are fully known.
     Projection(ProjectionTy),
 
+    /// An opaque type (`impl Trait`).
+    ///
+    /// This is currently only used for return type impl trait; each instance of
+    /// `impl Trait` in a return type gets its own ID.
+    Opaque(OpaqueTy),
+
     /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
     /// {}` when we're type-checking the body of that function. In this
     /// situation, we know this stands for *some* type, but don't know the exact
@@ -332,12 +364,6 @@ pub enum Ty {
     /// didn't seem worth the overhead yet.
     Dyn(Arc<[GenericPredicate]>),
 
-    /// An opaque type (`impl Trait`).
-    ///
-    /// The predicates are quantified over the `Self` type; see `Ty::Dyn` for
-    /// more.
-    Opaque(Arc<[GenericPredicate]>),
-
     /// A placeholder for a type which could not be computed; this is propagated
     /// to avoid useless error messages. Doubles as a placeholder where type
     /// variables are inserted before type checking, since we want to try to
@@ -490,7 +516,7 @@ impl Deref for Substs {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 pub struct Binders<T> {
     pub num_binders: usize,
     pub value: T,
@@ -534,6 +560,20 @@ impl<T: TypeWalk> Binders<T> {
     }
 }
 
+impl<T: TypeWalk> TypeWalk for Binders<T> {
+    fn walk(&self, f: &mut impl FnMut(&Ty)) {
+        self.value.walk(f);
+    }
+
+    fn walk_mut_binders(
+        &mut self,
+        f: &mut impl FnMut(&mut Ty, DebruijnIndex),
+        binders: DebruijnIndex,
+    ) {
+        self.value.walk_mut_binders(f, binders.shifted_in())
+    }
+}
+
 /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
 /// Name to be bikeshedded: TraitBound? TraitImplements?
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -947,11 +987,16 @@ impl TypeWalk for Ty {
                     t.walk(f);
                 }
             }
-            Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
+            Ty::Dyn(predicates) => {
                 for p in predicates.iter() {
                     p.walk(f);
                 }
             }
+            Ty::Opaque(o_ty) => {
+                for t in o_ty.parameters.iter() {
+                    t.walk(f);
+                }
+            }
             Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
         }
         f(self);
@@ -969,13 +1014,48 @@ impl TypeWalk for Ty {
             Ty::Projection(p_ty) => {
                 p_ty.parameters.walk_mut_binders(f, binders);
             }
-            Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
+            Ty::Dyn(predicates) => {
                 for p in make_mut_slice(predicates) {
                     p.walk_mut_binders(f, binders.shifted_in());
                 }
             }
+            Ty::Opaque(o_ty) => {
+                o_ty.parameters.walk_mut_binders(f, binders);
+            }
             Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
         }
         f(self, binders);
     }
 }
+
+impl<T: TypeWalk> TypeWalk for Vec<T> {
+    fn walk(&self, f: &mut impl FnMut(&Ty)) {
+        for t in self {
+            t.walk(f);
+        }
+    }
+    fn walk_mut_binders(
+        &mut self,
+        f: &mut impl FnMut(&mut Ty, DebruijnIndex),
+        binders: DebruijnIndex,
+    ) {
+        for t in self {
+            t.walk_mut_binders(f, binders);
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
+pub enum OpaqueTyId {
+    ReturnTypeImplTrait(hir_def::FunctionId, u16),
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct ReturnTypeImplTraits {
+    pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub(crate) struct ReturnTypeImplTrait {
+    pub(crate) bounds: Binders<Vec<GenericPredicate>>,
+}
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 35ac86a461..a05cbd7fcf 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -21,8 +21,10 @@ use hir_def::{
     HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
     UnionId, VariantId,
 };
+use hir_expand::name::Name;
 use ra_arena::map::ArenaMap;
 use ra_db::CrateId;
+use test_utils::mark;
 
 use crate::{
     db::HirDatabase,
@@ -31,10 +33,10 @@ use crate::{
         all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
         make_mut_slice, variant_data,
     },
-    Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate,
-    ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
+    Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, OpaqueTy, OpaqueTyId, PolyFnSig,
+    ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, ReturnTypeImplTraits, Substs,
+    TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
 };
-use hir_expand::name::Name;
 
 #[derive(Debug)]
 pub struct TyLoweringContext<'a> {
@@ -47,7 +49,16 @@ pub struct TyLoweringContext<'a> {
     /// possible currently, so this should be fine for now.
     pub type_param_mode: TypeParamLoweringMode,
     pub impl_trait_mode: ImplTraitLoweringMode,
-    pub impl_trait_counter: std::cell::Cell<u16>,
+    impl_trait_counter: std::cell::Cell<u16>,
+    /// When turning `impl Trait` into opaque types, we have to collect the
+    /// bounds at the same time to get the IDs correct (without becoming too
+    /// complicated). I don't like using interior mutability (as for the
+    /// counter), but I've tried and failed to make the lifetimes work for
+    /// passing around a `&mut TyLoweringContext`. The core problem is that
+    /// we're grouping the mutable data (the counter and this field) together
+    /// with the immutable context (the references to the DB and resolver).
+    /// Splitting this up would be a possible fix.
+    opaque_type_data: std::cell::RefCell<Vec<ReturnTypeImplTrait>>,
 }
 
 impl<'a> TyLoweringContext<'a> {
@@ -56,26 +67,42 @@ impl<'a> TyLoweringContext<'a> {
         let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
         let type_param_mode = TypeParamLoweringMode::Placeholder;
         let in_binders = DebruijnIndex::INNERMOST;
-        Self { db, resolver, in_binders, impl_trait_mode, impl_trait_counter, type_param_mode }
+        let opaque_type_data = std::cell::RefCell::new(Vec::new());
+        Self {
+            db,
+            resolver,
+            in_binders,
+            impl_trait_mode,
+            impl_trait_counter,
+            type_param_mode,
+            opaque_type_data,
+        }
     }
 
-    pub fn with_shifted_in<T>(
+    pub fn with_debruijn<T>(
         &self,
         debruijn: DebruijnIndex,
         f: impl FnOnce(&TyLoweringContext) -> T,
     ) -> T {
+        let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
         let new_ctx = Self {
-            in_binders: self.in_binders.shifted_in_from(debruijn),
+            in_binders: debruijn,
             impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()),
+            opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec),
             ..*self
         };
         let result = f(&new_ctx);
         self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
+        self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
         result
     }
 
-    pub fn shifted_in(self, debruijn: DebruijnIndex) -> Self {
-        Self { in_binders: self.in_binders.shifted_in_from(debruijn), ..self }
+    pub fn with_shifted_in<T>(
+        &self,
+        debruijn: DebruijnIndex,
+        f: impl FnOnce(&TyLoweringContext) -> T,
+    ) -> T {
+        self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f)
     }
 
     pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
@@ -167,20 +194,44 @@ impl Ty {
             TypeRef::ImplTrait(bounds) => {
                 match ctx.impl_trait_mode {
                     ImplTraitLoweringMode::Opaque => {
-                        let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
-                        let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-                            bounds
-                                .iter()
-                                .flat_map(|b| {
-                                    GenericPredicate::from_type_bound(ctx, b, self_ty.clone())
-                                })
-                                .collect()
-                        });
-                        Ty::Opaque(predicates)
+                        let idx = ctx.impl_trait_counter.get();
+                        ctx.impl_trait_counter.set(idx + 1);
+
+                        assert!(idx as usize == ctx.opaque_type_data.borrow().len());
+                        // this dance is to make sure the data is in the right
+                        // place even if we encounter more opaque types while
+                        // lowering the bounds
+                        ctx.opaque_type_data
+                            .borrow_mut()
+                            .push(ReturnTypeImplTrait { bounds: Binders::new(1, Vec::new()) });
+                        // We don't want to lower the bounds inside the binders
+                        // we're currently in, because they don't end up inside
+                        // those binders. E.g. when we have `impl Trait<impl
+                        // OtherTrait<T>>`, the `impl OtherTrait<T>` can't refer
+                        // to the self parameter from `impl Trait`, and the
+                        // bounds aren't actually stored nested within each
+                        // other, but separately. So if the `T` refers to a type
+                        // parameter of the outer function, it's just one binder
+                        // away instead of two.
+                        let actual_opaque_type_data = ctx
+                            .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
+                                ReturnTypeImplTrait::from_hir(ctx, &bounds)
+                            });
+                        ctx.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
+
+                        let func = match ctx.resolver.generic_def() {
+                            Some(GenericDefId::FunctionId(f)) => f,
+                            _ => panic!("opaque impl trait lowering in non-function"),
+                        };
+                        let impl_trait_id = OpaqueTyId::ReturnTypeImplTrait(func, idx);
+                        let generics = generics(ctx.db.upcast(), func.into());
+                        let parameters = Substs::bound_vars(&generics, ctx.in_binders);
+                        Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters })
                     }
                     ImplTraitLoweringMode::Param => {
                         let idx = ctx.impl_trait_counter.get();
-                        ctx.impl_trait_counter.set(idx + 1);
+                        // FIXME we're probably doing something wrong here
+                        ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
                         if let Some(def) = ctx.resolver.generic_def() {
                             let generics = generics(ctx.db.upcast(), def);
                             let param = generics
@@ -197,7 +248,8 @@ impl Ty {
                     }
                     ImplTraitLoweringMode::Variable => {
                         let idx = ctx.impl_trait_counter.get();
-                        ctx.impl_trait_counter.set(idx + 1);
+                        // FIXME we're probably doing something wrong here
+                        ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
                         let (parent_params, self_params, list_params, _impl_trait_params) =
                             if let Some(def) = ctx.resolver.generic_def() {
                                 let generics = generics(ctx.db.upcast(), def);
@@ -663,6 +715,30 @@ fn assoc_type_bindings_from_type_bound<'a>(
         })
 }
 
+impl ReturnTypeImplTrait {
+    fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self {
+        mark::hit!(lower_rpit);
+        let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
+        let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| {
+            bounds
+                .iter()
+                .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone()))
+                .collect()
+        });
+        ReturnTypeImplTrait { bounds: Binders::new(1, predicates) }
+    }
+}
+
+fn count_impl_traits(type_ref: &TypeRef) -> usize {
+    let mut count = 0;
+    type_ref.walk(&mut |type_ref| {
+        if matches!(type_ref, TypeRef::ImplTrait(_)) {
+            count += 1;
+        }
+    });
+    count
+}
+
 /// Build the signature of a callable item (function, struct or enum variant).
 pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig {
     match def {
@@ -864,7 +940,9 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
         .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
         .with_type_param_mode(TypeParamLoweringMode::Variable);
     let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::<Vec<_>>();
-    let ctx_ret = ctx_params.with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+    let ctx_ret = TyLoweringContext::new(db, &resolver)
+        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
+        .with_type_param_mode(TypeParamLoweringMode::Variable);
     let ret = Ty::from_hir(&ctx_ret, &data.ret_type);
     let generics = generics(db.upcast(), def.into());
     let num_binders = generics.len();
@@ -1084,3 +1162,25 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
         TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value))?,
     ))
 }
+
+pub(crate) fn return_type_impl_traits(
+    db: &impl HirDatabase,
+    def: hir_def::FunctionId,
+) -> Option<Arc<Binders<ReturnTypeImplTraits>>> {
+    // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
+    let data = db.function_data(def);
+    let resolver = def.resolver(db.upcast());
+    let ctx_ret = TyLoweringContext::new(db, &resolver)
+        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
+        .with_type_param_mode(TypeParamLoweringMode::Variable);
+    let _ret = Ty::from_hir(&ctx_ret, &data.ret_type);
+    let generics = generics(db.upcast(), def.into());
+    let num_binders = generics.len();
+    let return_type_impl_traits =
+        ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() };
+    if return_type_impl_traits.impl_traits.is_empty() {
+        None
+    } else {
+        Some(Arc::new(Binders::new(num_binders, return_type_impl_traits)))
+    }
+}
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 61de3cc30c..a72a82f5a2 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;
 use log::debug;
 
 use chalk_ir::{fold::shift::Shift, GenericArg, TypeName};
-use chalk_solve::rust_ir::{self, WellKnownTrait};
+use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
 
 use hir_def::{
     lang_item::{lang_attr, LangItemTarget},
@@ -100,6 +100,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
     fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> {
         self.db.associated_ty_value(self.krate, id)
     }
+
     fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<Interner>> {
         vec![]
     }
@@ -130,11 +131,34 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
         self.db.program_clauses_for_chalk_env(self.krate, environment.clone())
     }
 
-    fn opaque_ty_data(
-        &self,
-        _id: chalk_ir::OpaqueTyId<Interner>,
-    ) -> Arc<rust_ir::OpaqueTyDatum<Interner>> {
-        unimplemented!()
+    fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> {
+        let interned_id = crate::db::InternedOpaqueTyId::from(id);
+        let full_id = self.db.lookup_intern_impl_trait_id(interned_id);
+        let (func, idx) = match full_id {
+            crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx),
+        };
+        let datas =
+            self.db.return_type_impl_traits(func).expect("impl trait id without impl traits");
+        let data = &datas.value.impl_traits[idx as usize];
+        let bound = OpaqueTyDatumBound {
+            bounds: make_binders(
+                data.bounds
+                    .value
+                    .iter()
+                    .cloned()
+                    .filter(|b| !b.is_error())
+                    .map(|b| b.to_chalk(self.db))
+                    .collect(),
+                1,
+            ),
+        };
+        let num_vars = datas.num_binders;
+        Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) })
+    }
+
+    fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
+        // FIXME: actually provide the hidden type; it is relevant for auto traits
+        Ty::Unknown.to_chalk(self.db)
     }
 
     fn force_impl_for(
@@ -150,10 +174,6 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
         // FIXME: implement actual object safety
         true
     }
-
-    fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
-        Ty::Unknown.to_chalk(self.db)
-    }
 }
 
 pub(crate) fn program_clauses_for_chalk_env_query(
@@ -460,6 +480,18 @@ impl From<crate::traits::GlobalImplId> for ImplId {
     }
 }
 
+impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
+    fn from(id: OpaqueTyId) -> Self {
+        InternKey::from_intern_id(id.0)
+    }
+}
+
+impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId {
+    fn from(id: crate::db::InternedOpaqueTyId) -> Self {
+        chalk_ir::OpaqueTyId(id.as_intern_id())
+    }
+}
+
 impl From<rust_ir::AssociatedTyValueId<Interner>> for crate::traits::AssocTyValueId {
     fn from(id: rust_ir::AssociatedTyValueId<Interner>) -> Self {
         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 e27074ba6f..56aab640c8 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
 pub type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>;
 pub type FnDefId = chalk_ir::FnDefId<Interner>;
 pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>;
+pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
+pub type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
 
 impl chalk_ir::interner::Interner for Interner {
     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 5f6daf842b..8343604303 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::{
     db::HirDatabase,
     primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
     traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
-    ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy,
-    Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
+    ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId,
+    ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
 };
 
 use super::interner::*;
@@ -68,7 +68,16 @@ impl ToChalk for Ty {
                 let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) };
                 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner)
             }
-            Ty::Opaque(_) | Ty::Unknown => {
+            Ty::Opaque(opaque_ty) => {
+                let opaque_ty_id = opaque_ty.opaque_ty_id.to_chalk(db);
+                let substitution = opaque_ty.parameters.to_chalk(db);
+                chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
+                    opaque_ty_id,
+                    substitution,
+                }))
+                .intern(&Interner)
+            }
+            Ty::Unknown => {
                 let substitution = chalk_ir::Substitution::empty(&Interner);
                 let name = TypeName::Error;
                 chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
@@ -98,7 +107,11 @@ impl ToChalk for Ty {
                 let parameters = from_chalk(db, proj.substitution);
                 Ty::Projection(ProjectionTy { associated_ty, parameters })
             }
-            chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(),
+            chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => {
+                let impl_trait_id = from_chalk(db, opaque_ty.opaque_ty_id);
+                let parameters = from_chalk(db, opaque_ty.substitution);
+                Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters })
+            }
             chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => {
                 let parameters: Substs = from_chalk(db, substitution);
                 Ty::Apply(ApplicationTy {
@@ -204,6 +217,21 @@ impl ToChalk for hir_def::TraitId {
     }
 }
 
+impl ToChalk for OpaqueTyId {
+    type Chalk = chalk_ir::OpaqueTyId<Interner>;
+
+    fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::OpaqueTyId<Interner> {
+        db.intern_impl_trait_id(self).into()
+    }
+
+    fn from_chalk(
+        db: &dyn HirDatabase,
+        opaque_ty_id: chalk_ir::OpaqueTyId<Interner>,
+    ) -> OpaqueTyId {
+        db.lookup_intern_impl_trait_id(opaque_ty_id.into())
+    }
+}
+
 impl ToChalk for TypeCtor {
     type Chalk = TypeName<Interner>;
 
@@ -214,6 +242,11 @@ impl ToChalk for TypeCtor {
                 TypeName::AssociatedType(type_id)
             }
 
+            TypeCtor::OpaqueType(impl_trait_id) => {
+                let id = impl_trait_id.to_chalk(db);
+                TypeName::OpaqueType(id)
+            }
+
             TypeCtor::Bool => TypeName::Scalar(Scalar::Bool),
             TypeCtor::Char => TypeName::Scalar(Scalar::Char),
             TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)),
@@ -252,7 +285,9 @@ impl ToChalk for TypeCtor {
         match type_name {
             TypeName::Adt(struct_id) => db.lookup_intern_type_ctor(struct_id.into()),
             TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
-            TypeName::OpaqueType(_) => unreachable!(),
+            TypeName::OpaqueType(opaque_type_id) => {
+                TypeCtor::OpaqueType(from_chalk(db, opaque_type_id))
+            }
 
             TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool,
             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 d88828c7c0..556af70989 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<'_> {
                 let name = self.0.type_alias_data(type_alias).name.clone();
                 write!(f, "{}::{}", trait_name, name)?;
             }
+            TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id {
+                crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
+                    write!(f, "{{impl trait {} of {:?}}}", idx, func)?;
+                }
+            },
             TypeCtor::Closure { def, expr } => {
                 write!(f, "{{closure {:?} in ", expr.into_raw())?;
                 match def {
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 62df074594..9636cd0d6a 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -13,43 +13,14 @@ use ra_ide_db::{
 use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset};
 
 use crate::{
-    display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav},
-    FilePosition, NavigationTarget, RangeInfo,
+    display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel},
+    FilePosition, RangeInfo,
 };
 
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct HoverConfig {
-    pub implementations: bool,
-}
-
-impl Default for HoverConfig {
-    fn default() -> Self {
-        Self { implementations: true }
-    }
-}
-
-impl HoverConfig {
-    pub const NO_ACTIONS: Self = Self { implementations: false };
-
-    pub fn any(&self) -> bool {
-        self.implementations
-    }
-
-    pub fn none(&self) -> bool {
-        !self.any()
-    }
-}
-
-#[derive(Debug, Clone)]
-pub enum HoverAction {
-    Implementaion(FilePosition),
-}
-
 /// Contains the results when hovering over an item
 #[derive(Debug, Default)]
 pub struct HoverResult {
     results: Vec<String>,
-    actions: Vec<HoverAction>,
 }
 
 impl HoverResult {
@@ -77,20 +48,10 @@ impl HoverResult {
         &self.results
     }
 
-    pub fn actions(&self) -> &[HoverAction] {
-        &self.actions
-    }
-
-    pub fn push_action(&mut self, action: HoverAction) {
-        self.actions.push(action);
-    }
-
     /// Returns the results converted into markup
     /// for displaying in a UI
-    ///
-    /// Does not process actions!
     pub fn to_markup(&self) -> String {
-        self.results.join("\n\n___\n")
+        self.results.join("\n\n---\n")
     }
 }
 
@@ -121,10 +82,6 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
         res.extend(hover_text_from_name_kind(db, name_kind));
 
         if !res.is_empty() {
-            if let Some(action) = show_implementations_action(db, name_kind) {
-                res.push_action(action);
-            }
-
             return Some(RangeInfo::new(range, res));
         }
     }
@@ -155,26 +112,6 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
     Some(RangeInfo::new(range, res))
 }
 
-fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
-    fn to_action(nav_target: NavigationTarget) -> HoverAction {
-        HoverAction::Implementaion(FilePosition {
-            file_id: nav_target.file_id(),
-            offset: nav_target.range().start(),
-        })
-    }
-
-    match def {
-        Definition::ModuleDef(it) => match it {
-            ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))),
-            ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))),
-            ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))),
-            ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))),
-            _ => None,
-        },
-        _ => None,
-    }
-}
-
 fn hover_text(
     docs: Option<String>,
     desc: Option<String>,
@@ -291,8 +228,6 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
 
 #[cfg(test)]
 mod tests {
-    use super::*;
-
     use ra_db::FileLoader;
     use ra_syntax::TextRange;
 
@@ -306,14 +241,7 @@ mod tests {
         s.map(trim_markup)
     }
 
-    fn assert_impl_action(action: &HoverAction, position: u32) {
-        let offset = match action {
-            HoverAction::Implementaion(pos) => pos.offset,
-        };
-        assert_eq!(offset, position.into());
-    }
-
-    fn check_hover_result(fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) {
+    fn check_hover_result(fixture: &str, expected: &[&str]) -> String {
         let (analysis, position) = analysis_and_position(fixture);
         let hover = analysis.hover(position).unwrap().unwrap();
         let mut results = Vec::from(hover.info.results());
@@ -328,7 +256,7 @@ mod tests {
         assert_eq!(hover.info.len(), expected.len());
 
         let content = analysis.db.file_text(position.file_id);
-        (content[hover.range].to_string(), hover.info.actions().to_vec())
+        content[hover.range].to_string()
     }
 
     fn check_hover_no_result(fixture: &str) {
@@ -818,7 +746,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
 
     #[test]
     fn test_hover_through_macro() {
-        let (hover_on, _) = check_hover_result(
+        let hover_on = check_hover_result(
             "
             //- /lib.rs
             macro_rules! id {
@@ -839,7 +767,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
 
     #[test]
     fn test_hover_through_expr_in_macro() {
-        let (hover_on, _) = check_hover_result(
+        let hover_on = check_hover_result(
             "
             //- /lib.rs
             macro_rules! id {
@@ -857,7 +785,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
 
     #[test]
     fn test_hover_through_expr_in_macro_recursive() {
-        let (hover_on, _) = check_hover_result(
+        let hover_on = check_hover_result(
             "
             //- /lib.rs
             macro_rules! id_deep {
@@ -878,7 +806,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
 
     #[test]
     fn test_hover_through_func_in_macro_recursive() {
-        let (hover_on, _) = check_hover_result(
+        let hover_on = check_hover_result(
             "
             //- /lib.rs
             macro_rules! id_deep {
@@ -902,7 +830,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
 
     #[test]
     fn test_hover_through_literal_string_in_macro() {
-        let (hover_on, _) = check_hover_result(
+        let hover_on = check_hover_result(
             r#"
             //- /lib.rs
             macro_rules! arr {
@@ -921,7 +849,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
 
     #[test]
     fn test_hover_through_assert_macro() {
-        let (hover_on, _) = check_hover_result(
+        let hover_on = check_hover_result(
             r#"
             //- /lib.rs
             #[rustc_builtin_macro]
@@ -997,14 +925,13 @@ fn func(foo: i32) { if true { <|>foo; }; }
 
     #[test]
     fn test_hover_trait_show_qualifiers() {
-        let (_, actions) = check_hover_result(
+        check_hover_result(
             "
             //- /lib.rs
             unsafe trait foo<|>() {}
             ",
             &["unsafe trait foo"],
         );
-        assert_impl_action(&actions[0], 13);
     }
 
     #[test]
@@ -1125,55 +1052,4 @@ fn func(foo: i32) { if true { <|>foo; }; }
             &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"],
         );
     }
-
-    #[test]
-    fn test_hover_trait_has_impl_action() {
-        let (_, actions) = check_hover_result(
-            "
-            //- /lib.rs
-            trait foo<|>() {}
-            ",
-            &["trait foo"],
-        );
-        assert_impl_action(&actions[0], 6);
-    }
-
-    #[test]
-    fn test_hover_struct_has_impl_action() {
-        let (_, actions) = check_hover_result(
-            "
-            //- /lib.rs
-            struct foo<|>() {}
-            ",
-            &["struct foo"],
-        );
-        assert_impl_action(&actions[0], 7);
-    }
-
-    #[test]
-    fn test_hover_union_has_impl_action() {
-        let (_, actions) = check_hover_result(
-            "
-            //- /lib.rs
-            union foo<|>() {}
-            ",
-            &["union foo"],
-        );
-        assert_impl_action(&actions[0], 6);
-    }
-
-    #[test]
-    fn test_hover_enum_has_impl_action() {
-        let (_, actions) = check_hover_result(
-            "
-            //- /lib.rs
-            enum foo<|>() {
-                A,
-                B
-            }
-            ",
-            &["enum foo"],
-        );
-        assert_impl_action(&actions[0], 5);
-    }
 }
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index a56718d3f5..34c2d75fed 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -66,7 +66,7 @@ pub use crate::{
     display::{file_structure, FunctionSignature, NavigationTarget, StructureNode},
     expand_macro::ExpandedMacro,
     folding_ranges::{Fold, FoldKind},
-    hover::{HoverAction, HoverConfig, HoverResult},
+    hover::HoverResult,
     inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
     references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
     runnables::{Runnable, RunnableKind, TestId},
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index ea78e49e05..1f4d2c0765 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -334,7 +334,6 @@ impl RootDatabase {
             hir::db::CrateLangItemsQuery
             hir::db::LangItemQuery
             hir::db::DocumentationQuery
-            hir::db::ImportMapQuery
 
             // InternDatabase
             hir::db::InternFunctionQuery
@@ -370,6 +369,7 @@ impl RootDatabase {
             hir::db::ImplDatumQuery
             hir::db::AssociatedTyValueQuery
             hir::db::TraitSolveQuery
+            hir::db::ReturnTypeImplTraitsQuery
 
             // SymbolsDatabase
             crate::symbol_index::FileSymbolsQuery
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index 1db60b87fb..8b06cbfc54 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -18,7 +18,7 @@ use ra_syntax::{
 use crate::RootDatabase;
 
 // FIXME: a more precise name would probably be `Symbol`?
-#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+#[derive(Debug, PartialEq, Eq)]
 pub enum Definition {
     Macro(MacroDef),
     Field(Field),
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index 727d743b5f..93d5891a04 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;
 use hir::db::{AstDatabase, DefDatabase};
 use ra_db::{
     salsa::{self, Database, Durability},
-    Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
-    SourceRootId, Upcast,
+    Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath,
+    SourceDatabase, SourceRootId, Upcast,
 };
 use rustc_hash::FxHashMap;
 
@@ -63,6 +63,13 @@ impl FileLoader for RootDatabase {
     fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
+    fn resolve_extern_path(
+        &self,
+        extern_id: ra_db::ExternSourceId,
+        relative_path: &RelativePath,
+    ) -> Option<FileId> {
+        FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path)
+    }
 }
 
 impl salsa::Database for RootDatabase {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 8d6efdbe8c..23168c3ae9 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};
 
 use lsp_types::ClientCapabilities;
 use ra_flycheck::FlycheckConfig;
-use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig};
+use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig};
 use ra_project_model::{CargoConfig, JsonProject, ProjectManifest};
 use serde::Deserialize;
 
@@ -34,7 +34,6 @@ pub struct Config {
     pub assist: AssistConfig,
     pub call_info_full: bool,
     pub lens: LensConfig,
-    pub hover: HoverConfig,
 
     pub with_sysroot: bool,
     pub linked_projects: Vec<LinkedProject>,
@@ -125,7 +124,6 @@ pub struct ClientCapsConfig {
     pub work_done_progress: bool,
     pub code_action_group: bool,
     pub resolve_code_action: bool,
-    pub hover_actions: bool,
 }
 
 impl Default for Config {
@@ -164,7 +162,6 @@ impl Default for Config {
             assist: AssistConfig::default(),
             call_info_full: true,
             lens: LensConfig::default(),
-            hover: HoverConfig::default(),
             linked_projects: Vec::new(),
         }
     }
@@ -281,14 +278,6 @@ impl Config {
             }
         }
 
-        let mut use_hover_actions = false;
-        set(value, "/hoverActions/enable", &mut use_hover_actions);
-        if use_hover_actions {
-            set(value, "/hoverActions/implementations", &mut self.hover.implementations);
-        } else {
-            self.hover = HoverConfig::NO_ACTIONS;
-        }
-
         log::info!("Config::update() = {:#?}", self);
 
         fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
@@ -342,15 +331,17 @@ impl Config {
 
         self.assist.allow_snippets(false);
         if let Some(experimental) = &caps.experimental {
-            let get_bool =
-                |index: &str| experimental.get(index).and_then(|it| it.as_bool()) == Some(true);
-
-            let snippet_text_edit = get_bool("snippetTextEdit");
+            let snippet_text_edit =
+                experimental.get("snippetTextEdit").and_then(|it| it.as_bool()) == Some(true);
             self.assist.allow_snippets(snippet_text_edit);
 
-            self.client_caps.code_action_group = get_bool("codeActionGroup");
-            self.client_caps.resolve_code_action = get_bool("resolveCodeAction");
-            self.client_caps.hover_actions = get_bool("hoverActions");
+            let code_action_group =
+                experimental.get("codeActionGroup").and_then(|it| it.as_bool()) == Some(true);
+            self.client_caps.code_action_group = code_action_group;
+
+            let resolve_code_action =
+                experimental.get("resolveCodeAction").and_then(|it| it.as_bool()) == Some(true);
+            self.client_caps.resolve_code_action = resolve_code_action;
         }
     }
 }
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 1371f6cb4a..3b957534dd 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -260,35 +260,3 @@ pub struct SnippetTextEdit {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub insert_text_format: Option<lsp_types::InsertTextFormat>,
 }
-
-pub enum HoverRequest {}
-
-impl Request for HoverRequest {
-    type Params = lsp_types::HoverParams;
-    type Result = Option<Hover>;
-    const METHOD: &'static str = "textDocument/hover";
-}
-
-#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
-pub struct Hover {
-    #[serde(flatten)]
-    pub hover: lsp_types::Hover,
-    #[serde(skip_serializing_if = "Vec::is_empty")]
-    pub actions: Vec<CommandLinkGroup>,
-}
-
-#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
-pub struct CommandLinkGroup {
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub title: Option<String>,
-    pub commands: Vec<CommandLink>,
-}
-
-// LSP v3.15 Command does not have a `tooltip` field, vscode supports one.
-#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
-pub struct CommandLink {
-    #[serde(flatten)]
-    pub command: lsp_types::Command,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub tooltip: Option<String>,
-}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 752dbf1452..e60337b8e8 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -510,7 +510,6 @@ fn on_request(
         .on::<lsp_ext::InlayHints>(handlers::handle_inlay_hints)?
         .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)?
         .on::<lsp_ext::ResolveCodeActionRequest>(handlers::handle_resolve_code_action)?
-        .on::<lsp_ext::HoverRequest>(handlers::handle_hover)?
         .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)?
         .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)?
         .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol)?
@@ -522,6 +521,7 @@ fn on_request(
         .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)?
         .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)?
         .on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)?
+        .on::<lsp_types::request::HoverRequest>(handlers::handle_hover)?
         .on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)?
         .on::<lsp_types::request::Rename>(handlers::handle_rename)?
         .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 3ff7797024..6acf80c582 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -12,14 +12,13 @@ use lsp_types::{
     CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
     CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
     CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight,
-    DocumentSymbol, FoldingRange, FoldingRangeParams, HoverContents, Location, MarkupContent,
-    MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensParams,
-    SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
-    TextDocumentIdentifier, Url, WorkspaceEdit,
+    DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location,
+    MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams,
+    SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult,
+    SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit,
 };
 use ra_ide::{
-    FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, RunnableKind, SearchScope,
-    TextEdit,
+    FileId, FilePosition, FileRange, Query, RangeInfo, RunnableKind, SearchScope, TextEdit,
 };
 use ra_prof::profile;
 use ra_project_model::TargetKind;
@@ -538,7 +537,7 @@ pub fn handle_signature_help(
 pub fn handle_hover(
     snap: GlobalStateSnapshot,
     params: lsp_types::HoverParams,
-) -> Result<Option<lsp_ext::Hover>> {
+) -> Result<Option<Hover>> {
     let _p = profile("handle_hover");
     let position = from_proto::file_position(&snap, params.text_document_position_params)?;
     let info = match snap.analysis().hover(position)? {
@@ -547,18 +546,14 @@ pub fn handle_hover(
     };
     let line_index = snap.analysis.file_line_index(position.file_id)?;
     let range = to_proto::range(&line_index, info.range);
-    let hover = lsp_ext::Hover {
-        hover: lsp_types::Hover {
-            contents: HoverContents::Markup(MarkupContent {
-                kind: MarkupKind::Markdown,
-                value: crate::markdown::format_docs(&info.info.to_markup()),
-            }),
-            range: Some(range),
-        },
-        actions: prepare_hover_actions(&snap, info.info.actions()),
+    let res = Hover {
+        contents: HoverContents::Markup(MarkupContent {
+            kind: MarkupKind::Markdown,
+            value: crate::markdown::format_docs(&info.info.to_markup()),
+        }),
+        range: Some(range),
     };
-
-    Ok(Some(hover))
+    Ok(Some(res))
 }
 
 pub fn handle_prepare_rename(
@@ -929,13 +924,24 @@ pub fn handle_code_lens_resolve(
                     _ => vec![],
                 };
 
-            let title = implementation_title(locations.len());
-            let cmd = show_references_command(
+            let title = if locations.len() == 1 {
+                "1 implementation".into()
+            } else {
+                format!("{} implementations", locations.len())
+            };
+
+            // We cannot use the 'editor.action.showReferences' command directly
+            // because that command requires vscode types which we convert in the handler
+            // on the client side.
+            let cmd = Command {
                 title,
-                &lens_params.text_document_position_params.text_document.uri,
-                code_lens.range.start,
-                locations,
-            );
+                command: "rust-analyzer.showReferences".into(),
+                arguments: Some(vec![
+                    to_value(&lens_params.text_document_position_params.text_document.uri).unwrap(),
+                    to_value(code_lens.range.start).unwrap(),
+                    to_value(locations).unwrap(),
+                ]),
+            };
             Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None })
         }
         None => Ok(CodeLens {
@@ -1139,78 +1145,3 @@ pub fn handle_semantic_tokens_range(
     let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
     Ok(Some(semantic_tokens.into()))
 }
-
-fn implementation_title(count: usize) -> String {
-    if count == 1 {
-        "1 implementation".into()
-    } else {
-        format!("{} implementations", count)
-    }
-}
-
-fn show_references_command(
-    title: String,
-    uri: &lsp_types::Url,
-    position: lsp_types::Position,
-    locations: Vec<lsp_types::Location>,
-) -> Command {
-    // We cannot use the 'editor.action.showReferences' command directly
-    // because that command requires vscode types which we convert in the handler
-    // on the client side.
-
-    Command {
-        title,
-        command: "rust-analyzer.showReferences".into(),
-        arguments: Some(vec![
-            to_value(uri).unwrap(),
-            to_value(position).unwrap(),
-            to_value(locations).unwrap(),
-        ]),
-    }
-}
-
-fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink {
-    lsp_ext::CommandLink { tooltip: Some(tooltip), command }
-}
-
-fn show_impl_command_link(
-    snap: &GlobalStateSnapshot,
-    position: &FilePosition,
-) -> Option<lsp_ext::CommandLinkGroup> {
-    if snap.config.hover.implementations {
-        if let Some(nav_data) = snap.analysis().goto_implementation(*position).unwrap_or(None) {
-            let uri = to_proto::url(snap, position.file_id).ok()?;
-            let line_index = snap.analysis().file_line_index(position.file_id).ok()?;
-            let position = to_proto::position(&line_index, position.offset);
-            let locations: Vec<_> = nav_data
-                .info
-                .iter()
-                .filter_map(|it| to_proto::location(snap, it.file_range()).ok())
-                .collect();
-            let title = implementation_title(locations.len());
-            let command = show_references_command(title, &uri, position, locations);
-
-            return Some(lsp_ext::CommandLinkGroup {
-                commands: vec![to_command_link(command, "Go to implementations".into())],
-                ..Default::default()
-            });
-        }
-    }
-    None
-}
-
-fn prepare_hover_actions(
-    snap: &GlobalStateSnapshot,
-    actions: &[HoverAction],
-) -> Vec<lsp_ext::CommandLinkGroup> {
-    if snap.config.hover.none() || !snap.config.client_caps.hover_actions {
-        return Vec::new();
-    }
-
-    actions
-        .iter()
-        .filter_map(|it| match it {
-            HoverAction::Implementaion(position) => show_impl_command_link(snap, position),
-        })
-        .collect()
-}
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index a0847dad3a..7f7940d0b6 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -467,41 +467,3 @@ interface InlayHint {
     label: string,
 }
 ```
-
-## Hover Actions
-
-**Client Capability:** `{ "hoverActions": boolean }`
-
-If this capability is set, `Hover` request returned from the server might contain an additional field, `actions`:
-
-```typescript
-interface Hover {
-    ...
-    actions?: CommandLinkGroup[];
-}
-
-interface CommandLink extends Command {
-    /**
-     * A tooltip for the command, when represented in the UI.
-     */
-    tooltip?: string;
-}
-
-interface CommandLinkGroup {
-    title?: string;
-    commands: CommandLink[];
-}
-```
-
-Such actions on the client side are appended to a hover bottom as command links:
-```
-  +-----------------------------+
-  | Hover content               |
-  |                             |
-  +-----------------------------+
-  | _Action1_ | _Action2_       |  <- first group, no TITLE
-  +-----------------------------+
-  | TITLE _Action1_ | _Action2_ |  <- second group
-  +-----------------------------+
-  ...
-```
\ No newline at end of file
diff --git a/editors/code/package.json b/editors/code/package.json
index b9c57db3bc..30ab7ba4a9 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -462,27 +462,17 @@
                     "default": true
                 },
                 "rust-analyzer.lens.run": {
-                    "markdownDescription": "Whether to show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
+                    "markdownDescription": "Whether to show Run lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
                     "type": "boolean",
                     "default": true
                 },
                 "rust-analyzer.lens.debug": {
-                    "markdownDescription": "Whether to show `Debug` lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
+                    "markdownDescription": "Whether to show Debug lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
                     "type": "boolean",
                     "default": true
                 },
                 "rust-analyzer.lens.implementations": {
-                    "markdownDescription": "Whether to show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
-                    "type": "boolean",
-                    "default": true
-                },
-                "rust-analyzer.hoverActions.enable": {
-                    "description": "Whether to show HoverActions in Rust files.",
-                    "type": "boolean",
-                    "default": true
-                },
-                "rust-analyzer.hoverActions.implementations": {
-                    "markdownDescription": "Whether to show `Implementations` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.",
+                    "markdownDescription": "Whether to show Implementations lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
                     "type": "boolean",
                     "default": true
                 },
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 65ad573d8c..40ad1e3cd8 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -7,20 +7,6 @@ import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.pr
 import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed';
 import { assert } from './util';
 
-function renderCommand(cmd: ra.CommandLink) {
-    return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip!}')`;
-}
-
-function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownString {
-    const text = actions.map(group =>
-        (group.title ? (group.title + " ") : "") + group.commands.map(renderCommand).join(' | ')
-    ).join('___');
-
-    const result = new vscode.MarkdownString(text);
-    result.isTrusted = true;
-    return result;
-}
-
 export function createClient(serverPath: string, cwd: string): lc.LanguageClient {
     // '.' Is the fallback if no folder is open
     // TODO?: Workspace folders support Uri's (eg: file://test.txt).
@@ -49,23 +35,6 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient
                 if (res === undefined) throw new Error('busy');
                 return res;
             },
-            async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, _next: lc.ProvideHoverSignature) {
-                return client.sendRequest(lc.HoverRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(
-                    (result) => {
-                        const hover = client.protocol2CodeConverter.asHover(result);
-                        if (hover) {
-                            const actions = (<any>result).actions;
-                            if (actions) {
-                                hover.contents.push(renderHoverActions(actions));
-                            }
-                        }
-                        return hover;
-                    },
-                    (error) => {
-                        client.logFailedRequest(lc.HoverRequest.type, error);
-                        return Promise.resolve(null);
-                    });
-            },
             // Using custom handling of CodeActions where each code action is resloved lazily
             // That's why we are not waiting for any command or edits
             async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) {
@@ -160,7 +129,6 @@ class ExperimentalFeatures implements lc.StaticFeature {
         caps.snippetTextEdit = true;
         caps.codeActionGroup = true;
         caps.resolveCodeAction = true;
-        caps.hoverActions = true;
         capabilities.experimental = caps;
     }
     initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void {
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index d8f0037d4c..e8abf8284e 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -16,8 +16,10 @@ export class Config {
         "files",
         "highlighting",
         "updates.channel",
-        "lens", // works as lens.*
-        "hoverActions", // works as hoverActions.*
+        "lens.enable",
+        "lens.run",
+        "lens.debug",
+        "lens.implementations",
     ]
         .map(opt => `${this.rootSection}.${opt}`);
 
@@ -130,11 +132,4 @@ export class Config {
             implementations: this.get<boolean>("lens.implementations"),
         };
     }
-
-    get hoverActions() {
-        return {
-            enable: this.get<boolean>("hoverActions.enable"),
-            implementations: this.get<boolean>("hoverActions.implementations"),
-        };
-    }
 }
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index e16ea799ce..9793b926c2 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -90,15 +90,3 @@ export interface SsrParams {
     parseOnly: boolean;
 }
 export const ssr = new lc.RequestType<SsrParams, lc.WorkspaceEdit, void>('experimental/ssr');
-
-export interface CommandLink extends lc.Command {
-    /**
-     * A tooltip for the command, when represented in the UI.
-     */
-    tooltip?: string;
-}
-
-export interface CommandLinkGroup {
-    title?: string;
-    commands: CommandLink[];
-}


Test patch:
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs
index bcfa66ac95..e7a5182f03 100644
--- a/crates/ra_hir_def/src/test_db.rs
+++ b/crates/ra_hir_def/src/test_db.rs
@@ -6,7 +6,9 @@ use std::{
 };
 
 use hir_expand::db::AstDatabase;
-use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
+use ra_db::{
+    salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath, Upcast,
+};
 
 use crate::db::DefDatabase;
 
@@ -62,6 +64,14 @@ impl FileLoader for TestDB {
     fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
+
+    fn resolve_extern_path(
+        &self,
+        extern_id: ExternSourceId,
+        relative_path: &RelativePath,
+    ) -> Option<FileId> {
+        FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path)
+    }
 }
 
 impl TestDB {
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs
index fdf225f55b..765a2f6d18 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::{
     sync::{Arc, Mutex},
 };
 
-use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate};
+use ra_db::{salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath};
 
 #[salsa::database(
     ra_db::SourceDatabaseExtStorage,
@@ -47,4 +47,11 @@ impl FileLoader for TestDB {
     fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
+    fn resolve_extern_path(
+        &self,
+        anchor: ExternSourceId,
+        relative_path: &RelativePath,
+    ) -> Option<FileId> {
+        FileLoaderDelegate(self).resolve_extern_path(anchor, relative_path)
+    }
 }
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index e484968a09..21a3bdfd15 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -7,7 +7,9 @@ use std::{
 
 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId};
 use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink};
-use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
+use ra_db::{
+    salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase, Upcast,
+};
 use stdx::format_to;
 
 use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator};
@@ -76,6 +78,13 @@ impl FileLoader for TestDB {
     fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
+    fn resolve_extern_path(
+        &self,
+        extern_id: ra_db::ExternSourceId,
+        relative_path: &RelativePath,
+    ) -> Option<FileId> {
+        FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path)
+    }
 }
 
 impl TestDB {
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index e8778d419b..0c538a62d9 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() {
 }
 
 #[test]
-#[ignore]
 fn impl_trait() {
     assert_snapshot!(
         infer(r#"
@@ -1160,6 +1159,95 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
     );
 }
 
+#[test]
+fn simple_return_pos_impl_trait() {
+    mark::check!(lower_rpit);
+    assert_snapshot!(
+        infer(r#"
+trait Trait<T> {
+    fn foo(&self) -> T;
+}
+fn bar() -> impl Trait<u64> { loop {} }
+
+fn test() {
+    let a = bar();
+    a.foo();
+}
+"#),
+        @r###"
+    30..34 'self': &Self
+    72..83 '{ loop {} }': !
+    74..81 'loop {}': !
+    79..81 '{}': ()
+    95..130 '{     ...o(); }': ()
+    105..106 'a': impl Trait<u64>
+    109..112 'bar': fn bar() -> impl Trait<u64>
+    109..114 'bar()': impl Trait<u64>
+    120..121 'a': impl Trait<u64>
+    120..127 'a.foo()': u64
+    "###
+    );
+}
+
+#[test]
+fn more_return_pos_impl_trait() {
+    assert_snapshot!(
+        infer(r#"
+trait Iterator {
+    type Item;
+    fn next(&mut self) -> Self::Item;
+}
+trait Trait<T> {
+    fn foo(&self) -> T;
+}
+fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} }
+fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} }
+
+fn test() {
+    let (a, b) = bar();
+    a.next().foo();
+    b.foo();
+    let (c, d) = baz(1u128);
+    c.next().foo();
+    d.foo();
+}
+"#),
+        @r###"
+    50..54 'self': &mut Self
+    102..106 'self': &Self
+    185..196 '{ loop {} }': ({unknown}, {unknown})
+    187..194 'loop {}': !
+    192..194 '{}': ()
+    207..208 't': T
+    269..280 '{ loop {} }': ({unknown}, {unknown})
+    271..278 'loop {}': !
+    276..278 '{}': ()
+    292..414 '{     ...o(); }': ()
+    302..308 '(a, b)': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
+    303..304 'a': impl Iterator<Item = impl Trait<u32>>
+    306..307 'b': impl Trait<u64>
+    311..314 'bar': fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
+    311..316 'bar()': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
+    322..323 'a': impl Iterator<Item = impl Trait<u32>>
+    322..330 'a.next()': impl Trait<u32>
+    322..336 'a.next().foo()': u32
+    342..343 'b': impl Trait<u64>
+    342..349 'b.foo()': u64
+    359..365 '(c, d)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
+    360..361 'c': impl Iterator<Item = impl Trait<u128>>
+    363..364 'd': impl Trait<u128>
+    368..371 'baz': fn baz<u128>(u128) -> (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
+    368..378 'baz(1u128)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
+    372..377 '1u128': u128
+    384..385 'c': impl Iterator<Item = impl Trait<u128>>
+    384..392 'c.next()': impl Trait<u128>
+    384..398 'c.next().foo()': u128
+    404..405 'd': impl Trait<u128>
+    404..411 'd.foo()': u128
+    "###
+    );
+}
+
 #[test]
 fn dyn_trait() {
     assert_snapshot!(