Repository: rust-analyzer/rust-analyzer
Pull request #9026 (2021-05-27 19:13:20)

Complete modules in assoc item lists
bors r+


Patch:
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 72f0d9b5f7..c5cf803fd3 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -427,6 +427,10 @@ impl HirDisplay for Trait {
         write!(f, "trait {}", data.name)?;
         let def_id = GenericDefId::TraitId(self.id);
         write_generic_params(def_id, f)?;
+        if !data.bounds.is_empty() {
+            write!(f, ": ")?;
+            f.write_joined(&*data.bounds, " + ")?;
+        }
         write_where_clause(def_id, f)?;
         Ok(())
     }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 01b2de515a..1ecd2391b0 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -472,13 +472,27 @@ impl Module {
                     });
                 }
 
-                DefDiagnosticKind::UnresolvedImport { id, index } => {
-                    let file_id = id.file_id();
-                    let item_tree = id.item_tree(db.upcast());
-                    let import = &item_tree[id.value];
+                DefDiagnosticKind::UnresolvedImport { ast, index } => {
+                    let use_item = ast.to_node(db.upcast());
+                    let hygiene = Hygiene::new(db.upcast(), ast.file_id);
+                    let mut cur = 0;
+                    let mut tree = None;
+                    ModPath::expand_use_item(
+                        db.upcast(),
+                        InFile::new(ast.file_id, use_item),
+                        &hygiene,
+                        |_mod_path, use_tree, _is_glob, _alias| {
+                            if cur == *index {
+                                tree = Some(use_tree.clone());
+                            }
+
+                            cur += 1;
+                        },
+                    );
 
-                    let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
-                    sink.push(UnresolvedImport { file: file_id, node: AstPtr::new(&use_tree) });
+                    if let Some(tree) = tree {
+                        sink.push(UnresolvedImport { file: ast.file_id, node: AstPtr::new(&tree) });
+                    }
                 }
 
                 DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index a04f73352b..8bcac60ef5 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -141,6 +141,7 @@ pub struct TraitData {
     pub is_auto: bool,
     pub is_unsafe: bool,
     pub visibility: RawVisibility,
+    pub bounds: Box<[Interned<TypeBound>]>,
 }
 
 impl TraitData {
@@ -154,6 +155,7 @@ impl TraitData {
         let module_id = tr_loc.container;
         let container = AssocContainerId::TraitId(tr);
         let visibility = item_tree[tr_def.visibility].clone();
+        let bounds = tr_def.bounds.clone();
         let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
 
         let items = collect_items(
@@ -166,7 +168,7 @@ impl TraitData {
             100,
         );
 
-        Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility })
+        Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility, bounds })
     }
 
     pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index c4d20c416b..11767d100f 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -523,38 +523,21 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
     }
 }
 
+/// A desugared `use` import.
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Import {
+    pub path: Interned<ModPath>,
+    pub alias: Option<ImportAlias>,
     pub visibility: RawVisibilityId,
+    pub is_glob: bool,
+    /// AST ID of the `use` item this import was derived from. Note that many `Import`s can map to
+    /// the same `use` item.
     pub ast_id: FileAstId<ast::Use>,
-    pub use_tree: UseTree,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub struct UseTree {
-    pub index: Idx<ast::UseTree>,
-    kind: UseTreeKind,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub enum UseTreeKind {
-    /// ```
-    /// use path::to::Item;
-    /// use path::to::Item as Renamed;
-    /// use path::to::Trait as _;
-    /// ```
-    Single { path: Interned<ModPath>, alias: Option<ImportAlias> },
-
-    /// ```
-    /// use *;  // (invalid, but can occur in nested tree)
-    /// use path::*;
-    /// ```
-    Glob { path: Option<Interned<ModPath>> },
-
-    /// ```
-    /// use prefix::{self, Item, ...};
-    /// ```
-    Prefixed { prefix: Option<Interned<ModPath>>, list: Box<[UseTree]> },
+    /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`.
+    ///
+    /// This can be used to get the `UseTree` this `Import` corresponds to and allows emitting
+    /// precise diagnostics.
+    pub index: usize,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -661,6 +644,7 @@ pub struct Trait {
     pub generic_params: Interned<GenericParams>,
     pub is_auto: bool,
     pub is_unsafe: bool,
+    pub bounds: Box<[Interned<TypeBound>]>,
     pub items: Box<[AssocItem]>,
     pub ast_id: FileAstId<ast::Trait>,
 }
@@ -727,97 +711,6 @@ pub struct MacroDef {
     pub ast_id: FileAstId<ast::MacroDef>,
 }
 
-impl Import {
-    /// Maps a `UseTree` contained in this import back to its AST node.
-    pub fn use_tree_to_ast(
-        &self,
-        db: &dyn DefDatabase,
-        file_id: HirFileId,
-        index: Idx<ast::UseTree>,
-    ) -> ast::UseTree {
-        // Re-lower the AST item and get the source map.
-        // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
-        let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast());
-        let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
-        let hygiene = Hygiene::new(db.upcast(), file_id);
-        let (_, source_map) =
-            lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree");
-        source_map[index].clone()
-    }
-}
-
-impl UseTree {
-    /// Expands the `UseTree` into individually imported `ModPath`s.
-    pub fn expand(
-        &self,
-        mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, /* is_glob */ bool, Option<ImportAlias>),
-    ) {
-        self.expand_impl(None, &mut cb)
-    }
-
-    fn expand_impl(
-        &self,
-        prefix: Option<ModPath>,
-        cb: &mut dyn FnMut(
-            Idx<ast::UseTree>,
-            ModPath,
-            /* is_glob */ bool,
-            Option<ImportAlias>,
-        ),
-    ) {
-        fn concat_mod_paths(prefix: Option<ModPath>, path: &ModPath) -> Option<ModPath> {
-            match (prefix, &path.kind) {
-                (None, _) => Some(path.clone()),
-                (Some(mut prefix), PathKind::Plain) => {
-                    for segment in path.segments() {
-                        prefix.push_segment(segment.clone());
-                    }
-                    Some(prefix)
-                }
-                (Some(prefix), PathKind::Super(0)) => {
-                    // `some::path::self` == `some::path`
-                    if path.segments().is_empty() {
-                        Some(prefix)
-                    } else {
-                        None
-                    }
-                }
-                (Some(_), _) => None,
-            }
-        }
-
-        match &self.kind {
-            UseTreeKind::Single { path, alias } => {
-                if let Some(path) = concat_mod_paths(prefix, path) {
-                    cb(self.index, path, false, alias.clone());
-                }
-            }
-            UseTreeKind::Glob { path: Some(path) } => {
-                if let Some(path) = concat_mod_paths(prefix, path) {
-                    cb(self.index, path, true, None);
-                }
-            }
-            UseTreeKind::Glob { path: None } => {
-                if let Some(prefix) = prefix {
-                    cb(self.index, prefix, true, None);
-                }
-            }
-            UseTreeKind::Prefixed { prefix: additional_prefix, list } => {
-                let prefix = match additional_prefix {
-                    Some(path) => match concat_mod_paths(prefix, path) {
-                        Some(path) => Some(path),
-                        None => return,
-                    },
-                    None => prefix,
-                };
-                for tree in &**list {
-                    tree.expand_impl(prefix.clone(), cb);
-                }
-            }
-        }
-    }
-}
-
 macro_rules! impl_froms {
     ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
         $(
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index b83adec46a..b4389371fb 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -3,6 +3,7 @@
 use std::{collections::hash_map::Entry, mem, sync::Arc};
 
 use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId};
+use smallvec::SmallVec;
 use syntax::{
     ast::{self, ModuleItemOwner},
     SyntaxNode, WalkEvent,
@@ -19,10 +20,22 @@ fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
     FileItemTreeId { index, _p: PhantomData }
 }
 
+struct ModItems(SmallVec<[ModItem; 1]>);
+
+impl<T> From<T> for ModItems
+where
+    T: Into<ModItem>,
+{
+    fn from(t: T) -> Self {
+        ModItems(SmallVec::from_buf([t.into(); 1]))
+    }
+}
+
 pub(super) struct Ctx<'a> {
     db: &'a dyn DefDatabase,
     tree: ItemTree,
     hygiene: Hygiene,
+    file: HirFileId,
     source_ast_id_map: Arc<AstIdMap>,
     body_ctx: crate::body::LowerCtx<'a>,
     forced_visibility: Option<RawVisibilityId>,
@@ -34,6 +47,7 @@ impl<'a> Ctx<'a> {
             db,
             tree: ItemTree::default(),
             hygiene,
+            file,
             source_ast_id_map: db.ast_id_map(file),
             body_ctx: crate::body::LowerCtx::new(db, file),
             forced_visibility: None,
@@ -41,8 +55,11 @@ impl<'a> Ctx<'a> {
     }
 
     pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
-        self.tree.top_level =
-            item_owner.items().flat_map(|item| self.lower_mod_item(&item, false)).collect();
+        self.tree.top_level = item_owner
+            .items()
+            .flat_map(|item| self.lower_mod_item(&item, false))
+            .flat_map(|items| items.0)
+            .collect();
         self.tree
     }
 
@@ -54,6 +71,7 @@ impl<'a> Ctx<'a> {
                 _ => None,
             })
             .flat_map(|item| self.lower_mod_item(&item, false))
+            .flat_map(|items| items.0)
             .collect();
 
         // Non-items need to have their inner items collected.
@@ -80,7 +98,7 @@ impl<'a> Ctx<'a> {
         self.tree.data_mut()
     }
 
-    fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItem> {
+    fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> {
         // Collect inner items for 1-to-1-lowered items.
         match item {
             ast::Item::Struct(_)
@@ -111,28 +129,34 @@ impl<'a> Ctx<'a> {
         };
 
         let attrs = RawAttrs::new(self.db, item, &self.hygiene);
-        let item: ModItem = match item {
-            ast::Item::Struct(ast) => self.lower_struct(ast)?.into(),
-            ast::Item::Union(ast) => self.lower_union(ast)?.into(),
-            ast::Item::Enum(ast) => self.lower_enum(ast)?.into(),
-            ast::Item::Fn(ast) => self.lower_function(ast)?.into(),
-            ast::Item::TypeAlias(ast) => self.lower_type_alias(ast)?.into(),
-            ast::Item::Static(ast) => self.lower_static(ast)?.into(),
-            ast::Item::Const(ast) => self.lower_const(ast).into(),
-            ast::Item::Module(ast) => self.lower_module(ast)?.into(),
-            ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
-            ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
-            ast::Item::Use(ast) => self.lower_use(ast)?.into(),
-            ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
-            ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
-            ast::Item::MacroRules(ast) => self.lower_macro_rules(ast)?.into(),
-            ast::Item::MacroDef(ast) => self.lower_macro_def(ast)?.into(),
-            ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
+        let items = match item {
+            ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into),
+            ast::Item::Union(ast) => self.lower_union(ast).map(Into::into),
+            ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into),
+            ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into),
+            ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
+            ast::Item::Static(ast) => self.lower_static(ast).map(Into::into),
+            ast::Item::Const(ast) => Some(self.lower_const(ast).into()),
+            ast::Item::Module(ast) => self.lower_module(ast).map(Into::into),
+            ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into),
+            ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into),
+            ast::Item::Use(ast) => Some(ModItems(
+                self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(),
+            )),
+            ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
+            ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
+            ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into),
+            ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into),
+            ast::Item::ExternBlock(ast) => Some(self.lower_extern_block(ast).into()),
         };
 
-        self.add_attrs(item.into(), attrs.clone());
+        if !attrs.is_empty() {
+            for item in items.iter().flat_map(|items| &items.0) {
+                self.add_attrs((*item).into(), attrs.clone());
+            }
+        }
 
-        Some(item)
+        items
     }
 
     fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
@@ -166,10 +190,12 @@ impl<'a> Ctx<'a> {
                             },
                             ast::Item(item) => {
                                 // FIXME: This triggers for macro calls in expression/pattern/type position
-                                let mod_item = self.lower_mod_item(&item, true);
+                                let mod_items = self.lower_mod_item(&item, true);
                                 let current_block = block_stack.last();
-                                if let (Some(mod_item), Some(block)) = (mod_item, current_block) {
-                                        self.data().inner_items.entry(*block).or_default().push(mod_item);
+                                if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
+                                    if !mod_items.0.is_empty() {
+                                        self.data().inner_items.entry(*block).or_default().extend(mod_items.0.iter().copied());
+                                    }
                                 }
                             },
                             _ => {}
@@ -454,7 +480,10 @@ impl<'a> Ctx<'a> {
                 items: module
                     .item_list()
                     .map(|list| {
-                        list.items().flat_map(|item| self.lower_mod_item(&item, false)).collect()
+                        list.items()
+                            .flat_map(|item| self.lower_mod_item(&item, false))
+                            .flat_map(|items| items.0)
+                            .collect()
                     })
                     .unwrap_or_else(|| {
                         cov_mark::hit!(name_res_works_for_broken_modules);
@@ -474,6 +503,7 @@ impl<'a> Ctx<'a> {
             self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
         let is_auto = trait_def.auto_token().is_some();
         let is_unsafe = trait_def.unsafe_token().is_some();
+        let bounds = self.lower_type_bounds(trait_def);
         let items = trait_def.assoc_item_list().map(|list| {
             let db = self.db;
             self.with_inherited_visibility(visibility, |this| {
@@ -496,6 +526,7 @@ impl<'a> Ctx<'a> {
             generic_params,
             is_auto,
             is_unsafe,
+            bounds: bounds.into(),
             items: items.unwrap_or_default(),
             ast_id,
         };
@@ -530,13 +561,30 @@ impl<'a> Ctx<'a> {
         Some(id(self.data().impls.alloc(res)))
     }
 
-    fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Import>> {
+    fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> {
         let visibility = self.lower_visibility(use_item);
         let ast_id = self.source_ast_id_map.ast_id(use_item);
-        let (use_tree, _) = lower_use_tree(self.db, &self.hygiene, use_item.use_tree()?)?;
 
-        let res = Import { visibility, ast_id, use_tree };
-        Some(id(self.data().imports.alloc(res)))
+        // Every use item can expand to many `Import`s.
+        let mut imports = Vec::new();
+        let tree = self.tree.data_mut();
+        ModPath::expand_use_item(
+            self.db,
+            InFile::new(self.file, use_item.clone()),
+            &self.hygiene,
+            |path, _use_tree, is_glob, alias| {
+                imports.push(id(tree.imports.alloc(Import {
+                    path: Interned::new(path),
+                    alias,
+                    visibility,
+                    is_glob,
+                    ast_id,
+                    index: imports.len(),
+                })));
+            },
+        );
+
+        imports
     }
 
     fn lower_extern_crate(
@@ -836,81 +884,3 @@ fn lower_abi(abi: ast::Abi) -> Interned<str> {
         }
     }
 }
-
-struct UseTreeLowering<'a> {
-    db: &'a dyn DefDatabase,
-    hygiene: &'a Hygiene,
-    mapping: Arena<ast::UseTree>,
-}
-
-impl UseTreeLowering<'_> {
-    fn lower_use_tree(&mut self, tree: ast::UseTree) -> Option<UseTree> {
-        if let Some(use_tree_list) = tree.use_tree_list() {
-            let prefix = match tree.path() {
-                // E.g. use something::{{{inner}}};
-                None => None,
-                // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
-                // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
-                Some(path) => {
-                    match ModPath::from_src(self.db, path, &self.hygiene) {
-                        Some(it) => Some(it),
-                        None => return None, // FIXME: report errors somewhere
-                    }
-                }
-            };
-
-            let list =
-                use_tree_list.use_trees().filter_map(|tree| self.lower_use_tree(tree)).collect();
-
-            Some(
-                self.use_tree(
-                    UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
-                    tree,
-                ),
-            )
-        } else {
-            let is_glob = tree.star_token().is_some();
-            let path = match tree.path() {
-                Some(path) => Some(ModPath::from_src(self.db, path, &self.hygiene)?),
-                None => None,
-            };
-            let alias = tree.rename().map(|a| {
-                a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
-            });
-            if alias.is_some() && is_glob {
-                return None;
-            }
-
-            match (path, alias, is_glob) {
-                (path, None, true) => {
-                    if path.is_none() {
-                        cov_mark::hit!(glob_enum_group);
-                    }
-                    Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree))
-                }
-                // Globs can't be renamed
-                (_, Some(_), true) | (None, None, false) => None,
-                // `bla::{ as Name}` is invalid
-                (None, Some(_), false) => None,
-                (Some(path), alias, false) => Some(
-                    self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree),
-                ),
-            }
-        }
-    }
-
-    fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
-        let index = self.mapping.alloc(ast);
-        UseTree { index, kind }
-    }
-}
-
-pub(super) fn lower_use_tree(
-    db: &dyn DefDatabase,
-    hygiene: &Hygiene,
-    tree: ast::UseTree,
-) -> Option<(UseTree, Arena<ast::UseTree>)> {
-    let mut lowering = UseTreeLowering { db, hygiene, mapping: Arena::new() };
-    let tree = lowering.lower_use_tree(tree)?;
-    Some((tree, lowering.mapping))
-}
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index d1ee697cb5..9394a5de66 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -163,46 +163,21 @@ impl<'a> Printer<'a> {
         }
     }
 
-    fn print_use_tree(&mut self, use_tree: &UseTree) {
-        match &use_tree.kind {
-            UseTreeKind::Single { path, alias } => {
-                w!(self, "{}", path);
-                if let Some(alias) = alias {
-                    w!(self, " as {}", alias);
-                }
-            }
-            UseTreeKind::Glob { path } => {
-                if let Some(path) = path {
-                    w!(self, "{}::", path);
-                }
-                w!(self, "*");
-            }
-            UseTreeKind::Prefixed { prefix, list } => {
-                if let Some(prefix) = prefix {
-                    w!(self, "{}::", prefix);
-                }
-                w!(self, "{{");
-                for (i, tree) in list.iter().enumerate() {
-                    if i != 0 {
-                        w!(self, ", ");
-                    }
-                    self.print_use_tree(tree);
-                }
-                w!(self, "}}");
-            }
-        }
-    }
-
     fn print_mod_item(&mut self, item: ModItem) {
         self.print_attrs_of(item);
 
         match item {
             ModItem::Import(it) => {
-                let Import { visibility, use_tree, ast_id: _ } = &self.tree[it];
+                let Import { visibility, path, is_glob, alias, ast_id: _, index } = &self.tree[it];
                 self.print_visibility(*visibility);
-                w!(self, "use ");
-                self.print_use_tree(use_tree);
-                wln!(self, ";");
+                w!(self, "use {}", path);
+                if *is_glob {
+                    w!(self, "::*");
+                }
+                if let Some(alias) = alias {
+                    w!(self, " as {}", alias);
+                }
+                wln!(self, ";  // {}", index);
             }
             ModItem::ExternCrate(it) => {
                 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
@@ -345,6 +320,7 @@ impl<'a> Printer<'a> {
                     visibility,
                     is_auto,
                     is_unsafe,
+                    bounds,
                     items,
                     generic_params,
                     ast_id: _,
@@ -358,6 +334,10 @@ impl<'a> Printer<'a> {
                 }
                 w!(self, "trait {}", name);
                 self.print_generic_params(generic_params);
+                if !bounds.is_empty() {
+                    w!(self, ": ");
+                    self.print_type_bounds(bounds);
+                }
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for item in &**items {
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 4296c63045..3ea4729080 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -17,7 +17,6 @@ use hir_expand::{
 };
 use hir_expand::{InFile, MacroCallLoc};
 use itertools::Itertools;
-use la_arena::Idx;
 use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::ast;
 
@@ -144,7 +143,7 @@ impl PartialResolvedImport {
 
 #[derive(Clone, Debug, Eq, PartialEq)]
 enum ImportSource {
-    Import { id: ItemTreeId<item_tree::Import>, use_tree: Idx<ast::UseTree> },
+    Import(ItemTreeId<item_tree::Import>),
     ExternCrate(ItemTreeId<item_tree::ExternCrate>),
 }
 
@@ -166,26 +165,20 @@ impl Import {
         krate: CrateId,
         tree: &ItemTree,
         id: ItemTreeId<item_tree::Import>,
-    ) -> Vec<Self> {
+    ) -> Self {
         let it = &tree[id.value];
         let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
         let visibility = &tree[it.visibility];
-        let is_prelude = attrs.by_key("prelude_import").exists();
-
-        let mut res = Vec::new();
-        it.use_tree.expand(|idx, path, is_glob, alias| {
-            res.push(Self {
-                path: Interned::new(path), // FIXME this makes little sense
-                alias,
-                visibility: visibility.clone(),
-                is_glob,
-                is_prelude,
-                is_extern_crate: false,
-                is_macro_use: false,
-                source: ImportSource::Import { id, use_tree: idx },
-            });
-        });
-        res
+        Self {
+            path: it.path.clone(),
+            alias: it.alias.clone(),
+            visibility: visibility.clone(),
+            is_glob: it.is_glob,
+            is_prelude: attrs.by_key("prelude_import").exists(),
+            is_extern_crate: false,
+            is_macro_use: false,
+            source: ImportSource::Import(id),
+        }
     }
 
     fn from_extern_crate(
@@ -1137,8 +1130,11 @@ impl DefCollector<'_> {
         }
 
         for directive in &self.unresolved_imports {
-            if let ImportSource::Import { id: import, use_tree } = &directive.import.source {
-                match (directive.import.path.segments().first(), &directive.import.path.kind) {
+            if let ImportSource::Import(import) = &directive.import.source {
+                let item_tree = import.item_tree(self.db);
+                let import_data = &item_tree[import.value];
+
+                match (import_data.path.segments().first(), &import_data.path.kind) {
                     (Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => {
                         if diagnosed_extern_crates.contains(krate) {
                             continue;
@@ -1149,8 +1145,8 @@ impl DefCollector<'_> {
 
                 self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
                     directive.module_id,
-                    *import,
-                    *use_tree,
+                    InFile::new(import.file_id(), import_data.ast_id),
+                    import_data.index,
                 ));
             }
         }
@@ -1226,20 +1222,16 @@ impl ModCollector<'_, '_> {
             match item {
                 ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs),
                 ModItem::Import(import_id) => {
-                    let module_id = self.module_id;
-                    let imports = Import::from_use(
-                        self.def_collector.db,
-                        krate,
-                        &self.item_tree,
-                        ItemTreeId::new(self.file_id, import_id),
-                    );
-                    self.def_collector.unresolved_imports.extend(imports.into_iter().map(
-                        |import| ImportDirective {
-                            module_id,
-                            import,
-                            status: PartialResolvedImport::Unresolved,
-                        },
-                    ));
+                    self.def_collector.unresolved_imports.push(ImportDirective {
+                        module_id: self.module_id,
+                        import: Import::from_use(
+                            self.def_collector.db,
+                            krate,
+                            &self.item_tree,
+                            ItemTreeId::new(self.file_id, import_id),
+                        ),
+                        status: PartialResolvedImport::Unresolved,
+                    })
                 }
                 ModItem::ExternCrate(import_id) => {
                     self.def_collector.unresolved_imports.push(ImportDirective {
diff --git a/crates/hir_def/src/nameres/diagnostics.rs b/crates/hir_def/src/nameres/diagnostics.rs
index 57c36c3c6c..8f2f0ff9f5 100644
--- a/crates/hir_def/src/nameres/diagnostics.rs
+++ b/crates/hir_def/src/nameres/diagnostics.rs
@@ -2,15 +2,9 @@
 
 use cfg::{CfgExpr, CfgOptions};
 use hir_expand::MacroCallKind;
-use la_arena::Idx;
 use syntax::ast;
 
-use crate::{
-    item_tree::{self, ItemTreeId},
-    nameres::LocalModuleId,
-    path::ModPath,
-    AstId,
-};
+use crate::{nameres::LocalModuleId, path::ModPath, AstId};
 
 #[derive(Debug, PartialEq, Eq)]
 pub enum DefDiagnosticKind {
@@ -18,7 +12,7 @@ pub enum DefDiagnosticKind {
 
     UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
 
-    UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> },
+    UnresolvedImport { ast: AstId<ast::Use>, index: usize },
 
     UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions },
 
@@ -59,10 +53,10 @@ impl DefDiagnostic {
 
     pub(super) fn unresolved_import(
         container: LocalModuleId,
-        id: ItemTreeId<item_tree::Import>,
-        index: Idx<ast::UseTree>,
+        ast: AstId<ast::Use>,
+        index: usize,
     ) -> Self {
-        Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } }
+        Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { ast, index } }
     }
 
     pub(super) fn unconfigured_code(
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 16440041dc..d9ec03d2da 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -14,7 +14,10 @@ use hir_expand::{
 };
 use syntax::ast;
 
-use crate::type_ref::{TypeBound, TypeRef};
+use crate::{
+    type_ref::{TypeBound, TypeRef},
+    InFile,
+};
 
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct ModPath {
@@ -53,7 +56,8 @@ impl Display for ImportAlias {
 
 impl ModPath {
     pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
-        lower::convert_path(db, None, path, hygiene)
+        let ctx = LowerCtx::with_hygiene(db, hygiene);
+        lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone())
     }
 
     pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
@@ -66,6 +70,18 @@ impl ModPath {
         ModPath { kind, segments: Vec::new() }
     }
 
+    /// Calls `cb` with all paths, represented by this use item.
+    pub fn expand_use_item(
+        db: &dyn DefDatabase,
+        item_src: InFile<ast::Use>,
+        hygiene: &Hygiene,
+        mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
+    ) {
+        if let Some(tree) = item_src.value.use_tree() {
+            lower::lower_use_tree(db, None, tree, hygiene, &mut cb);
+        }
+    }
+
     pub fn segments(&self) -> &[Name] {
         &self.segments
     }
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index f6220aa928..54ede73939 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -15,7 +15,7 @@ use crate::{
     type_ref::{LifetimeRef, TypeBound, TypeRef},
 };
 
-pub(super) use lower_use::convert_path;
+pub(super) use lower_use::lower_use_tree;
 
 /// Converts an `ast::Path` to `Path`. Works with use trees.
 /// It correctly handles `$crate` based path from macro call.
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs
index 0ee406f63a..ee80e3df3c 100644
--- a/crates/hir_def/src/path/lower/lower_use.rs
+++ b/crates/hir_def/src/path/lower/lower_use.rs
@@ -4,15 +4,68 @@
 use std::iter;
 
 use either::Either;
-use hir_expand::hygiene::Hygiene;
-use syntax::{ast, AstNode};
+use hir_expand::{hygiene::Hygiene, name::AsName};
+use syntax::ast::{self, NameOwner};
 
 use crate::{
     db::DefDatabase,
-    path::{ModPath, PathKind},
+    path::{ImportAlias, ModPath, PathKind},
 };
 
-pub(crate) fn convert_path(
+pub(crate) fn lower_use_tree(
+    db: &dyn DefDatabase,
+    prefix: Option<ModPath>,
+    tree: ast::UseTree,
+    hygiene: &Hygiene,
+    cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option<ImportAlias>),
+) {
+    if let Some(use_tree_list) = tree.use_tree_list() {
+        let prefix = match tree.path() {
+            // E.g. use something::{{{inner}}};
+            None => prefix,
+            // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
+            // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
+            Some(path) => match convert_path(db, prefix, path, hygiene) {
+                Some(it) => Some(it),
+                None => return, // FIXME: report errors somewhere
+            },
+        };
+        for child_tree in use_tree_list.use_trees() {
+            lower_use_tree(db, prefix.clone(), child_tree, hygiene, cb);
+        }
+    } else {
+        let alias = tree.rename().map(|a| {
+            a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
+        });
+        let is_glob = tree.star_token().is_some();
+        if let Some(ast_path) = tree.path() {
+            // Handle self in a path.
+            // E.g. `use something::{self, <...>}`
+            if ast_path.qualifier().is_none() {
+                if let Some(segment) = ast_path.segment() {
+                    if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
+                        if let Some(prefix) = prefix {
+                            cb(prefix, &tree, false, alias);
+                            return;
+                        }
+                    }
+                }
+            }
+            if let Some(path) = convert_path(db, prefix, ast_path, hygiene) {
+                cb(path, &tree, is_glob, alias)
+            }
+        // FIXME: report errors somewhere
+        // We get here if we do
+        } else if is_glob {
+            cov_mark::hit!(glob_enum_group);
+            if let Some(prefix) = prefix {
+                cb(prefix, &tree, is_glob, None)
+            }
+        }
+    }
+}
+
+fn convert_path(
     db: &dyn DefDatabase,
     prefix: Option<ModPath>,
     path: ast::Path,
@@ -25,7 +78,7 @@ pub(crate) fn convert_path(
     };
 
     let segment = path.segment()?;
-    let mut mod_path = match segment.kind()? {
+    let res = match segment.kind()? {
         ast::PathSegmentKind::Name(name_ref) => {
             match hygiene.name_ref_to_name(db.upcast(), name_ref) {
                 Either::Left(name) => {
@@ -72,18 +125,5 @@ pub(crate) fn convert_path(
             return None;
         }
     };
-
-    // handle local_inner_macros :
-    // Basically, even in rustc it is quite hacky:
-    // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
-    // We follow what it did anyway :)
-    if mod_path.segments.len() == 1 && mod_path.kind == PathKind::Plain {
-        if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
-            if let Some(crate_id) = hygiene.local_inner_macros(db.upcast(), path) {
-                mod_path.kind = PathKind::DollarCrate(crate_id);
-            }
-        }
-    }
-
-    Some(mod_path)
+    Some(res)
 }
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 6cf5810fa4..dcac7c76d2 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -311,7 +311,6 @@ mod tests {
     ///  * a diagnostic is produced
     ///  * the first diagnostic fix trigger range touches the input cursor position
     ///  * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
-    #[track_caller]
     pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
         check_nth_fix(0, ra_fixture_before, ra_fixture_after);
     }
@@ -326,7 +325,6 @@ mod tests {
         }
     }
 
-    #[track_caller]
     fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
         let after = trim_indent(ra_fixture_after);
 
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 79c2f4a1ed..7f7f4d38af 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -42,83 +42,13 @@ pub struct HlRange {
 // Feature: Semantic Syntax Highlighting
 //
 // rust-analyzer highlights the code semantically.
-// For example, `Bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait.
-// rust-analyzer does not specify colors directly, instead it assigns a tag (like `struct`) and a set of modifiers (like `declaration`) to each token.
+// For example, `bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait.
+// rust-analyzer does not specify colors directly, instead it assigns tag (like `struct`) and a set of modifiers (like `declaration`) to each token.
 // It's up to the client to map those to specific colors.
 //
 // The general rule is that a reference to an entity gets colored the same way as the entity itself.
 // We also give special modifier for `mut` and `&mut` local variables.
 //
-//
-// .Token Tags
-//
-// Rust-analyzer currently emits the following token tags:
-//
-// - For items:
-// +
-// [horizontal]
-// enum:: Emitted for enums.
-// function:: Emitted for free-standing functions.
-// macro:: Emitted for macros.
-// method:: Emitted for associated functions, also knowns as methods.
-// namespace:: Emitted for modules.
-// struct:: Emitted for structs.
-// trait:: Emitted for traits.
-// typeAlias:: Emitted for type aliases and `Self` in `impl`s.
-// union:: Emitted for unions.
-//
-// - For literals:
-// +
-// [horizontal]
-// boolean:: Emitted for the boolean literals `true` and `false`.
-// character:: Emitted for character literals.
-// number:: Emitted for numeric literals.
-// string:: Emitted for string literals.
-// escapeSequence:: Emitted for escaped sequences inside strings like `\n`.
-// formatSpecifier:: Emitted for format specifiers `{:?}` in `format!`-like macros.
-//
-// - For operators:
-// +
-// [horizontal]
-// operator:: Emitted for general operators.
-// arithmetic:: Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`.
-// bitwise:: Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`.
-// comparison:: Emitted for the comparison operators `>`, `<`, `==`, `>=`, `<=`, `!=`.
-// logical:: Emitted for the logical operators `||`, `&&`, `!`.
-//
-// - For punctuation:
-// +
-// [horizontal]
-// punctuation:: Emitted for general punctuation.
-// angle:: Emitted for `<>` angle brackets.
-// brace:: Emitted for `{}` braces.
-// bracket:: Emitted for `[]` brackets.
-// parenthesis:: Emitted for `()` parentheses.
-// colon:: Emitted for the `:` token.
-// comma:: Emitted for the `,` token.
-// dot:: Emitted for the `.` token.
-// Semi:: Emitted for the `;` token.
-//
-// //-
-//
-// [horizontal]
-// attribute:: Emitted for attributes.
-// builtinType:: Emitted for builtin types like `u32`, `str` and `f32`.
-// comment:: Emitted for comments.
-// constParameter:: Emitted for const parameters.
-// enumMember:: Emitted for enum variants.
-// generic:: Emitted for generic tokens that have no mapping.
-// keyword:: Emitted for keywords.
-// label:: Emitted for labels.
-// lifetime:: Emitted for lifetimes.
-// parameter:: Emitted for non-self function parameters.
-// property:: Emitted for struct and union fields.
-// selfKeyword:: Emitted for the self function parameter and self path-specifier.
-// typeParameter:: Emitted for type parameters.
-// unresolvedReference:: Emitted for unresolved references, names that rust-analyzer can't find the definition of.
-// variable:: Emitted for locals, constants and statics.
-//
-//
 // .Token Modifiers
 //
 // Token modifiers allow to style some elements in the source code more precisely.
@@ -126,10 +56,10 @@ pub struct HlRange {
 // Rust-analyzer currently emits the following token modifiers:
 //
 // [horizontal]
+// associated:: Emitted for associated items.
 // async:: Emitted for async functions and the `async` and `await` keywords.
 // attribute:: Emitted for tokens inside attributes.
 // callable:: Emitted for locals whose types implements one of the `Fn*` traits.
-// constant:: Emitted for consts.
 // consuming:: Emitted for locals that are being consumed when use in a function call.
 // controlFlow:: Emitted for control-flow related tokens, this includes the `?` operator.
 // declaration:: Emitted for names of definitions, like `foo` in `fn foo() {}`.
@@ -138,7 +68,7 @@ pub struct HlRange {
 // intraDocLink:: Emitted for intra doc links in doc-strings.
 // library:: Emitted for items that are defined outside of the current crate.
 // mutable:: Emitted for mutable locals and statics.
-// static:: Emitted for "static" functions, also known as functions that do not take a `self` param, as well as statics and consts.
+// static:: Emitted for "static" functions, also known as functions that do not take a `self` param.
 // trait:: Emitted for associated trait items.
 // unsafe:: Emitted for unsafe operations, like unsafe function calls, as well as the `unsafe` token.
 //
diff --git a/crates/ide_completion/src/completions/macro_in_item_position.rs b/crates/ide_completion/src/completions/macro_in_item_position.rs
index c5e3775000..ec57aee30e 100644
--- a/crates/ide_completion/src/completions/macro_in_item_position.rs
+++ b/crates/ide_completion/src/completions/macro_in_item_position.rs
@@ -2,6 +2,7 @@
 
 use crate::{CompletionContext, Completions};
 
+// Ideally this should be removed and moved into `(un)qualified_path` respectively
 pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
     // Show only macros in top level.
     if !ctx.is_new_item {
@@ -12,6 +13,10 @@ pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl
         if let hir::ScopeDef::MacroDef(mac) = res {
             acc.add_macro(ctx, Some(name.to_string()), mac);
         }
+        // FIXME: This should be done in qualified_path/unqualified_path instead?
+        if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
+            acc.add_resolution(ctx, name.to_string(), &res);
+        }
     })
 }
 
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index c16bb215f7..7a0e1ead3f 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -7,7 +7,7 @@ use syntax::AstNode;
 use crate::{CompletionContext, Completions};
 
 pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
-    if ctx.is_path_disallowed() {
+    if ctx.is_path_disallowed() || ctx.expects_item() {
         return;
     }
     let path = match &ctx.path_qual {
@@ -20,13 +20,16 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
         None => return,
     };
     let context_module = ctx.scope.module();
-    if ctx.expects_item() || ctx.expects_assoc_item() {
+    if ctx.expects_assoc_item() {
         if let PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
             let module_scope = module.scope(ctx.db, context_module);
             for (name, def) in module_scope {
                 if let ScopeDef::MacroDef(macro_def) = def {
                     acc.add_macro(ctx, Some(name.to_string()), macro_def);
                 }
+                if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
+                    acc.add_resolution(ctx, name.to_string(), &def);
+                }
             }
         }
         return;
@@ -614,24 +617,43 @@ fn main() { let _ = crate::$0 }
     }
 
     #[test]
-    fn completes_qualified_macros_in_impl() {
+    fn completes_in_assoc_item_list() {
         check(
             r#"
 #[macro_export]
 macro_rules! foo { () => {} }
+mod bar {}
 
 struct MyStruct {}
-
 impl MyStruct {
     crate::$0
 }
 "#,
             expect![[r##"
+                md bar
                 ma foo! #[macro_export] macro_rules! foo
             "##]],
         );
     }
 
+    #[test]
+    #[ignore] // FIXME doesn't complete anything atm
+    fn completes_in_item_list() {
+        check(
+            r#"
+struct MyStruct {}
+macro_rules! foo {}
+mod bar {}
+
+crate::$0
+"#,
+            expect![[r#"
+                md bar
+                ma foo! macro_rules! foo
+            "#]],
+        )
+    }
+
     #[test]
     fn test_super_super_completion() {
         check(
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index cbac882407..c901b358b2 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -9,14 +9,17 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
     if !ctx.is_trivial_path {
         return;
     }
-    if ctx.is_path_disallowed() {
+    if ctx.is_path_disallowed() || ctx.expects_item() {
         return;
     }
-    if ctx.expects_item() || ctx.expects_assoc_item() {
+    if ctx.expects_assoc_item() {
         ctx.scope.process_all_names(&mut |name, def| {
             if let ScopeDef::MacroDef(macro_def) = def {
                 acc.add_macro(ctx, Some(name.to_string()), macro_def);
             }
+            if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
+                acc.add_resolution(ctx, name.to_string(), &def);
+            }
         });
         return;
     }
@@ -672,19 +675,39 @@ impl My$0
     }
 
     #[test]
-    fn only_completes_macros_in_assoc_item_list() {
+    fn completes_in_assoc_item_list() {
         check(
             r#"
-struct MyStruct {}
 macro_rules! foo {}
+mod bar {}
 
+struct MyStruct {}
 impl MyStruct {
     $0
 }
 "#,
             expect![[r#"
+                md bar
                 ma foo! macro_rules! foo
             "#]],
         )
     }
+
+    // FIXME: The completions here currently come from `macro_in_item_position`, but they shouldn't
+    #[test]
+    fn completes_in_item_list() {
+        check(
+            r#"
+struct MyStruct {}
+macro_rules! foo {}
+mod bar {}
+
+$0
+"#,
+            expect![[r#"
+                md bar
+                ma foo!(…) macro_rules! foo
+            "#]],
+        )
+    }
 }
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index ed289d5611..19e42ba432 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -62,7 +62,6 @@ pub(crate) fn determine_location(tok: SyntaxToken) -> Option<ImmediateLocation>
             ast::SourceFile(_it) => ImmediateLocation::ItemList,
             ast::ItemList(_it) => ImmediateLocation::ItemList,
             ast::RefExpr(_it) => ImmediateLocation::RefExpr,
-            ast::RefPat(_it) => ImmediateLocation::RefExpr,
             ast::RecordField(_it) => ImmediateLocation::RecordField,
             ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) {
                 Some(IMPL) => ImmediateLocation::Impl,
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index db216d951f..6129af95fc 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -46,7 +46,7 @@ define_semantic_token_types![
     (BRACE, "brace"),
     (BRACKET, "bracket"),
     (BUILTIN_TYPE, "builtinType"),
-    (CHAR, "character"),
+    (CHAR_LITERAL, "characterLiteral"),
     (COLON, "colon"),
     (COMMA, "comma"),
     (COMPARISON, "comparison"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 6d18d0ffc1..ca95139284 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -466,7 +466,7 @@ fn semantic_token_type_and_modifiers(
         HlTag::BoolLiteral => semantic_tokens::BOOLEAN,
         HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE,
         HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER,
-        HlTag::CharLiteral => semantic_tokens::CHAR,
+        HlTag::CharLiteral => semantic_tokens::CHAR_LITERAL,
         HlTag::Comment => lsp_types::SemanticTokenType::COMMENT,
         HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
         HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 11a3dd04e8..fbe2ce1c93 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -25,21 +25,15 @@ rust-analyzer supports clangd's extension for opting into UTF-8 as the coordinat
 
 https://clangd.llvm.org/extensions.html#utf-8-offsets
 
-## Configuration in `initializationOptions`
-
-**Issue:** https://github.com/microsoft/language-server-protocol/issues/567
-
-The `initializationOptions` filed of the `InitializeParams` of the initialization request should contain `"rust-analyzer"` section of the configuration.
-
-`rust-analyzer` normally sends a `"workspace/configuration"` request with `{ "items": ["rust-analyzer"] }` payload.
-However, the server can't do this during initialization.
-At the same time some essential configuration parameters are needed early on, before servicing requests.
-For this reason, we ask that `initializationOptions` contains the configuration, as if the server did make a `"workspace/configuration"` request.
+## `initializationOptions`
 
+For `initializationOptions`, `rust-analyzer` expects `"rust-analyzer"` section of the configuration.
+That is, `rust-analyzer` usually sends `"workspace/configuration"` request with `{ "items": ["rust-analyzer"] }` payload.
+`initializationOptions` should contain the same data that would be in the first item of the result.
 If a language client does not know about `rust-analyzer`'s configuration options it can get sensible defaults by doing any of the following:
  * Not sending `initializationOptions`
- * Sending `"initializationOptions": null`
- * Sending `"initializationOptions": {}`
+ * Send `"initializationOptions": null`
+ * Send `"initializationOptions": {}`
 
 ## Snippet `TextEdit`
 
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index 3a67294c5e..7ac9ae5b86 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -67,11 +67,7 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
 fn dist_server(release_channel: &str) -> Result<()> {
     let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
     let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "thin");
-
-    // Uncomment to enable debug info for releases. Note that:
-    //   * debug info is split on windows and macs, so it does nothing for those platforms,
-    //   * on Linux, this blows up the binary size from 8MB to 43MB, which is unreasonable.
-    // let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");
+    let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");
 
     let target = get_target();
     if target.contains("-linux-gnu") || target.contains("-linux-musl") {


Test patch:
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index b362add5c9..6407871b50 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -26,8 +26,6 @@ use globs::*;
 
 /// docs on import
 use crate::{A, B};
-
-use a::{c, d::{e}};
         "#,
         expect![[r##"
             #![doc = " file comment"]  // AttrId { is_doc_comment: true, ast_index: 0 }
@@ -38,14 +36,19 @@ use a::{c, d::{e}};
 
             pub(super) extern crate bli;
 
-            pub use crate::path::{nested, items as renamed, Trait as _};
+            pub use crate::path::nested;  // 0
+
+            pub use crate::path::items as renamed;  // 1
 
-            pub(self) use globs::*;
+            pub use crate::path::Trait as _;  // 2
+
+            pub(self) use globs::*;  // 0
 
             #[doc = " docs on import"]  // AttrId { is_doc_comment: true, ast_index: 0 }
-            pub(self) use crate::{A, B};
+            pub(self) use crate::A;  // 0
 
-            pub(self) use a::{c, d::{e}};
+            #[doc = " docs on import"]  // AttrId { is_doc_comment: true, ast_index: 0 }
+            pub(self) use crate::B;  // 1
         "##]],
     );
 }
@@ -180,7 +183,7 @@ trait Tr: SuperTrait + 'lifetime {
                 _: (),
             ) -> ();
 
-            pub(self) trait Tr<Self>
+            pub(self) trait Tr<Self>: SuperTrait + 'lifetime
             where
                 Self: SuperTrait,
                 Self: 'lifetime
@@ -215,7 +218,7 @@ mod outline;
             #[doc = " outer"]  // AttrId { is_doc_comment: true, ast_index: 0 }
             #[doc = " inner"]  // AttrId { is_doc_comment: true, ast_index: 1 }
             pub(self) mod inline {
-                pub(self) use super::*;
+                pub(self) use super::*;  // 0
 
                 // flags = 0x2
                 pub(self) fn fn_in_module() -> ();
@@ -350,7 +353,7 @@ trait Tr<'a, T: 'a>: Super {}
             pub(self) union Union<'a, T, const U: u8> {
             }
 
-            pub(self) trait Tr<'a, Self, T>
+            pub(self) trait Tr<'a, Self, T>: Super
             where
                 Self: Super,
                 T: 'a
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index a9c1e13e2f..6c357c915b 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -278,11 +278,9 @@ impl TestDB {
                         let node = ast.to_node(self.upcast());
                         (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedExternCrate")
                     }
-                    DefDiagnosticKind::UnresolvedImport { id, .. } => {
-                        let item_tree = id.item_tree(self.upcast());
-                        let import = &item_tree[id.value];
-                        let node = InFile::new(id.file_id(), import.ast_id).to_node(self.upcast());
-                        (InFile::new(id.file_id(), node.syntax().clone()), "UnresolvedImport")
+                    DefDiagnosticKind::UnresolvedImport { ast, .. } => {
+                        let node = ast.to_node(self.upcast());
+                        (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedImport")
                     }
                     DefDiagnosticKind::UnconfiguredCode { ast, .. } => {
                         let node = ast.to_node(self.upcast());