Repository: rust-analyzer/rust-analyzer
Pull request #8048 (2021-03-16 08:48:23)

Fix missing unresolved macro diagnostic in function body
This was an issue I found while working on https://github.com/rust-analyzer/rust-analyzer/pull/7970.

**Reproduction:**
1. Call a non-existent macro in a function body.
```
fn main() {
  foo!();
}
```
2. No diagnostics are raised. An unresolved-macro-call diagnostic is expected.
3. If the macro call is instead outside of the function body, this works as expected.

I believe this worked previously and regressed in https://github.com/rust-analyzer/rust-analyzer/pull/7805.

**Behavior prior to https://github.com/rust-analyzer/rust-analyzer/pull/7805:**
- The unresolved-macro-call diagnostic did not exist. Instead, a macro-error diagnostic would be raised with the text "could not resolve macro [path]".
- This was implemented by adding an error to the error sink (https://github.com/rust-analyzer/rust-analyzer/pull/7805/files#diff-50a326c5ae465bd9b31ee4310186380aa06e4fa1f6b41dbc0aed5bcc656a3cb8L657).
- The error was propagated through https://github.com/rust-analyzer/rust-analyzer/blob/1a82af3527e476d52410ff4dfd2fb4c57466abcb/crates/hir_def/src/body.rs#L123 eventually reaching https://github.com/rust-analyzer/rust-analyzer/blob/1a82af3527e476d52410ff4dfd2fb4c57466abcb/crates/hir_def/src/body/lower.rs#L569.

**Behavior after:**
- Instead of writing to the error sink, an UnresolvedMacro error is now returned (https://github.com/rust-analyzer/rust-analyzer/pull/7805/files#diff-50a326c5ae465bd9b31ee4310186380aa06e4fa1f6b41dbc0aed5bcc656a3cb8R631).
- The parent caller throws away the error as its function signature is `Option<MacroCallId>` (https://github.com/rust-analyzer/rust-analyzer/pull/7805/files#diff-50a326c5ae465bd9b31ee4310186380aa06e4fa1f6b41dbc0aed5bcc656a3cb8R604).
- We instead now reach the warn condition (https://github.com/rust-analyzer/rust-analyzer/blob/1a82af3527e476d52410ff4dfd2fb4c57466abcb/crates/hir_def/src/body.rs#L124) and no diagnostics are created in https://github.com/rust-analyzer/rust-analyzer/blob/1a82af3527e476d52410ff4dfd2fb4c57466abcb/crates/hir_def/src/body/lower.rs#L575.

**Fix:**
- Make sure to propagate the UnresolvedMacro error. Report the error using the new unresolved-macro-call diagnostic.



Patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index ae9dccce9d..32c7cf7ef7 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -13,7 +13,6 @@ env:
   CARGO_NET_RETRY: 10
   RUSTFLAGS: "-D warnings -W unreachable-pub"
   RUSTUP_MAX_RETRIES: 10
-  FETCH_DEPTH: 200
 
 jobs:
   dist-x86_64-pc-windows-msvc:
@@ -25,8 +24,6 @@ jobs:
     steps:
     - name: Checkout repository
       uses: actions/checkout@v2
-      with:
-        fetch-depth: ${{ env.FETCH_DEPTH }}
 
     # We need to disable the existing toolchain to avoid updating rust-docs
     # which takes a long time. The fastest way to do this is to rename the
@@ -60,8 +57,6 @@ jobs:
     steps:
     - name: Checkout repository
       uses: actions/checkout@v2
-      with:
-        fetch-depth: ${{ env.FETCH_DEPTH }}
 
     - name: Rename existing rust toolchain
       run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old
@@ -92,8 +87,6 @@ jobs:
     steps:
     - name: Checkout repository
       uses: actions/checkout@v2
-      with:
-        fetch-depth: ${{ env.FETCH_DEPTH }}
 
     - name: Install Rust toolchain
       uses: actions-rs/toolchain@v1
@@ -146,8 +139,6 @@ jobs:
 
     - name: Checkout repository
       uses: actions/checkout@v2
-      with:
-        fetch-depth: ${{ env.FETCH_DEPTH }}
 
     - name: Dist
       run: cargo xtask dist
@@ -168,8 +159,6 @@ jobs:
     steps:
     - name: Checkout repository
       uses: actions/checkout@v2
-      with:
-        fetch-depth: ${{ env.FETCH_DEPTH }}
 
     - name: Install Rust toolchain
       uses: actions-rs/toolchain@v1
@@ -204,8 +193,6 @@ jobs:
 
     - name: Checkout repository
       uses: actions/checkout@v2
-      with:
-        fetch-depth: ${{ env.FETCH_DEPTH }}
 
     - name: Install Rust toolchain
       uses: actions-rs/toolchain@v1
@@ -236,8 +223,6 @@ jobs:
 
     - name: Checkout repository
       uses: actions/checkout@v2
-      with:
-        fetch-depth: ${{ env.FETCH_DEPTH }}
 
     - name: Install Rust toolchain
       uses: actions-rs/toolchain@v1
@@ -274,8 +259,6 @@ jobs:
 
     - name: Checkout repository
       uses: actions/checkout@v2
-      with:
-        fetch-depth: ${{ env.FETCH_DEPTH }}
 
     - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
     - run: 'echo "HEAD_SHA: $HEAD_SHA"'
diff --git a/Cargo.lock b/Cargo.lock
index 2efae6a014..b2d009e38f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1811,9 +1811,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
 [[package]]
 name = "ungrammar"
-version = "1.12.2"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df6586a7c530704efe803d49a0b4132dcbdb4063163df39110548e6b5f2373ba"
+checksum = "84c629795d377049f2a1dc5f42cf505dc5ba8b28a5df0a03f4183a24480e4a6a"
 
 [[package]]
 name = "unicase"
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
deleted file mode 100644
index 44cdcc2963..0000000000
--- a/crates/hir/src/display.rs
+++ /dev/null
@@ -1,441 +0,0 @@
-//! HirDisplay implementations for various hir types.
-use hir_def::{
-    adt::VariantData,
-    generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
-    type_ref::{TypeBound, TypeRef},
-    AdtId, GenericDefId,
-};
-use hir_ty::display::{
-    write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
-    HirFormatter,
-};
-use syntax::ast::{self, NameOwner};
-
-use crate::{
-    Const, ConstParam, Enum, Field, Function, HasVisibility, Module, Static, Struct, Substs, Trait,
-    Type, TypeAlias, TypeParam, Union, Variant,
-};
-
-impl HirDisplay for Function {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        let data = f.db.function_data(self.id);
-        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
-        let qual = &data.qualifier;
-        if qual.is_default {
-            write!(f, "default ")?;
-        }
-        if qual.is_const {
-            write!(f, "const ")?;
-        }
-        if qual.is_async {
-            write!(f, "async ")?;
-        }
-        if qual.is_unsafe {
-            write!(f, "unsafe ")?;
-        }
-        if let Some(abi) = &qual.abi {
-            // FIXME: String escape?
-            write!(f, "extern \"{}\" ", abi)?;
-        }
-        write!(f, "fn {}", data.name)?;
-
-        write_generic_params(GenericDefId::FunctionId(self.id), f)?;
-
-        write!(f, "(")?;
-
-        let write_self_param = |ty: &TypeRef, f: &mut HirFormatter| match ty {
-            TypeRef::Path(p) if p.is_self_type() => write!(f, "self"),
-            TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner,TypeRef::Path(p) if p.is_self_type()) =>
-            {
-                write!(f, "&")?;
-                if let Some(lifetime) = lifetime {
-                    write!(f, "{} ", lifetime.name)?;
-                }
-                if let hir_def::type_ref::Mutability::Mut = mut_ {
-                    write!(f, "mut ")?;
-                }
-                write!(f, "self")
-            }
-            _ => {
-                write!(f, "self: ")?;
-                ty.hir_fmt(f)
-            }
-        };
-
-        let mut first = true;
-        for (param, type_ref) in self.assoc_fn_params(f.db).into_iter().zip(&data.params) {
-            if !first {
-                write!(f, ", ")?;
-            } else {
-                first = false;
-                if data.has_self_param {
-                    write_self_param(type_ref, f)?;
-                    continue;
-                }
-            }
-            match param.pattern_source(f.db) {
-                Some(ast::Pat::IdentPat(p)) if p.name().is_some() => {
-                    write!(f, "{}: ", p.name().unwrap())?
-                }
-                _ => write!(f, "_: ")?,
-            }
-            // FIXME: Use resolved `param.ty` or raw `type_ref`?
-            // The former will ignore lifetime arguments currently.
-            type_ref.hir_fmt(f)?;
-        }
-        write!(f, ")")?;
-
-        // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
-        // Use ugly pattern match to strip the Future trait.
-        // Better way?
-        let ret_type = if !qual.is_async {
-            &data.ret_type
-        } else {
-            match &data.ret_type {
-                TypeRef::ImplTrait(bounds) => match &bounds[0] {
-                    TypeBound::Path(path) => {
-                        path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
-                            [0]
-                        .type_ref
-                        .as_ref()
-                        .unwrap()
-                    }
-                    _ => panic!("Async fn ret_type should be impl Future"),
-                },
-                _ => panic!("Async fn ret_type should be impl Future"),
-            }
-        };
-
-        match ret_type {
-            TypeRef::Tuple(tup) if tup.is_empty() => {}
-            ty => {
-                write!(f, " -> ")?;
-                ty.hir_fmt(f)?;
-            }
-        }
-
-        write_where_clause(GenericDefId::FunctionId(self.id), f)?;
-
-        Ok(())
-    }
-}
-
-impl HirDisplay for Struct {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
-        write!(f, "struct ")?;
-        write!(f, "{}", self.name(f.db))?;
-        let def_id = GenericDefId::AdtId(AdtId::StructId(self.id));
-        write_generic_params(def_id, f)?;
-        write_where_clause(def_id, f)?;
-        Ok(())
-    }
-}
-
-impl HirDisplay for Enum {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
-        write!(f, "enum ")?;
-        write!(f, "{}", self.name(f.db))?;
-        let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
-        write_generic_params(def_id, f)?;
-        write_where_clause(def_id, f)?;
-        Ok(())
-    }
-}
-
-impl HirDisplay for Union {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
-        write!(f, "union ")?;
-        write!(f, "{}", self.name(f.db))?;
-        let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
-        write_generic_params(def_id, f)?;
-        write_where_clause(def_id, f)?;
-        Ok(())
-    }
-}
-
-impl HirDisplay for Field {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
-        write!(f, "{}: ", self.name(f.db))?;
-        self.signature_ty(f.db).hir_fmt(f)
-    }
-}
-
-impl HirDisplay for Variant {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write!(f, "{}", self.name(f.db))?;
-        let data = self.variant_data(f.db);
-        match &*data {
-            VariantData::Unit => {}
-            VariantData::Tuple(fields) => {
-                write!(f, "(")?;
-                let mut first = true;
-                for (_, field) in fields.iter() {
-                    if first {
-                        first = false;
-                    } else {
-                        write!(f, ", ")?;
-                    }
-                    // Enum variant fields must be pub.
-                    field.type_ref.hir_fmt(f)?;
-                }
-                write!(f, ")")?;
-            }
-            VariantData::Record(fields) => {
-                write!(f, " {{")?;
-                let mut first = true;
-                for (_, field) in fields.iter() {
-                    if first {
-                        first = false;
-                        write!(f, " ")?;
-                    } else {
-                        write!(f, ", ")?;
-                    }
-                    // Enum variant fields must be pub.
-                    write!(f, "{}: ", field.name)?;
-                    field.type_ref.hir_fmt(f)?;
-                }
-                write!(f, " }}")?;
-            }
-        }
-        Ok(())
-    }
-}
-
-impl HirDisplay for Type {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        self.ty.value.hir_fmt(f)
-    }
-}
-
-impl HirDisplay for TypeParam {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write!(f, "{}", self.name(f.db))?;
-        let bounds = f.db.generic_predicates_for_param(self.id);
-        let substs = Substs::type_params(f.db, self.id.parent);
-        let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>();
-        if !(predicates.is_empty() || f.omit_verbose_types()) {
-            write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
-        }
-        Ok(())
-    }
-}
-
-impl HirDisplay for ConstParam {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write!(f, "const {}: ", self.name(f.db))?;
-        self.ty(f.db).hir_fmt(f)
-    }
-}
-
-fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-    let params = f.db.generic_params(def);
-    if params.lifetimes.is_empty()
-        && params.consts.is_empty()
-        && params
-            .types
-            .iter()
-            .all(|(_, param)| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
-    {
-        return Ok(());
-    }
-    write!(f, "<")?;
-
-    let mut first = true;
-    let mut delim = |f: &mut HirFormatter| {
-        if first {
-            first = false;
-            Ok(())
-        } else {
-            write!(f, ", ")
-        }
-    };
-    for (_, lifetime) in params.lifetimes.iter() {
-        delim(f)?;
-        write!(f, "{}", lifetime.name)?;
-    }
-    for (_, ty) in params.types.iter() {
-        if ty.provenance != TypeParamProvenance::TypeParamList {
-            continue;
-        }
-        if let Some(name) = &ty.name {
-            delim(f)?;
-            write!(f, "{}", name)?;
-            if let Some(default) = &ty.default {
-                write!(f, " = ")?;
-                default.hir_fmt(f)?;
-            }
-        }
-    }
-    for (_, konst) in params.consts.iter() {
-        delim(f)?;
-        write!(f, "const {}: ", konst.name)?;
-        konst.ty.hir_fmt(f)?;
-    }
-
-    write!(f, ">")?;
-    Ok(())
-}
-
-fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-    let params = f.db.generic_params(def);
-    if params.where_predicates.is_empty() {
-        return Ok(());
-    }
-
-    let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter| match target {
-        WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
-        WherePredicateTypeTarget::TypeParam(id) => match &params.types[*id].name {
-            Some(name) => write!(f, "{}", name),
-            None => write!(f, "{{unnamed}}"),
-        },
-    };
-
-    write!(f, "\nwhere")?;
-
-    for (pred_idx, pred) in params.where_predicates.iter().enumerate() {
-        let prev_pred =
-            if pred_idx == 0 { None } else { Some(&params.where_predicates[pred_idx - 1]) };
-
-        let new_predicate = |f: &mut HirFormatter| {
-            write!(f, "{}", if pred_idx == 0 { "\n    " } else { ",\n    " })
-        };
-
-        match pred {
-            WherePredicate::TypeBound { target, bound } => {
-                if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target)
-                {
-                    write!(f, " + ")?;
-                } else {
-                    new_predicate(f)?;
-                    write_target(target, f)?;
-                    write!(f, ": ")?;
-                }
-                bound.hir_fmt(f)?;
-            }
-            WherePredicate::Lifetime { target, bound } => {
-                if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target)
-                {
-                    write!(f, " + {}", bound.name)?;
-                } else {
-                    new_predicate(f)?;
-                    write!(f, "{}: {}", target.name, bound.name)?;
-                }
-            }
-            WherePredicate::ForLifetime { lifetimes, target, bound } => {
-                if matches!(
-                    prev_pred,
-                    Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. })
-                    if lifetimes_ == lifetimes && target_ == target,
-                ) {
-                    write!(f, " + ")?;
-                } else {
-                    new_predicate(f)?;
-                    write!(f, "for<")?;
-                    for (idx, lifetime) in lifetimes.iter().enumerate() {
-                        if idx != 0 {
-                            write!(f, ", ")?;
-                        }
-                        write!(f, "{}", lifetime)?;
-                    }
-                    write!(f, "> ")?;
-                    write_target(target, f)?;
-                    write!(f, ": ")?;
-                }
-                bound.hir_fmt(f)?;
-            }
-        }
-    }
-
-    // End of final predicate. There must be at least one predicate here.
-    write!(f, ",")?;
-
-    Ok(())
-}
-
-impl HirDisplay for Const {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
-        let data = f.db.const_data(self.id);
-        write!(f, "const ")?;
-        match &data.name {
-            Some(name) => write!(f, "{}: ", name)?,
-            None => write!(f, "_: ")?,
-        }
-        data.type_ref.hir_fmt(f)?;
-        Ok(())
-    }
-}
-
-impl HirDisplay for Static {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
-        let data = f.db.static_data(self.id);
-        write!(f, "static ")?;
-        if data.mutable {
-            write!(f, "mut ")?;
-        }
-        match &data.name {
-            Some(name) => write!(f, "{}: ", name)?,
-            None => write!(f, "_: ")?,
-        }
-        data.type_ref.hir_fmt(f)?;
-        Ok(())
-    }
-}
-
-impl HirDisplay for Trait {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
-        let data = f.db.trait_data(self.id);
-        if data.is_unsafe {
-            write!(f, "unsafe ")?;
-        }
-        if data.is_auto {
-            write!(f, "auto ")?;
-        }
-        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(())
-    }
-}
-
-impl HirDisplay for TypeAlias {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
-        let data = f.db.type_alias_data(self.id);
-        write!(f, "type {}", data.name)?;
-        if !data.bounds.is_empty() {
-            write!(f, ": ")?;
-            f.write_joined(&data.bounds, " + ")?;
-        }
-        if let Some(ty) = &data.type_ref {
-            write!(f, " = ")?;
-            ty.hir_fmt(f)?;
-        }
-        Ok(())
-    }
-}
-
-impl HirDisplay for Module {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        // FIXME: Module doesn't have visibility saved in data.
-        match self.name(f.db) {
-            Some(name) => write!(f, "mod {}", name),
-            None if self.crate_root(f.db) == *self => match self.krate().display_name(f.db) {
-                Some(name) => write!(f, "extern crate {}", name),
-                None => write!(f, "extern crate {{unknown}}"),
-            },
-            None => write!(f, "mod {{unnamed}}"),
-        }
-    }
-}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index f0bc2c7b95..c5161dadd8 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -29,8 +29,6 @@ mod has_source;
 pub mod diagnostics;
 pub mod db;
 
-mod display;
-
 use std::{iter, sync::Arc};
 
 use arrayvec::ArrayVec;
@@ -52,8 +50,8 @@ use hir_def::{
 use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind};
 use hir_ty::{
     autoderef,
+    display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter},
     method_resolution::{self, TyFingerprint},
-    primitive::UintTy,
     to_assoc_type_id,
     traits::{FnTrait, Solution, SolutionVariables},
     AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate,
@@ -573,12 +571,6 @@ impl Struct {
     }
 }
 
-impl HasVisibility for Struct {
-    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        db.struct_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
-    }
-}
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Union {
     pub(crate) id: UnionId,
@@ -611,12 +603,6 @@ impl Union {
     }
 }
 
-impl HasVisibility for Union {
-    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        db.union_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
-    }
-}
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Enum {
     pub(crate) id: EnumId,
@@ -644,12 +630,6 @@ impl Enum {
     }
 }
 
-impl HasVisibility for Enum {
-    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        db.enum_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
-    }
-}
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Variant {
     pub(crate) parent: Enum,
@@ -841,8 +821,7 @@ impl Function {
         db.function_data(self.id)
             .params
             .iter()
-            .enumerate()
-            .map(|(idx, type_ref)| {
+            .map(|type_ref| {
                 let ty = Type {
                     krate,
                     ty: InEnvironment {
@@ -850,7 +829,7 @@ impl Function {
                         environment: environment.clone(),
                     },
                 };
-                Param { func: self, ty, idx }
+                Param { ty }
             })
             .collect()
     }
@@ -864,7 +843,7 @@ impl Function {
     }
 
     pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
-        db.function_data(self.id).qualifier.is_unsafe
+        db.function_data(self.id).is_unsafe
     }
 
     pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
@@ -913,9 +892,6 @@ impl From<hir_ty::Mutability> for Access {
 
 #[derive(Debug)]
 pub struct Param {
-    func: Function,
-    /// The index in parameter list, including self parameter.
-    idx: usize,
     ty: Type,
 }
 
@@ -923,15 +899,6 @@ impl Param {
     pub fn ty(&self) -> &Type {
         &self.ty
     }
-
-    pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
-        let params = self.func.source(db)?.value.param_list()?;
-        if params.self_param().is_some() {
-            params.params().nth(self.idx.checked_sub(1)?)?.pat()
-        } else {
-            params.params().nth(self.idx)?.pat()
-        }
-    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -954,14 +921,6 @@ impl SelfParam {
             })
             .unwrap_or(Access::Owned)
     }
-
-    pub fn display(self, db: &dyn HirDatabase) -> &'static str {
-        match self.access(db) {
-            Access::Shared => "&self",
-            Access::Exclusive => "&mut self",
-            Access::Owned => "self",
-        }
-    }
 }
 
 impl HasVisibility for Function {
@@ -989,10 +948,6 @@ impl Const {
     pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
         db.const_data(self.id).name.clone()
     }
-
-    pub fn type_ref(self, db: &dyn HirDatabase) -> TypeRef {
-        db.const_data(self.id).type_ref.clone()
-    }
 }
 
 impl HasVisibility for Const {
@@ -1026,12 +981,6 @@ impl Static {
     }
 }
 
-impl HasVisibility for Static {
-    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        db.static_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
-    }
-}
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Trait {
     pub(crate) id: TraitId,
@@ -1051,13 +1000,7 @@ impl Trait {
     }
 
     pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
-        db.trait_data(self.id).is_auto
-    }
-}
-
-impl HasVisibility for Trait {
-    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        db.trait_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
+        db.trait_data(self.id).auto
     }
 }
 
@@ -1469,6 +1412,19 @@ impl TypeParam {
     }
 }
 
+impl HirDisplay for TypeParam {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+        write!(f, "{}", self.name(f.db))?;
+        let bounds = f.db.generic_predicates_for_param(self.id);
+        let substs = Substs::type_params(f.db, self.id.parent);
+        let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>();
+        if !(predicates.is_empty() || f.omit_verbose_types()) {
+            write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
+        }
+        Ok(())
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct LifetimeParam {
     pub(crate) id: LifetimeParamId,
@@ -1675,10 +1631,6 @@ impl Type {
         matches!(self.ty.value.interned(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
     }
 
-    pub fn is_usize(&self) -> bool {
-        matches!(self.ty.value.interned(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
-    }
-
     pub fn remove_ref(&self) -> Option<Type> {
         match &self.ty.value.interned(&Interner) {
             TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
@@ -2102,6 +2054,12 @@ impl Type {
     }
 }
 
+impl HirDisplay for Type {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+        self.ty.value.hir_fmt(f)
+    }
+}
+
 // FIXME: closures
 #[derive(Debug)]
 pub struct Callable {
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs
index 1b9bb8235f..efbde17d88 100644
--- a/crates/hir_def/src/adt.rs
+++ b/crates/hir_def/src/adt.rs
@@ -31,14 +31,12 @@ pub struct StructData {
     pub name: Name,
     pub variant_data: Arc<VariantData>,
     pub repr: Option<ReprKind>,
-    pub visibility: RawVisibility,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct EnumData {
     pub name: Name,
     pub variants: Arena<EnumVariantData>,
-    pub visibility: RawVisibility,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -104,7 +102,6 @@ impl StructData {
             name: strukt.name.clone(),
             variant_data: Arc::new(variant_data),
             repr,
-            visibility: item_tree[strukt.visibility].clone(),
         })
     }
     pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
@@ -121,7 +118,6 @@ impl StructData {
             name: union.name.clone(),
             variant_data: Arc::new(variant_data),
             repr,
-            visibility: item_tree[union.visibility].clone(),
         })
     }
 }
@@ -154,11 +150,7 @@ impl EnumData {
             }
         }
 
-        Arc::new(EnumData {
-            name: enum_.name.clone(),
-            variants,
-            visibility: item_tree[enum_.visibility].clone(),
-        })
+        Arc::new(EnumData { name: enum_.name.clone(), variants })
     }
 
     pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 8bcc350ce5..1080d9c2c3 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -32,6 +32,7 @@ use crate::{
     path::{ModPath, Path},
     src::HasSource,
     AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleId,
+    UnresolvedMacro,
 };
 
 /// A subset of Expander that only deals with cfg attributes. We only need it to
@@ -101,10 +102,12 @@ impl Expander {
         &mut self,
         db: &dyn DefDatabase,
         macro_call: ast::MacroCall,
-    ) -> ExpandResult<Option<(Mark, T)>> {
+    ) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
         if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT {
             cov_mark::hit!(your_stack_belongs_to_me);
-            return ExpandResult::str_err("reached recursion limit during macro expansion".into());
+            return Ok(ExpandResult::str_err(
+                "reached recursion limit during macro expansion".into(),
+            ));
         }
 
         let macro_call = InFile::new(self.current_file_id, &macro_call);
@@ -116,14 +119,11 @@ impl Expander {
         let call_id =
             macro_call.as_call_id_with_errors(db, self.def_map.krate(), resolver, &mut |e| {
                 err.get_or_insert(e);
-            });
+            })?;
         let call_id = match call_id {
-            Some(it) => it,
-            None => {
-                if err.is_none() {
-                    log::warn!("no error despite `as_call_id_with_errors` returning `None`");
-                }
-                return ExpandResult { value: None, err };
+            Ok(it) => it,
+            Err(_) => {
+                return Ok(ExpandResult { value: None, err });
             }
         };
 
@@ -141,9 +141,9 @@ impl Expander {
                     log::warn!("no error despite `parse_or_expand` failing");
                 }
 
-                return ExpandResult::only_err(err.unwrap_or_else(|| {
+                return Ok(ExpandResult::only_err(err.unwrap_or_else(|| {
                     mbe::ExpandError::Other("failed to parse macro invocation".into())
-                }));
+                })));
             }
         };
 
@@ -151,7 +151,7 @@ impl Expander {
             Some(it) => it,
             None => {
                 // This can happen without being an error, so only forward previous errors.
-                return ExpandResult { value: None, err };
+                return Ok(ExpandResult { value: None, err });
             }
         };
 
@@ -167,7 +167,7 @@ impl Expander {
         self.current_file_id = file_id;
         self.ast_id_map = db.ast_id_map(file_id);
 
-        ExpandResult { value: Some((mark, node)), err }
+        Ok(ExpandResult { value: Some((mark, node)), err })
     }
 
     pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
diff --git a/crates/hir_def/src/body/diagnostics.rs b/crates/hir_def/src/body/diagnostics.rs
index 1de7d30e20..f6992c9a8a 100644
--- a/crates/hir_def/src/body/diagnostics.rs
+++ b/crates/hir_def/src/body/diagnostics.rs
@@ -2,13 +2,14 @@
 
 use hir_expand::diagnostics::DiagnosticSink;
 
-use crate::diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro};
+use crate::diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro};
 
 #[derive(Debug, Eq, PartialEq)]
 pub(crate) enum BodyDiagnostic {
     InactiveCode(InactiveCode),
     MacroError(MacroError),
     UnresolvedProcMacro(UnresolvedProcMacro),
+    UnresolvedMacroCall(UnresolvedMacroCall),
 }
 
 impl BodyDiagnostic {
@@ -23,6 +24,9 @@ impl BodyDiagnostic {
             BodyDiagnostic::UnresolvedProcMacro(diag) => {
                 sink.push(diag.clone());
             }
+            BodyDiagnostic::UnresolvedMacroCall(diag) => {
+                sink.push(diag.clone());
+            }
         }
     }
 }
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 7052058f2a..08f0c32f41 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -24,7 +24,7 @@ use crate::{
     body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
     db::DefDatabase,
-    diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro},
+    diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro},
     expr::{
         dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
         LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
@@ -33,7 +33,7 @@ use crate::{
     item_scope::BuiltinShadowMode,
     path::{GenericArgs, Path},
     type_ref::{Mutability, Rawness, TypeRef},
-    AdtId, BlockLoc, ModuleDefId,
+    AdtId, BlockLoc, ModuleDefId, UnresolvedMacro,
 };
 
 use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
@@ -519,7 +519,7 @@ impl ExprCollector<'_> {
             }
             ast::Expr::MacroCall(e) => {
                 let mut ids = vec![];
-                self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| {
+                self.collect_macro_call(e, syntax_ptr.clone(), |this, expansion| {
                     ids.push(match expansion {
                         Some(it) => this.collect_expr(it),
                         None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -527,17 +527,6 @@ impl ExprCollector<'_> {
                 });
                 ids[0]
             }
-            ast::Expr::MacroStmts(e) => {
-                // FIXME:  these statements should be held by some hir containter
-                for stmt in e.statements() {
-                    self.collect_stmt(stmt);
-                }
-                if let Some(expr) = e.expr() {
-                    self.collect_expr(expr)
-                } else {
-                    self.alloc_expr(Expr::Missing, syntax_ptr)
-                }
-            }
         }
     }
 
@@ -545,7 +534,6 @@ impl ExprCollector<'_> {
         &mut self,
         e: ast::MacroCall,
         syntax_ptr: AstPtr<ast::Expr>,
-        is_error_recoverable: bool,
         mut collector: F,
     ) {
         // File containing the macro call. Expansion errors will be attached here.
@@ -554,6 +542,17 @@ impl ExprCollector<'_> {
         let macro_call = self.expander.to_source(AstPtr::new(&e));
         let res = self.expander.enter_expand(self.db, e);
 
+        let res = match res {
+            Ok(res) => res,
+            Err(UnresolvedMacro) => {
+                self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall(
+                    UnresolvedMacroCall { file: outer_file, node: syntax_ptr.cast().unwrap() },
+                ));
+                collector(self, None);
+                return;
+            }
+        };
+
         match &res.err {
             Some(ExpandError::UnresolvedProcMacro) => {
                 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
@@ -579,7 +578,7 @@ impl ExprCollector<'_> {
             Some((mark, expansion)) => {
                 // FIXME: Statements are too complicated to recover from error for now.
                 // It is because we don't have any hygiene for local variable expansion right now.
-                if !is_error_recoverable && res.err.is_some() {
+                if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
                     self.expander.exit(self.db, mark);
                     collector(self, None);
                 } else {
@@ -603,55 +602,56 @@ impl ExprCollector<'_> {
     }
 
     fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
-        let stmt = match s {
-            ast::Stmt::LetStmt(stmt) => {
-                self.check_cfg(&stmt)?;
-
-                let pat = self.collect_pat_opt(stmt.pat());
-                let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
-                let initializer = stmt.initializer().map(|e| self.collect_expr(e));
-                vec![Statement::Let { pat, type_ref, initializer }]
-            }
-            ast::Stmt::ExprStmt(stmt) => {
-                self.check_cfg(&stmt)?;
-
-                // Note that macro could be expended to multiple statements
-                if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
-                    let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
-                    let mut stmts = vec![];
-
-                    self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
-                        match expansion {
-                            Some(expansion) => {
-                                let statements: ast::MacroStmts = expansion;
-
-                                statements.statements().for_each(|stmt| {
-                                    if let Some(mut r) = this.collect_stmt(stmt) {
-                                        stmts.append(&mut r);
+        let stmt =
+            match s {
+                ast::Stmt::LetStmt(stmt) => {
+                    self.check_cfg(&stmt)?;
+
+                    let pat = self.collect_pat_opt(stmt.pat());
+                    let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
+                    let initializer = stmt.initializer().map(|e| self.collect_expr(e));
+                    vec![Statement::Let { pat, type_ref, initializer }]
+                }
+                ast::Stmt::ExprStmt(stmt) => {
+                    self.check_cfg(&stmt)?;
+
+                    // Note that macro could be expended to multiple statements
+                    if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
+                        let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
+                        let mut stmts = vec![];
+
+                        self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| {
+                            match expansion {
+                                Some(expansion) => {
+                                    let statements: ast::MacroStmts = expansion;
+
+                                    statements.statements().for_each(|stmt| {
+                                        if let Some(mut r) = this.collect_stmt(stmt) {
+                                            stmts.append(&mut r);
+                                        }
+                                    });
+                                    if let Some(expr) = statements.expr() {
+                                        stmts.push(Statement::Expr(this.collect_expr(expr)));
                                     }
-                                });
-                                if let Some(expr) = statements.expr() {
-                                    stmts.push(Statement::Expr(this.collect_expr(expr)));
+                                }
+                                None => {
+                                    stmts.push(Statement::Expr(
+                                        this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
+                                    ));
                                 }
                             }
-                            None => {
-                                stmts.push(Statement::Expr(
-                                    this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
-                                ));
-                            }
-                        }
-                    });
-                    stmts
-                } else {
-                    vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
+                        });
+                        stmts
+                    } else {
+                        vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
+                    }
                 }
-            }
-            ast::Stmt::Item(item) => {
-                self.check_cfg(&item)?;
+                ast::Stmt::Item(item) => {
+                    self.check_cfg(&item)?;
 
-                return None;
-            }
-        };
+                    return None;
+                }
+            };
 
         Some(stmt)
     }
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index 74a2194e5e..e3bb9de08b 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -9,7 +9,7 @@ use crate::{
     attr::Attrs,
     body::Expander,
     db::DefDatabase,
-    item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem},
+    item_tree::{AssocItem, ItemTreeId, ModItem},
     type_ref::{TypeBound, TypeRef},
     visibility::RawVisibility,
     AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
@@ -26,9 +26,9 @@ pub struct FunctionData {
     /// can be called as a method.
     pub has_self_param: bool,
     pub has_body: bool,
-    pub qualifier: FunctionQualifier,
-    pub is_in_extern_block: bool,
+    pub is_unsafe: bool,
     pub is_varargs: bool,
+    pub is_extern: bool,
     pub visibility: RawVisibility,
 }
 
@@ -46,9 +46,9 @@ impl FunctionData {
             attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
             has_self_param: func.has_self_param,
             has_body: func.has_body,
-            qualifier: func.qualifier.clone(),
-            is_in_extern_block: func.is_in_extern_block,
+            is_unsafe: func.is_unsafe,
             is_varargs: func.is_varargs,
+            is_extern: func.is_extern,
             visibility: item_tree[func.visibility].clone(),
         })
     }
@@ -87,10 +87,7 @@ impl TypeAliasData {
 pub struct TraitData {
     pub name: Name,
     pub items: Vec<(Name, AssocItemId)>,
-    pub is_auto: bool,
-    pub is_unsafe: bool,
-    pub visibility: RawVisibility,
-    pub bounds: Box<[TypeBound]>,
+    pub auto: bool,
 }
 
 impl TraitData {
@@ -99,13 +96,10 @@ impl TraitData {
         let item_tree = db.item_tree(tr_loc.id.file_id);
         let tr_def = &item_tree[tr_loc.id.value];
         let name = tr_def.name.clone();
-        let is_auto = tr_def.is_auto;
-        let is_unsafe = tr_def.is_unsafe;
+        let auto = tr_def.auto;
         let module_id = tr_loc.container;
         let container = AssocContainerId::TraitId(tr);
         let mut expander = Expander::new(db, tr_loc.id.file_id, module_id);
-        let visibility = item_tree[tr_def.visibility].clone();
-        let bounds = tr_def.bounds.clone();
 
         let items = collect_items(
             db,
@@ -117,7 +111,7 @@ impl TraitData {
             100,
         );
 
-        Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility, bounds })
+        Arc::new(TraitData { name, items, auto })
     }
 
     pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
@@ -267,23 +261,26 @@ fn collect_items(
                 let ast_id_map = db.ast_id_map(file_id);
                 let root = db.parse_or_expand(file_id).unwrap();
                 let call = ast_id_map.get(call.ast_id).to_node(&root);
-
-                if let Some((mark, mac)) = expander.enter_expand(db, call).value {
-                    let src: InFile<ast::MacroItems> = expander.to_source(mac);
-                    let item_tree = db.item_tree(src.file_id);
-                    let iter =
-                        item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
-                    items.extend(collect_items(
-                        db,
-                        module,
-                        expander,
-                        iter,
-                        src.file_id,
-                        container,
-                        limit - 1,
-                    ));
-
-                    expander.exit(db, mark);
+                let res = expander.enter_expand(db, call);
+
+                if let Ok(res) = res {
+                    if let Some((mark, mac)) = res.value {
+                        let src: InFile<ast::MacroItems> = expander.to_source(mac);
+                        let item_tree = db.item_tree(src.file_id);
+                        let iter =
+                            item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
+                        items.extend(collect_items(
+                            db,
+                            module,
+                            expander,
+                            iter,
+                            src.file_id,
+                            container,
+                            limit - 1,
+                        ));
+
+                        expander.exit(db, mark);
+                    }
                 }
             }
         }
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
index 7188bb299d..97abf86534 100644
--- a/crates/hir_def/src/diagnostics.rs
+++ b/crates/hir_def/src/diagnostics.rs
@@ -99,7 +99,7 @@ impl Diagnostic for UnresolvedImport {
 //
 // This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
 // macro in a macro invocation.
-#[derive(Debug)]
+#[derive(Debug, Clone, Eq, PartialEq)]
 pub struct UnresolvedMacroCall {
     pub file: HirFileId,
     pub node: AstPtr<ast::MacroCall>,
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 7bb22c4c49..09bcb10dc0 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -24,7 +24,7 @@ use la_arena::{Arena, Idx, RawIdx};
 use profile::Count;
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
-use syntax::{ast, match_ast, SmolStr, SyntaxKind};
+use syntax::{ast, match_ast, SyntaxKind};
 
 use crate::{
     attr::{Attrs, RawAttrs},
@@ -110,11 +110,6 @@ impl ItemTree {
                     // still need to collect inner items.
                     ctx.lower_inner_items(e.syntax())
                 },
-                ast::ExprStmt(stmt) => {
-                    // Macros can expand to stmt. We return an empty item tree in this case, but
-                    // still need to collect inner items.
-                    ctx.lower_inner_items(stmt.syntax())
-                },
                 _ => {
                     panic!("cannot create item tree from {:?} {}", syntax, syntax);
                 },
@@ -556,25 +551,16 @@ pub struct Function {
     pub generic_params: GenericParamsId,
     pub has_self_param: bool,
     pub has_body: bool,
-    pub qualifier: FunctionQualifier,
+    pub is_unsafe: bool,
     /// Whether the function is located in an `extern` block (*not* whether it is an
     /// `extern "abi" fn`).
-    pub is_in_extern_block: bool,
+    pub is_extern: bool,
     pub params: Box<[Idx<TypeRef>]>,
     pub is_varargs: bool,
     pub ret_type: Idx<TypeRef>,
     pub ast_id: FileAstId<ast::Fn>,
 }
 
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct FunctionQualifier {
-    pub is_default: bool,
-    pub is_const: bool,
-    pub is_async: bool,
-    pub is_unsafe: bool,
-    pub abi: Option<SmolStr>,
-}
-
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Struct {
     pub name: Name,
@@ -638,9 +624,7 @@ pub struct Trait {
     pub name: Name,
     pub visibility: RawVisibilityId,
     pub generic_params: GenericParamsId,
-    pub is_auto: bool,
-    pub is_unsafe: bool,
-    pub bounds: Box<[TypeBound]>,
+    pub auto: bool,
     pub items: Box<[AssocItem]>,
     pub ast_id: FileAstId<ast::Trait>,
 }
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 7e91b991d2..240fdacf94 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -391,33 +391,14 @@ impl Ctx {
         let has_body = func.body().is_some();
 
         let ast_id = self.source_ast_id_map.ast_id(func);
-        let qualifier = FunctionQualifier {
-            is_default: func.default_token().is_some(),
-            is_const: func.const_token().is_some(),
-            is_async: func.async_token().is_some(),
-            is_unsafe: func.unsafe_token().is_some(),
-            abi: func.abi().map(|abi| {
-                // FIXME: Abi::abi() -> Option<SyntaxToken>?
-                match abi.syntax().last_token() {
-                    Some(tok) if tok.kind() == SyntaxKind::STRING => {
-                        // FIXME: Better way to unescape?
-                        tok.text().trim_matches('"').into()
-                    }
-                    _ => {
-                        // `extern` default to be `extern "C"`.
-                        "C".into()
-                    }
-                }
-            }),
-        };
         let mut res = Function {
             name,
             visibility,
             generic_params: GenericParamsId::EMPTY,
             has_self_param,
             has_body,
-            qualifier,
-            is_in_extern_block: false,
+            is_unsafe: func.unsafe_token().is_some(),
+            is_extern: false,
             params,
             is_varargs,
             ret_type,
@@ -500,9 +481,7 @@ impl Ctx {
         let visibility = self.lower_visibility(trait_def);
         let generic_params =
             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 auto = trait_def.auto_token().is_some();
         let items = trait_def.assoc_item_list().map(|list| {
             self.with_inherited_visibility(visibility, |this| {
                 list.assoc_items()
@@ -522,9 +501,7 @@ impl Ctx {
             name,
             visibility,
             generic_params,
-            is_auto,
-            is_unsafe,
-            bounds: bounds.into(),
+            auto,
             items: items.unwrap_or_default(),
             ast_id,
         };
@@ -631,8 +608,8 @@ impl Ctx {
                         ast::ExternItem::Fn(ast) => {
                             let func_id = self.lower_function(&ast)?;
                             let func = &mut self.data().functions[func_id.index];
-                            func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name);
-                            func.is_in_extern_block = true;
+                            func.is_unsafe = is_intrinsic_fn_unsafe(&func.name);
+                            func.is_extern = true;
                             func_id.into()
                         }
                         ast::ExternItem::Static(ast) => {
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index c6655c5fbf..6758411a0c 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -58,7 +58,7 @@ use std::{
 use base_db::{impl_intern_key, salsa, CrateId};
 use hir_expand::{
     ast_id_map::FileAstId,
-    eager::{expand_eager_macro, ErrorEmitted},
+    eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
     hygiene::Hygiene,
     AstId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
 };
@@ -583,7 +583,7 @@ pub trait AsMacroCall {
         krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
     ) -> Option<MacroCallId> {
-        self.as_call_id_with_errors(db, krate, resolver, &mut |_| ())
+        self.as_call_id_with_errors(db, krate, resolver, &mut |_| ()).ok()?.ok()
     }
 
     fn as_call_id_with_errors(
@@ -592,7 +592,7 @@ pub trait AsMacroCall {
         krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
         error_sink: &mut dyn FnMut(mbe::ExpandError),
-    ) -> Option<MacroCallId>;
+    ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro>;
 }
 
 impl AsMacroCall for InFile<&ast::MacroCall> {
@@ -601,25 +601,28 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
         db: &dyn db::DefDatabase,
         krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
-        error_sink: &mut dyn FnMut(mbe::ExpandError),
-    ) -> Option<MacroCallId> {
+        mut error_sink: &mut dyn FnMut(mbe::ExpandError),
+    ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
         let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
         let h = Hygiene::new(db.upcast(), self.file_id);
         let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h));
 
-        if path.is_none() {
-            error_sink(mbe::ExpandError::Other("malformed macro invocation".into()));
-        }
+        let path = match error_sink
+            .option(path, || mbe::ExpandError::Other("malformed macro invocation".into()))
+        {
+            Ok(path) => path,
+            Err(error) => {
+                return Ok(Err(error));
+            }
+        };
 
         macro_call_as_call_id(
-            &AstIdWithPath::new(ast_id.file_id, ast_id.value, path?),
+            &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
             db,
             krate,
             resolver,
             error_sink,
         )
-        .ok()?
-        .ok()
     }
 }
 
@@ -636,7 +639,7 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
     }
 }
 
-struct UnresolvedMacro;
+pub struct UnresolvedMacro;
 
 fn macro_call_as_call_id(
     call: &AstIdWithPath<ast::MacroCall>,
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 8c923bb7b2..0e60dc2b63 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -9,10 +9,7 @@ use std::{
 
 use crate::{body::LowerCtx, type_ref::LifetimeRef};
 use base_db::CrateId;
-use hir_expand::{
-    hygiene::Hygiene,
-    name::{name, Name},
-};
+use hir_expand::{hygiene::Hygiene, name::Name};
 use syntax::ast;
 
 use crate::{
@@ -212,12 +209,6 @@ impl Path {
         };
         Some(res)
     }
-
-    pub fn is_self_type(&self) -> bool {
-        self.type_anchor.is_none()
-            && self.generic_args == &[None]
-            && self.mod_path.as_ident() == Some(&name!(Self))
-    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index a3070f1f94..9086e6c176 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -401,14 +401,13 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
 
     match parent.kind() {
         MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
-        MACRO_STMTS => FragmentKind::Statement,
         ITEM_LIST => FragmentKind::Items,
         LET_STMT => {
             // FIXME: Handle Pattern
             FragmentKind::Expr
         }
         EXPR_STMT => FragmentKind::Statements,
-        BLOCK_EXPR => FragmentKind::Statements,
+        BLOCK_EXPR => FragmentKind::Expr,
         ARG_LIST => FragmentKind::Expr,
         TRY_EXPR => FragmentKind::Expr,
         TUPLE_EXPR => FragmentKind::Expr,
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index ae7b51a088..dc618a9ee1 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -35,7 +35,7 @@ pub struct ErrorEmitted {
     _private: (),
 }
 
-trait ErrorSink {
+pub trait ErrorSink {
     fn emit(&mut self, err: mbe::ExpandError);
 
     fn option<T>(
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index 982ad5b9e0..3605ca5816 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -91,7 +91,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
 
     fn validate_func(&mut self, func: FunctionId) {
         let data = self.db.function_data(func);
-        if data.is_in_extern_block {
+        if data.is_extern {
             cov_mark::hit!(extern_func_incorrect_case_ignored);
             return;
         }
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index 44a7e55064..20bb648279 100644
--- a/crates/hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs
@@ -32,7 +32,7 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> {
         let def = self.owner.into();
         let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
         let is_unsafe = match self.owner {
-            DefWithBodyId::FunctionId(it) => db.function_data(it).qualifier.is_unsafe,
+            DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe,
             DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
         };
         if is_unsafe
@@ -86,7 +86,7 @@ fn walk_unsafe(
     match expr {
         &Expr::Call { callee, .. } => {
             if let Some(func) = infer[callee].as_fn_def(db) {
-                if db.function_data(func).qualifier.is_unsafe {
+                if db.function_data(func).is_unsafe {
                     unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
                 }
             }
@@ -103,7 +103,7 @@ fn walk_unsafe(
         Expr::MethodCall { .. } => {
             if infer
                 .method_resolution(current)
-                .map(|func| db.function_data(func).qualifier.is_unsafe)
+                .map(|func| db.function_data(func).is_unsafe)
                 .unwrap_or(false)
             {
                 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index c572bb1141..c1062387e1 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -5,13 +5,7 @@ use std::{borrow::Cow, fmt};
 use arrayvec::ArrayVec;
 use chalk_ir::Mutability;
 use hir_def::{
-    db::DefDatabase,
-    find_path,
-    generics::TypeParamProvenance,
-    item_scope::ItemInNs,
-    path::{GenericArg, Path, PathKind},
-    type_ref::{TypeBound, TypeRef},
-    visibility::Visibility,
+    db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs,
     AssocContainerId, Lookup, ModuleId, TraitId,
 };
 use hir_expand::name::Name;
@@ -238,7 +232,7 @@ where
 
 const TYPE_HINT_TRUNCATION: &str = "…";
 
-impl<T: HirDisplay> HirDisplay for &'_ T {
+impl HirDisplay for &Ty {
     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         HirDisplay::hir_fmt(*self, f)
     }
@@ -767,6 +761,12 @@ impl HirDisplay for TraitRef {
     }
 }
 
+impl HirDisplay for &GenericPredicate {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+        HirDisplay::hir_fmt(*self, f)
+    }
+}
+
 impl HirDisplay for GenericPredicate {
     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         if f.should_truncate() {
@@ -825,190 +825,3 @@ impl HirDisplay for Obligation {
         }
     }
 }
-
-pub fn write_visibility(
-    module_id: ModuleId,
-    vis: Visibility,
-    f: &mut HirFormatter,
-) -> Result<(), HirDisplayError> {
-    match vis {
-        Visibility::Public => write!(f, "pub "),
-        Visibility::Module(vis_id) => {
-            let def_map = module_id.def_map(f.db.upcast());
-            let root_module_id = def_map.module_id(def_map.root());
-            if vis_id == module_id {
-                // pub(self) or omitted
-                Ok(())
-            } else if root_module_id == vis_id {
-                write!(f, "pub(crate) ")
-            } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) {
-                write!(f, "pub(super) ")
-            } else {
-                write!(f, "pub(in ...) ")
-            }
-        }
-    }
-}
-
-impl HirDisplay for TypeRef {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        match self {
-            TypeRef::Never => write!(f, "!")?,
-            TypeRef::Placeholder => write!(f, "_")?,
-            TypeRef::Tuple(elems) => {
-                write!(f, "(")?;
-                f.write_joined(elems, ", ")?;
-                if elems.len() == 1 {
-                    write!(f, ",")?;
-                }
-                write!(f, ")")?;
-            }
-            TypeRef::Path(path) => path.hir_fmt(f)?,
-            TypeRef::RawPtr(inner, mutability) => {
-                let mutability = match mutability {
-                    hir_def::type_ref::Mutability::Shared => "*const ",
-                    hir_def::type_ref::Mutability::Mut => "*mut ",
-                };
-                write!(f, "{}", mutability)?;
-                inner.hir_fmt(f)?;
-            }
-            TypeRef::Reference(inner, lifetime, mutability) => {
-                let mutability = match mutability {
-                    hir_def::type_ref::Mutability::Shared => "",
-                    hir_def::type_ref::Mutability::Mut => "mut ",
-                };
-                write!(f, "&")?;
-                if let Some(lifetime) = lifetime {
-                    write!(f, "{} ", lifetime.name)?;
-                }
-                write!(f, "{}", mutability)?;
-                inner.hir_fmt(f)?;
-            }
-            TypeRef::Array(inner) => {
-                write!(f, "[")?;
-                inner.hir_fmt(f)?;
-                // FIXME: Array length?
-                write!(f, "; _]")?;
-            }
-            TypeRef::Slice(inner) => {
-                write!(f, "[")?;
-                inner.hir_fmt(f)?;
-                write!(f, "]")?;
-            }
-            TypeRef::Fn(tys, is_varargs) => {
-                // FIXME: Function pointer qualifiers.
-                write!(f, "fn(")?;
-                f.write_joined(&tys[..tys.len() - 1], ", ")?;
-                if *is_varargs {
-                    write!(f, "{}...", if tys.len() == 1 { "" } else { ", " })?;
-                }
-                write!(f, ")")?;
-                let ret_ty = tys.last().unwrap();
-                match ret_ty {
-                    TypeRef::Tuple(tup) if tup.is_empty() => {}
-                    _ => {
-                        write!(f, " -> ")?;
-                        ret_ty.hir_fmt(f)?;
-                    }
-                }
-            }
-            TypeRef::ImplTrait(bounds) => {
-                write!(f, "impl ")?;
-                f.write_joined(bounds, " + ")?;
-            }
-            TypeRef::DynTrait(bounds) => {
-                write!(f, "dyn ")?;
-                f.write_joined(bounds, " + ")?;
-            }
-            TypeRef::Error => write!(f, "{{error}}")?,
-        }
-        Ok(())
-    }
-}
-
-impl HirDisplay for TypeBound {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        match self {
-            TypeBound::Path(path) => path.hir_fmt(f),
-            TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
-            TypeBound::Error => write!(f, "{{error}}"),
-        }
-    }
-}
-
-impl HirDisplay for Path {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        match (self.type_anchor(), self.kind()) {
-            (Some(anchor), _) => {
-                write!(f, "<")?;
-                anchor.hir_fmt(f)?;
-                write!(f, ">")?;
-            }
-            (_, PathKind::Plain) => {}
-            (_, PathKind::Abs) => write!(f, "::")?,
-            (_, PathKind::Crate) => write!(f, "crate")?,
-            (_, PathKind::Super(0)) => write!(f, "self")?,
-            (_, PathKind::Super(n)) => {
-                write!(f, "super")?;
-                for _ in 0..*n {
-                    write!(f, "::super")?;
-                }
-            }
-            (_, PathKind::DollarCrate(_)) => write!(f, "{{extern_crate}}")?,
-        }
-
-        for (seg_idx, segment) in self.segments().iter().enumerate() {
-            if seg_idx != 0 {
-                write!(f, "::")?;
-            }
-            write!(f, "{}", segment.name)?;
-            if let Some(generic_args) = segment.args_and_bindings {
-                // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
-                // Do we actually format expressions?
-                write!(f, "<")?;
-                let mut first = true;
-                for arg in &generic_args.args {
-                    if first {
-                        first = false;
-                        if generic_args.has_self_type {
-                            // FIXME: Convert to `<Ty as Trait>` form.
-                            write!(f, "Self = ")?;
-                        }
-                    } else {
-                        write!(f, ", ")?;
-                    }
-                    arg.hir_fmt(f)?;
-                }
-                for binding in &generic_args.bindings {
-                    if first {
-                        first = false;
-                    } else {
-                        write!(f, ", ")?;
-                    }
-                    write!(f, "{}", binding.name)?;
-                    match &binding.type_ref {
-                        Some(ty) => {
-                            write!(f, " = ")?;
-                            ty.hir_fmt(f)?
-                        }
-                        None => {
-                            write!(f, ": ")?;
-                            f.write_joined(&binding.bounds, " + ")?;
-                        }
-                    }
-                }
-                write!(f, ">")?;
-            }
-        }
-        Ok(())
-    }
-}
-
-impl HirDisplay for GenericArg {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        match self {
-            GenericArg::Type(ty) => ty.hir_fmt(f),
-            GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
-        }
-    }
-}
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 4bd8ba3031..232cf9cd0d 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -429,7 +429,7 @@ pub(crate) fn trait_datum_query(
     let generic_params = generics(db.upcast(), trait_.into());
     let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
     let flags = rust_ir::TraitFlags {
-        auto: trait_data.is_auto,
+        auto: trait_data.auto,
         upstream: trait_.lookup(db.upcast()).container.krate() != krate,
         non_enumerable: true,
         coinductive: false, // only relevant for Chalk testing
diff --git a/crates/ide/src/display.rs b/crates/ide/src/display.rs
index 1f7b665c07..bae9e40dfa 100644
--- a/crates/ide/src/display.rs
+++ b/crates/ide/src/display.rs
@@ -5,5 +5,6 @@ pub(crate) mod navigation_target;
 mod short_label;
 
 pub(crate) use navigation_target::{ToNav, TryToNav};
+pub(crate) use short_label::ShortLabel;
 
 pub(crate) use syntax::display::{function_declaration, macro_label};
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 69c3751a1b..1982434663 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -3,9 +3,7 @@
 use std::fmt;
 
 use either::Either;
-use hir::{
-    AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay, InFile, ModuleSource,
-};
+use hir::{AssocItem, Documentation, FieldSource, HasAttrs, HasSource, InFile, ModuleSource};
 use ide_db::{
     base_db::{FileId, FileRange, SourceDatabase},
     symbol_index::FileSymbolKind,
@@ -100,7 +98,7 @@ impl NavigationTarget {
                 SymbolKind::Module,
             );
             res.docs = module.attrs(db).docs();
-            res.description = Some(module.display(db).to_string());
+            res.description = src.value.short_label();
             return res;
         }
         module.to_nav(db)
@@ -253,8 +251,8 @@ impl ToNavFromAst for hir::Trait {
 
 impl<D> TryToNav for D
 where
-    D: HasSource + ToNavFromAst + Copy + HasAttrs + HirDisplay,
-    D::Ast: ast::NameOwner,
+    D: HasSource + ToNavFromAst + Copy + HasAttrs,
+    D::Ast: ast::NameOwner + ShortLabel,
 {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
         let src = self.source(db)?;
@@ -264,7 +262,7 @@ where
             D::KIND,
         );
         res.docs = self.docs(db);
-        res.description = Some(self.display(db).to_string());
+        res.description = src.value.short_label();
         Some(res)
     }
 }
@@ -319,7 +317,7 @@ impl TryToNav for hir::Field {
                 let mut res =
                     NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field);
                 res.docs = self.docs(db);
-                res.description = Some(self.display(db).to_string());
+                res.description = it.short_label();
                 res
             }
             FieldSource::Pos(it) => {
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index a35805c5e7..ea45086ce8 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,7 +1,7 @@
 use either::Either;
 use hir::{
-    Adt, AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, Module,
-    ModuleDef, Semantics,
+    Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource,
+    HirDisplay, Module, ModuleDef, ModuleSource, Semantics,
 };
 use ide_db::{
     base_db::SourceDatabase,
@@ -14,7 +14,7 @@ use stdx::format_to;
 use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
 
 use crate::{
-    display::{macro_label, TryToNav},
+    display::{macro_label, ShortLabel, TryToNav},
     doc_links::{remove_links, rewrite_links},
     markdown_remove::remove_markdown,
     markup::Markup,
@@ -335,18 +335,34 @@ fn hover_for_definition(
             let label = macro_label(&it.source(db)?.value);
             from_def_source_labeled(db, it, Some(label), mod_path)
         }
-        Definition::Field(def) => from_hir_fmt(db, def, mod_path),
+        Definition::Field(def) => {
+            let src = def.source(db)?.value;
+            if let FieldSource::Named(it) = src {
+                from_def_source_labeled(db, def, it.short_label(), mod_path)
+            } else {
+                None
+            }
+        }
         Definition::ModuleDef(it) => match it {
-            ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path),
-            ModuleDef::Function(it) => from_hir_fmt(db, it, mod_path),
-            ModuleDef::Adt(Adt::Struct(it)) => from_hir_fmt(db, it, mod_path),
-            ModuleDef::Adt(Adt::Union(it)) => from_hir_fmt(db, it, mod_path),
-            ModuleDef::Adt(Adt::Enum(it)) => from_hir_fmt(db, it, mod_path),
-            ModuleDef::Variant(it) => from_hir_fmt(db, it, mod_path),
-            ModuleDef::Const(it) => from_hir_fmt(db, it, mod_path),
-            ModuleDef::Static(it) => from_hir_fmt(db, it, mod_path),
-            ModuleDef::Trait(it) => from_hir_fmt(db, it, mod_path),
-            ModuleDef::TypeAlias(it) => from_hir_fmt(db, it, mod_path),
+            ModuleDef::Module(it) => from_def_source_labeled(
+                db,
+                it,
+                match it.definition_source(db).value {
+                    ModuleSource::Module(it) => it.short_label(),
+                    ModuleSource::SourceFile(it) => it.short_label(),
+                    ModuleSource::BlockExpr(it) => it.short_label(),
+                },
+                mod_path,
+            ),
+            ModuleDef::Function(it) => from_def_source(db, it, mod_path),
+            ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
+            ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path),
+            ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path),
+            ModuleDef::Variant(it) => from_def_source(db, it, mod_path),
+            ModuleDef::Const(it) => from_def_source(db, it, mod_path),
+            ModuleDef::Static(it) => from_def_source(db, it, mod_path),
+            ModuleDef::Trait(it) => from_def_source(db, it, mod_path),
+            ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path),
             ModuleDef::BuiltinType(it) => famous_defs
                 .and_then(|fd| hover_for_builtin(fd, it))
                 .or_else(|| Some(Markup::fenced_block(&it.name()))),
@@ -354,25 +370,26 @@ fn hover_for_definition(
         Definition::Local(it) => hover_for_local(it, db),
         Definition::SelfType(impl_def) => {
             impl_def.target_ty(db).as_adt().and_then(|adt| match adt {
-                Adt::Struct(it) => from_hir_fmt(db, it, mod_path),
-                Adt::Union(it) => from_hir_fmt(db, it, mod_path),
-                Adt::Enum(it) => from_hir_fmt(db, it, mod_path),
+                Adt::Struct(it) => from_def_source(db, it, mod_path),
+                Adt::Union(it) => from_def_source(db, it, mod_path),
+                Adt::Enum(it) => from_def_source(db, it, mod_path),
             })
         }
         Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
         Definition::GenericParam(it) => match it {
             GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))),
             GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
-            GenericParam::ConstParam(it) => Some(Markup::fenced_block(&it.display(db))),
+            GenericParam::ConstParam(it) => from_def_source(db, it, None),
         },
     };
 
-    fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
+    fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
     where
-        D: HasAttrs + HirDisplay,
+        D: HasSource<Ast = A> + HasAttrs + Copy,
+        A: ShortLabel,
     {
-        let label = def.display(db).to_string();
-        from_def_source_labeled(db, def, Some(label), mod_path)
+        let short_label = def.source(db)?.value.short_label();
+        from_def_source_labeled(db, def, short_label, mod_path)
     }
 
     fn from_def_source_labeled<D>(
@@ -653,9 +670,7 @@ fn main() { let foo_test = fo$0o(); }
                 ```
 
                 ```rust
-                pub fn foo<'a, T>(b: &'a T) -> &'a str
-                where
-                    T: AsRef<str>,
+                pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str
                 ```
             "#]],
         );
@@ -863,7 +878,7 @@ fn main() { So$0me(12); }
                 ```
 
                 ```rust
-                Some(T)
+                Some
                 ```
             "#]],
         );
@@ -929,7 +944,7 @@ fn main() {
                 ```
 
                 ```rust
-                Some(T)
+                Some
                 ```
 
                 ---
@@ -1426,14 +1441,13 @@ fn bar() { fo$0o(); }
                 ```
             "#]],
         );
-        // Top level `pub(crate)` will be displayed as no visibility.
         check(
-            r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#,
+            r#"pub(crate) async unsafe extern "C" fn foo$0() {}"#,
             expect![[r#"
                 *foo*
 
                 ```rust
-                test::m
+                test
                 ```
 
                 ```rust
@@ -1475,18 +1489,11 @@ extern crate st$0d;
 //! abc123
             "#,
             expect![[r#"
-                *std*
-
-                ```rust
-                extern crate std
-                ```
+            *std*
+            Standard library for this test
 
-                ---
-
-                Standard library for this test
-
-                Printed?
-                abc123
+            Printed?
+            abc123
             "#]],
         );
         check(
@@ -1500,18 +1507,11 @@ extern crate std as ab$0c;
 //! abc123
             "#,
             expect![[r#"
-                *abc*
-
-                ```rust
-                extern crate std
-                ```
-
-                ---
+            *abc*
+            Standard library for this test
 
-                Standard library for this test
-
-                Printed?
-                abc123
+            Printed?
+            abc123
             "#]],
         );
     }
@@ -2021,7 +2021,7 @@ enum E {
                 ```
 
                 ```rust
-                V { field: i32 }
+                V
                 ```
 
                 ---
@@ -2417,7 +2417,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; }
                                     focus_range: 24..25,
                                     name: "S",
                                     kind: Struct,
-                                    description: "struct S<T>",
+                                    description: "struct S",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2463,7 +2463,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
                                     focus_range: 24..25,
                                     name: "S",
                                     kind: Struct,
-                                    description: "struct S<T>",
+                                    description: "struct S",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2605,7 +2605,7 @@ fn main() { let s$0t = foo(); }
                                     focus_range: 6..9,
                                     name: "Foo",
                                     kind: Trait,
-                                    description: "trait Foo<T>",
+                                    description: "trait Foo",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2702,7 +2702,7 @@ fn main() { let s$0t = foo(); }
                                     focus_range: 6..9,
                                     name: "Foo",
                                     kind: Trait,
-                                    description: "trait Foo<T>",
+                                    description: "trait Foo",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2715,7 +2715,7 @@ fn main() { let s$0t = foo(); }
                                     focus_range: 22..25,
                                     name: "Bar",
                                     kind: Trait,
-                                    description: "trait Bar<T>",
+                                    description: "trait Bar",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2819,7 +2819,7 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {}
                                     focus_range: 19..22,
                                     name: "Bar",
                                     kind: Trait,
-                                    description: "trait Bar<T>",
+                                    description: "trait Bar",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2916,7 +2916,7 @@ fn foo(ar$0g: &impl Foo<S>) {}
                                     focus_range: 6..9,
                                     name: "Foo",
                                     kind: Trait,
-                                    description: "trait Foo<T>",
+                                    description: "trait Foo",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2966,7 +2966,7 @@ fn main() { let s$0t = foo(); }
                                     focus_range: 49..50,
                                     name: "B",
                                     kind: Struct,
-                                    description: "struct B<T>",
+                                    description: "struct B",
                                 },
                             },
                             HoverGotoTypeData {
@@ -3042,7 +3042,7 @@ fn foo(ar$0g: &dyn Foo<S>) {}
                                     focus_range: 6..9,
                                     name: "Foo",
                                     kind: Trait,
-                                    description: "trait Foo<T>",
+                                    description: "trait Foo",
                                 },
                             },
                             HoverGotoTypeData {
@@ -3090,7 +3090,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
                                     focus_range: 6..15,
                                     name: "ImplTrait",
                                     kind: Trait,
-                                    description: "trait ImplTrait<T>",
+                                    description: "trait ImplTrait",
                                 },
                             },
                             HoverGotoTypeData {
@@ -3103,7 +3103,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
                                     focus_range: 50..51,
                                     name: "B",
                                     kind: Struct,
-                                    description: "struct B<T>",
+                                    description: "struct B",
                                 },
                             },
                             HoverGotoTypeData {
@@ -3116,7 +3116,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
                                     focus_range: 28..36,
                                     name: "DynTrait",
                                     kind: Trait,
-                                    description: "trait DynTrait<T>",
+                                    description: "trait DynTrait",
                                 },
                             },
                             HoverGotoTypeData {
@@ -3582,17 +3582,6 @@ mod foo$0;
 "#,
             expect![[r#"
                 *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                mod foo
-                ```
-
-                ---
-
                 For the horde!
             "#]],
         );
@@ -3617,7 +3606,7 @@ use foo::bar::{self$0};
                 ```
 
                 ```rust
-                mod bar
+                pub mod bar
                 ```
 
                 ---
@@ -3668,43 +3657,4 @@ cosnt _: &str$0 = ""; }"#;
             "#]],
         );
     }
-
-    #[test]
-    fn hover_macro_expanded_function() {
-        check(
-            r#"
-struct S<'a, T>(&'a T);
-trait Clone {}
-macro_rules! foo {
-    () => {
-        fn bar<'t, T: Clone + 't>(s: &mut S<'t, T>, t: u32) -> *mut u32 where
-            't: 't + 't,
-            for<'a> T: Clone + 'a
-        { 0 as _ }
-    };
-}
-
-foo!();
-
-fn main() {
-    bar$0;
-}
-"#,
-            expect![[r#"
-                *bar*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32
-                where
-                    T: Clone + 't,
-                    't: 't + 't,
-                    for<'a> T: Clone + 'a,
-                ```
-            "#]],
-        )
-    }
 }
diff --git a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
index b8834d283d..aa7072f25c 100644
--- a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
+++ b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
@@ -1,7 +1,7 @@
 use hir::{known, HasSource, Name};
 use syntax::{
     ast::{self, NameOwner},
-    AstNode,
+    AstNode, TextRange,
 };
 
 use crate::{
@@ -51,19 +51,12 @@ pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext)
     }
 
     let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?;
-    let len_fn = get_impl_method(ctx, &impl_, &known::len)?;
-    if !len_fn.ret_type(ctx.sema.db).is_usize() {
-        cov_mark::hit!(len_fn_different_return_type);
-        return None;
-    }
-
     if get_impl_method(ctx, &impl_, &known::is_empty).is_some() {
         cov_mark::hit!(is_empty_already_implemented);
         return None;
     }
 
-    let node = len_fn.source(ctx.sema.db)?;
-    let range = node.syntax().value.text_range();
+    let range = get_text_range_of_len_function(ctx, &impl_)?;
 
     acc.add(
         AssistId("generate_is_empty_from_len", AssistKind::Generate),
@@ -96,6 +89,13 @@ fn get_impl_method(
     ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func))
 }
 
+fn get_text_range_of_len_function(ctx: &AssistContext, impl_: &ast::Impl) -> Option<TextRange> {
+    let db = ctx.sema.db;
+    let func = get_impl_method(ctx, impl_, &known::len)?;
+    let node = func.source(db)?;
+    Some(node.syntax().value.text_range())
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -157,23 +157,6 @@ impl MyStruct {
         );
     }
 
-    #[test]
-    fn len_fn_different_return_type() {
-        cov_mark::check!(len_fn_different_return_type);
-        check_assist_not_applicable(
-            generate_is_empty_from_len,
-            r#"
-struct MyStruct { data: Vec<String> }
-
-impl MyStruct {
-    p$0ub fn len(&self) -> u32 {
-        self.data.len()
-    }
-}
-"#,
-        );
-    }
-
     #[test]
     fn generate_is_empty() {
         check_assist(
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index cec2d0c3a3..5ee9a9f077 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -81,7 +81,7 @@ fn foo(s: S) { s.$0 }
 "#,
             expect![[r#"
                 fd foo   u32
-                me bar() fn(&self)
+                me bar() -> ()
             "#]],
         );
     }
@@ -97,7 +97,7 @@ impl S {
 "#,
             expect![[r#"
                 fd the_field (u32,)
-                me foo()     fn(self)
+                me foo()     -> ()
             "#]],
         )
     }
@@ -113,7 +113,7 @@ impl A {
 "#,
             expect![[r#"
                 fd the_field (u32, i32)
-                me foo()     fn(&self)
+                me foo()     -> ()
             "#]],
         )
     }
@@ -163,7 +163,7 @@ mod m {
 fn foo(a: A) { a.$0 }
 "#,
             expect![[r#"
-                me the_method() fn(&self)
+                me the_method() -> ()
             "#]],
         );
     }
@@ -196,7 +196,7 @@ impl A<i32> {
 fn foo(a: A<u32>) { a.$0 }
 "#,
             expect![[r#"
-                me the_method() fn(&self)
+                me the_method() -> ()
             "#]],
         )
     }
@@ -211,7 +211,7 @@ impl Trait for A {}
 fn foo(a: A) { a.$0 }
 "#,
             expect![[r#"
-                me the_method() fn(&self)
+                me the_method() -> ()
             "#]],
         );
     }
@@ -226,7 +226,7 @@ impl<T> Trait for T {}
 fn foo(a: &A) { a.$0 }
 ",
             expect![[r#"
-                me the_method() fn(&self)
+                me the_method() -> ()
             "#]],
         );
     }
@@ -244,7 +244,7 @@ impl Trait for A {}
 fn foo(a: A) { a.$0 }
 ",
             expect![[r#"
-                me the_method() fn(&self)
+                me the_method() -> ()
             "#]],
         );
     }
@@ -298,7 +298,7 @@ impl T {
 }
 "#,
             expect![[r#"
-                me blah() fn(&self)
+                me blah() -> ()
             "#]],
         );
     }
@@ -407,7 +407,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-                me the_method() fn(&self)
+                me the_method() -> ()
             "#]],
         );
     }
@@ -422,7 +422,7 @@ macro_rules! make_s { () => { S }; }
 fn main() { make_s!().f$0; }
 "#,
             expect![[r#"
-                me foo() fn(&self)
+                me foo() -> ()
             "#]],
         )
     }
@@ -450,7 +450,7 @@ mod foo {
 }
         "#,
             expect![[r#"
-                me private() fn(&self)
+                me private() -> ()
             "#]],
         );
     }
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 08df2df3f6..391a11c91c 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -402,7 +402,7 @@ fn main() {
         check(
             fixture,
             expect![[r#"
-                fn weird_function() (dep::test_mod::TestTrait) fn()
+                fn weird_function() (dep::test_mod::TestTrait) -> ()
             "#]],
         );
 
@@ -495,7 +495,7 @@ fn main() {
         check(
             fixture,
             expect![[r#"
-                me random_method() (dep::test_mod::TestTrait) fn(&self)
+                me random_method() (dep::test_mod::TestTrait) -> ()
             "#]],
         );
 
@@ -665,7 +665,7 @@ fn main() {
 }
         "#,
             expect![[r#"
-                me random_method() (dep::test_mod::TestTrait) fn(&self) DEPRECATED
+                me random_method() (dep::test_mod::TestTrait) -> () DEPRECATED
             "#]],
         );
 
@@ -696,7 +696,7 @@ fn main() {
 "#,
             expect![[r#"
                 ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED
-                fn weird_function() (dep::test_mod::TestTrait) fn() DEPRECATED
+                fn weird_function() (dep::test_mod::TestTrait) -> () DEPRECATED
             "#]],
         );
     }
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 105ff60131..df74b739e9 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -359,8 +359,8 @@ impl S {
 fn foo() { let _ = S::$0 }
 "#,
             expect![[r#"
-                fn a()  fn()
-                me b(…) fn(&self)
+                fn a()  -> ()
+                me b(…) -> ()
                 ct C    const C: i32 = 42;
                 ta T    type T = i32;
             "#]],
@@ -387,7 +387,7 @@ mod m {
 fn foo() { let _ = S::$0 }
 "#,
             expect![[r#"
-                fn public_method() fn()
+                fn public_method() -> ()
                 ct PUBLIC_CONST    pub(crate) const PUBLIC_CONST: u32 = 1;
                 ta PublicType      pub(crate) type PublicType = u32;
             "#]],
@@ -404,7 +404,7 @@ impl E { fn m() { } }
 fn foo() { let _ = E::$0 }
         "#,
             expect![[r#"
-                fn m() fn()
+                fn m() -> ()
             "#]],
         );
     }
@@ -419,7 +419,7 @@ impl U { fn m() { } }
 fn foo() { let _ = U::$0 }
 "#,
             expect![[r#"
-                fn m() fn()
+                fn m() -> ()
             "#]],
         );
     }
@@ -449,7 +449,7 @@ trait Trait { fn m(); }
 fn foo() { let _ = Trait::$0 }
 "#,
             expect![[r#"
-                fn m() fn()
+                fn m() -> ()
             "#]],
         );
     }
@@ -466,7 +466,7 @@ impl Trait for S {}
 fn foo() { let _ = S::$0 }
 "#,
             expect![[r#"
-                fn m() fn()
+                fn m() -> ()
             "#]],
         );
     }
@@ -483,7 +483,7 @@ impl Trait for S {}
 fn foo() { let _ = <S as Trait>::$0 }
 "#,
             expect![[r#"
-                fn m() fn()
+                fn m() -> ()
             "#]],
         );
     }
@@ -512,11 +512,11 @@ fn foo<T: Sub>() { T::$0 }
                 ta SubTy        type SubTy;
                 ta Ty           type Ty;
                 ct C2           const C2: ();
-                fn subfunc()    fn()
-                me submethod(…) fn(&self)
+                fn subfunc()    -> ()
+                me submethod(…) -> ()
                 ct CONST        const CONST: u8;
-                fn func()       fn()
-                me method(…)    fn(&self)
+                fn func()       -> ()
+                me method(…)    -> ()
             "#]],
         );
     }
@@ -552,11 +552,11 @@ impl<T> Sub for Wrap<T> {
                 ta SubTy        type SubTy;
                 ta Ty           type Ty;
                 ct CONST        const CONST: u8 = 0;
-                fn func()       fn()
-                me method(…)    fn(&self)
+                fn func()       -> ()
+                me method(…)    -> ()
                 ct C2           const C2: () = ();
-                fn subfunc()    fn()
-                me submethod(…) fn(&self)
+                fn subfunc()    -> ()
+                me submethod(…) -> ()
             "#]],
         );
     }
@@ -573,8 +573,8 @@ impl T { fn bar() {} }
 fn main() { T::$0; }
 "#,
             expect![[r#"
-                fn foo() fn()
-                fn bar() fn()
+                fn foo() -> ()
+                fn bar() -> ()
             "#]],
         );
     }
@@ -589,7 +589,7 @@ macro_rules! foo { () => {} }
 fn main() { let _ = crate::$0 }
         "#,
             expect![[r##"
-                fn main()  fn()
+                fn main()  -> ()
                 ma foo!(…) #[macro_export] macro_rules! foo
             "##]],
         );
@@ -633,7 +633,7 @@ mod p {
 "#,
             expect![[r#"
                 ct RIGHT_CONST
-                fn right_fn()  fn()
+                fn right_fn()  -> ()
                 st RightType
             "#]],
         );
@@ -680,8 +680,8 @@ fn main() { m!(self::f$0); }
 fn foo() {}
 "#,
             expect![[r#"
-                fn main() fn()
-                fn foo()  fn()
+                fn main() -> ()
+                fn foo()  -> ()
             "#]],
         );
     }
@@ -699,7 +699,7 @@ mod m {
 "#,
             expect![[r#"
                 md z
-                fn z() fn()
+                fn z() -> ()
             "#]],
         );
     }
@@ -719,7 +719,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-                fn new() fn() -> HashMap<K, V, RandomState>
+                fn new() -> HashMap<K, V, RandomState>
             "#]],
         );
     }
@@ -752,8 +752,8 @@ fn main() {
 }
 "#,
             expect![[r#"
-                fn main() fn()
-                fn foo(…) fn(i32, i32)
+                fn main() -> ()
+                fn foo(…) -> ()
             "#]],
         );
     }
@@ -776,7 +776,7 @@ impl Foo {
             expect![[r#"
                 ev Bar    ()
                 ev Baz    ()
-                me foo(…) fn(self)
+                me foo(…) -> ()
             "#]],
         );
     }
@@ -800,7 +800,7 @@ impl u8 {
 "#,
             expect![[r#"
                 ct MAX     pub const MAX: Self = 255;
-                me func(…) fn(self)
+                me func(…) -> ()
             "#]],
         );
     }
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 1b8b063e7d..5ef80f6a72 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -135,7 +135,7 @@ fn quux(x: i32) {
             expect![[r#"
                 lc y       i32
                 lc x       i32
-                fn quux(…) fn(i32)
+                fn quux(…) -> ()
             "#]],
         );
     }
@@ -157,7 +157,7 @@ fn quux() {
             expect![[r#"
                 lc b      i32
                 lc a
-                fn quux() fn()
+                fn quux() -> ()
             "#]],
         );
     }
@@ -172,7 +172,7 @@ fn quux() {
 "#,
             expect![[r#"
                 lc x
-                fn quux() fn()
+                fn quux() -> ()
             "#]],
         );
     }
@@ -203,14 +203,14 @@ fn main() {
             r#"fn quux<T>() { $0 }"#,
             expect![[r#"
                 tp T
-                fn quux() fn()
+                fn quux() -> ()
             "#]],
         );
         check(
             r#"fn quux<const C: usize>() { $0 }"#,
             expect![[r#"
                 cp C
-                fn quux() fn()
+                fn quux() -> ()
             "#]],
         );
     }
@@ -221,7 +221,7 @@ fn main() {
         check(
             r#"fn quux<'a>() { $0 }"#,
             expect![[r#"
-                fn quux() fn()
+                fn quux() -> ()
             "#]],
         );
     }
@@ -259,7 +259,7 @@ fn quux() { $0 }
 "#,
             expect![[r#"
                 st S
-                fn quux() fn()
+                fn quux() -> ()
                 en E
             "#]],
         );
@@ -312,7 +312,7 @@ mod m {
 }
 "#,
             expect![[r#"
-                fn quux() fn()
+                fn quux() -> ()
                 st Bar
             "#]],
         );
@@ -327,7 +327,7 @@ fn x() -> $0
 "#,
             expect![[r#"
                 st Foo
-                fn x() fn()
+                fn x() -> ()
             "#]],
         );
     }
@@ -348,7 +348,7 @@ fn foo() {
             expect![[r#"
                 lc bar   i32
                 lc bar   i32
-                fn foo() fn()
+                fn foo() -> ()
             "#]],
         );
     }
@@ -378,7 +378,7 @@ use prelude::*;
 mod prelude { struct Option; }
 "#,
             expect![[r#"
-                fn foo()  fn()
+                fn foo()  -> ()
                 md std
                 st Option
             "#]],
@@ -408,7 +408,7 @@ mod macros {
 }
 "#,
             expect![[r##"
-                fn f()        fn()
+                fn f()        -> ()
                 ma concat!(…) #[macro_export] macro_rules! concat
                 md std
             "##]],
@@ -435,7 +435,7 @@ use prelude::*;
 mod prelude { struct String; }
 "#,
             expect![[r#"
-                fn foo()  fn()
+                fn foo()  -> ()
                 md std
                 md core
                 st String
@@ -466,7 +466,7 @@ fn main() { let v = $0 }
             expect![[r##"
                 md m1
                 ma baz!(…) #[macro_export] macro_rules! baz
-                fn main()  fn()
+                fn main()  -> ()
                 md m2
                 ma bar!(…) macro_rules! bar
                 ma foo!(…) macro_rules! foo
@@ -482,7 +482,7 @@ macro_rules! foo { () => {} }
 fn foo() { $0 }
 "#,
             expect![[r#"
-                fn foo()   fn()
+                fn foo()   -> ()
                 ma foo!(…) macro_rules! foo
             "#]],
         );
@@ -496,7 +496,7 @@ macro_rules! foo { () => {} }
 fn main() { let x: $0 }
 "#,
             expect![[r#"
-                fn main()  fn()
+                fn main()  -> ()
                 ma foo!(…) macro_rules! foo
             "#]],
         );
@@ -510,7 +510,7 @@ macro_rules! foo { () => {} }
 fn main() { $0 }
 "#,
             expect![[r#"
-                fn main()  fn()
+                fn main()  -> ()
                 ma foo!(…) macro_rules! foo
             "#]],
         );
@@ -526,8 +526,8 @@ fn main() {
 }
 "#,
             expect![[r#"
-                fn frobnicate() fn()
-                fn main()       fn()
+                fn frobnicate() -> ()
+                fn main()       -> ()
             "#]],
         );
     }
@@ -545,7 +545,7 @@ fn quux(x: i32) {
             expect![[r#"
                 lc y       i32
                 lc x       i32
-                fn quux(…) fn(i32)
+                fn quux(…) -> ()
                 ma m!(…)   macro_rules! m
             "#]],
         );
@@ -564,7 +564,7 @@ fn quux(x: i32) {
             expect![[r#"
                 lc y       i32
                 lc x       i32
-                fn quux(…) fn(i32)
+                fn quux(…) -> ()
                 ma m!(…)   macro_rules! m
             "#]],
         );
@@ -583,7 +583,7 @@ fn quux(x: i32) {
             expect![[r#"
                 lc y       i32
                 lc x       i32
-                fn quux(…) fn(i32)
+                fn quux(…) -> ()
                 ma m!(…)   macro_rules! m
             "#]],
         );
@@ -598,7 +598,7 @@ use spam::Quux;
 fn main() { $0 }
 "#,
             expect![[r#"
-                fn main() fn()
+                fn main() -> ()
                 ?? Quux
             "#]],
         );
@@ -616,7 +616,7 @@ fn main() { let foo: Foo = Q$0 }
                 ev Foo::Baz  ()
                 ev Foo::Quux ()
                 en Foo
-                fn main()    fn()
+                fn main()    -> ()
             "#]],
         )
     }
@@ -631,7 +631,7 @@ fn f() -> m::E { V$0 }
             expect![[r#"
                 ev m::E::V ()
                 md m
-                fn f()     fn() -> E
+                fn f()     -> E
             "#]],
         )
     }
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 5b7ad38d5f..263554ecf7 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -230,7 +230,7 @@ fn foo() {
     bar.fo$0;
 }
 "#,
-            DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" },
+            DetailAndDocumentation { detail: "-> ()", documentation: "Do the foo" },
         );
     }
 
@@ -255,7 +255,7 @@ fn foo() {
     bar.fo$0;
 }
 "#,
-            DetailAndDocumentation { detail: "fn(&self)", documentation: " Do the foo" },
+            DetailAndDocumentation { detail: "-> ()", documentation: " Do the foo" },
         );
     }
 
@@ -273,7 +273,7 @@ fn bar() {
     for c in fo$0
 }
 "#,
-            DetailAndDocumentation { detail: "fn() -> &str", documentation: "Do the foo" },
+            DetailAndDocumentation { detail: "-> &str", documentation: "Do the foo" },
         );
     }
 }
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 36655667c2..2514dda7c7 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -10,8 +10,10 @@ pub(crate) mod type_alias;
 
 mod builder_ext;
 
+use base_db::Upcast;
 use hir::{
-    AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type,
+    db::HirDatabase, AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability,
+    ScopeDef, Type,
 };
 use ide_db::{
     helpers::{item_name, SnippetCap},
@@ -20,8 +22,8 @@ use ide_db::{
 use syntax::TextRange;
 
 use crate::{
-    item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
-    CompletionRelevance,
+    item::{CompletionRelevance, ImportEdit},
+    CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
 };
 
 use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro};
@@ -142,15 +144,7 @@ impl<'a> Render<'a> {
             .set_documentation(field.docs(self.ctx.db()))
             .set_deprecated(is_deprecated);
 
-        item.set_relevance(CompletionRelevance {
-            exact_type_match: compute_exact_type_match(self.ctx.completion, ty),
-            exact_name_match: compute_exact_name_match(self.ctx.completion, name.to_string()),
-            ..CompletionRelevance::default()
-        });
-
-        if let Some(ref_match) = compute_ref_match(self.ctx.completion, ty) {
-            item.ref_match(ref_match);
-        }
+        item.set_relevance(compute_relevance(&self.ctx, &ty, &name.to_string()));
 
         item.build()
     }
@@ -240,18 +234,31 @@ impl<'a> Render<'a> {
             if !ty.is_unknown() {
                 item.detail(ty.display(self.ctx.db()).to_string());
             }
+        };
 
-            item.set_relevance(CompletionRelevance {
-                exact_type_match: compute_exact_type_match(self.ctx.completion, &ty),
-                exact_name_match: compute_exact_name_match(self.ctx.completion, local_name.clone()),
-                is_local: true,
-                ..CompletionRelevance::default()
-            });
+        if let ScopeDef::Local(local) = resolution {
+            let ty = local.ty(self.ctx.db());
 
-            if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ty) {
-                item.ref_match(ref_match);
+            let mut relevance = compute_relevance(&self.ctx, &ty, &local_name);
+            relevance.is_local = true;
+            item.set_relevance(relevance);
+
+            if let Some(expected_type) = self.ctx.completion.expected_type.as_ref() {
+                if &ty != expected_type {
+                    if let Some(ty_without_ref) = expected_type.remove_ref() {
+                        if relevance_type_match(self.ctx.db().upcast(), &ty, &ty_without_ref) {
+                            cov_mark::hit!(suggest_ref);
+                            let mutability = if expected_type.is_mutable_reference() {
+                                Mutability::Mut
+                            } else {
+                                Mutability::Shared
+                            };
+                            item.ref_match(mutability);
+                        }
+                    }
+                }
             }
-        };
+        }
 
         // Add `<>` for generic types
         if self.ctx.completion.is_path_type
@@ -306,44 +313,17 @@ impl<'a> Render<'a> {
     }
 }
 
-fn compute_exact_type_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> bool {
-    if let Some(expected_type) = ctx.expected_type.as_ref() {
-        // We don't ever consider unit type to be an exact type match, since
-        // nearly always this is not meaningful to the user.
-        completion_ty == expected_type && !expected_type.is_unit()
-    } else {
-        false
-    }
-}
+fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> CompletionRelevance {
+    let mut res = CompletionRelevance::default();
 
-fn compute_exact_name_match(ctx: &CompletionContext, completion_name: impl Into<String>) -> bool {
-    let completion_name = completion_name.into();
+    res.exact_type_match = Some(ty) == ctx.completion.expected_type.as_ref();
+    res.exact_name_match = Some(name) == ctx.completion.expected_name.as_deref();
 
-    Some(&completion_name) == ctx.expected_name.as_ref()
+    res
 }
 
-fn compute_ref_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> Option<Mutability> {
-    let mut ref_match = None;
-    if let Some(expected_type) = &ctx.expected_type {
-        if completion_ty != expected_type {
-            if let Some(expected_type_without_ref) = expected_type.remove_ref() {
-                if completion_ty == &expected_type_without_ref
-                    || completion_ty
-                        .autoderef(ctx.db)
-                        .any(|deref_ty| deref_ty == expected_type_without_ref)
-                {
-                    cov_mark::hit!(suggest_ref);
-                    let mutability = if expected_type.is_mutable_reference() {
-                        Mutability::Mut
-                    } else {
-                        Mutability::Shared
-                    };
-                    ref_match = Some(mutability);
-                }
-            }
-        }
-    };
-    ref_match
+fn relevance_type_match(db: &dyn HirDatabase, ty: &Type, expected_type: &Type) -> bool {
+    ty == expected_type || ty.autoderef(db).any(|deref_ty| &deref_ty == expected_type)
 }
 
 #[cfg(test)]
@@ -451,44 +431,6 @@ fn main() { Foo::Fo$0 }
         );
     }
 
-    #[test]
-    fn fn_detail_includes_args_and_return_type() {
-        check(
-            r#"
-fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }
-
-fn main() { fo$0 }
-"#,
-            expect![[r#"
-                [
-                    CompletionItem {
-                        label: "foo(…)",
-                        source_range: 68..70,
-                        delete: 68..70,
-                        insert: "foo(${1:a}, ${2:b}, ${3:t})$0",
-                        kind: SymbolKind(
-                            Function,
-                        ),
-                        lookup: "foo",
-                        detail: "fn(u32, u32, T) -> (u32, T)",
-                        trigger_call_info: true,
-                    },
-                    CompletionItem {
-                        label: "main()",
-                        source_range: 68..70,
-                        delete: 68..70,
-                        insert: "main()$0",
-                        kind: SymbolKind(
-                            Function,
-                        ),
-                        lookup: "main",
-                        detail: "fn()",
-                    },
-                ]
-            "#]],
-        );
-    }
-
     #[test]
     fn enum_detail_just_parentheses_for_unit() {
         check(
@@ -535,11 +477,6 @@ fn main() { let _: m::Spam = S$0 }
                         ),
                         lookup: "Spam::Bar",
                         detail: "(i32)",
-                        relevance: CompletionRelevance {
-                            exact_name_match: false,
-                            exact_type_match: true,
-                            is_local: false,
-                        },
                         trigger_call_info: true,
                     },
                     CompletionItem {
@@ -561,11 +498,6 @@ fn main() { let _: m::Spam = S$0 }
                         ),
                         lookup: "Spam::Foo",
                         detail: "()",
-                        relevance: CompletionRelevance {
-                            exact_name_match: false,
-                            exact_type_match: true,
-                            is_local: false,
-                        },
                     },
                     CompletionItem {
                         label: "main()",
@@ -576,7 +508,7 @@ fn main() { let _: m::Spam = S$0 }
                             Function,
                         ),
                         lookup: "main",
-                        detail: "fn()",
+                        detail: "-> ()",
                     },
                 ]
             "#]],
@@ -605,7 +537,7 @@ fn main() { som$0 }
                             Function,
                         ),
                         lookup: "main",
-                        detail: "fn()",
+                        detail: "-> ()",
                     },
                     CompletionItem {
                         label: "something_deprecated()",
@@ -616,7 +548,7 @@ fn main() { som$0 }
                             Function,
                         ),
                         lookup: "something_deprecated",
-                        detail: "fn()",
+                        detail: "-> ()",
                         deprecated: true,
                     },
                     CompletionItem {
@@ -628,7 +560,7 @@ fn main() { som$0 }
                             Function,
                         ),
                         lookup: "something_else_deprecated",
-                        detail: "fn()",
+                        detail: "-> ()",
                         deprecated: true,
                     },
                 ]
@@ -679,7 +611,7 @@ impl S {
                         insert: "bar()$0",
                         kind: Method,
                         lookup: "bar",
-                        detail: "fn(self)",
+                        detail: "-> ()",
                         documentation: Documentation(
                             "Method docs",
                         ),
@@ -779,7 +711,7 @@ fn foo(s: S) { s.$0 }
                         insert: "the_method()$0",
                         kind: Method,
                         lookup: "the_method",
-                        detail: "fn(&self)",
+                        detail: "-> ()",
                     },
                 ]
             "#]],
@@ -1087,7 +1019,7 @@ fn main() {
                             Function,
                         ),
                         lookup: "foo",
-                        detail: "fn(&mut S)",
+                        detail: "-> ()",
                         trigger_call_info: true,
                     },
                     CompletionItem {
@@ -1099,7 +1031,7 @@ fn main() {
                             Function,
                         ),
                         lookup: "main",
-                        detail: "fn()",
+                        detail: "-> ()",
                     },
                     CompletionItem {
                         label: "s",
@@ -1237,86 +1169,4 @@ fn foo(bar: u32) {
             "#]],
         );
     }
-
-    #[test]
-    fn enum_owned() {
-        check_relevance(
-            r#"
-enum Foo { A, B }
-fn foo() {
-    bar($0);
-}
-fn bar(t: Foo) {}
-"#,
-            expect![[r#"
-                ev Foo::A [type]
-                ev Foo::B [type]
-                en Foo []
-                fn bar(…) []
-                fn foo() []
-            "#]],
-        );
-    }
-
-    #[test]
-    fn enum_ref() {
-        check_relevance(
-            r#"
-enum Foo { A, B }
-fn foo() {
-    bar($0);
-}
-fn bar(t: &Foo) {}
-"#,
-            expect![[r#"
-                ev Foo::A []
-                ev &Foo::A [type]
-                ev Foo::B []
-                ev &Foo::B [type]
-                en Foo []
-                fn bar(…) []
-                fn foo() []
-            "#]],
-        );
-    }
-
-    #[test]
-    fn suggest_deref_fn_ret() {
-        check_relevance(
-            r#"
-#[lang = "deref"]
-trait Deref {
-    type Target;
-    fn deref(&self) -> &Self::Target;
-}
-
-struct S;
-struct T(S);
-
-impl Deref for T {
-    type Target = S;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-fn foo(s: &S) {}
-fn bar() -> T {}
-
-fn main() {
-    foo($0);
-}
-            "#,
-            expect![[r#"
-                tt Deref []
-                fn bar() []
-                fn &bar() [type]
-                fn foo(…) []
-                st T []
-                st S []
-                fn main() []
-            "#]],
-        )
-    }
 }
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs
index 374247b056..e8cfcc0c7b 100644
--- a/crates/ide_completion/src/render/enum_variant.rs
+++ b/crates/ide_completion/src/render/enum_variant.rs
@@ -6,8 +6,7 @@ use itertools::Itertools;
 
 use crate::{
     item::{CompletionItem, CompletionKind, ImportEdit},
-    render::{builder_ext::Params, compute_exact_type_match, compute_ref_match, RenderContext},
-    CompletionRelevance,
+    render::{builder_ext::Params, RenderContext},
 };
 
 pub(crate) fn render_variant<'a>(
@@ -75,16 +74,6 @@ impl<'a> EnumRender<'a> {
             item.lookup_by(self.short_qualified_name);
         }
 
-        let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db);
-        item.set_relevance(CompletionRelevance {
-            exact_type_match: compute_exact_type_match(self.ctx.completion, &ty),
-            ..CompletionRelevance::default()
-        });
-
-        if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ty) {
-            item.ref_match(ref_match);
-        }
-
         item.build()
     }
 
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 0103031829..47e26a5d8d 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -2,15 +2,11 @@
 
 use hir::{HasSource, HirDisplay, Type};
 use ide_db::SymbolKind;
-use itertools::Itertools;
 use syntax::ast::Fn;
 
 use crate::{
     item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit},
-    render::{
-        builder_ext::Params, compute_exact_name_match, compute_exact_type_match, compute_ref_match,
-        RenderContext,
-    },
+    render::{builder_ext::Params, RenderContext},
 };
 
 pub(crate) fn render_fn<'a>(
@@ -56,60 +52,30 @@ impl<'a> FunctionRender<'a> {
                 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
             )
             .detail(self.detail())
-            .add_call_parens(self.ctx.completion, self.name.clone(), params)
+            .add_call_parens(self.ctx.completion, self.name, params)
             .add_import(import_to_add);
 
-        let ret_type = self.func.ret_type(self.ctx.db());
-        item.set_relevance(CompletionRelevance {
-            exact_type_match: compute_exact_type_match(self.ctx.completion, &ret_type),
-            exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()),
-            ..CompletionRelevance::default()
-        });
+        let mut relevance = CompletionRelevance::default();
+        if let Some(expected_type) = &self.ctx.completion.expected_type {
+            let ret_ty = self.func.ret_type(self.ctx.db());
 
-        if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ret_type) {
-            item.ref_match(ref_match);
+            // We don't ever consider a function which returns unit type to be an
+            // exact type match, since nearly always this is not meaningful to the
+            // user.
+            relevance.exact_type_match = &ret_ty == expected_type && !ret_ty.is_unit();
         }
+        if let Some(expected_name) = &self.ctx.completion.expected_name {
+            relevance.exact_name_match =
+                expected_name == &self.func.name(self.ctx.db()).to_string();
+        }
+        item.set_relevance(relevance);
 
         item.build()
     }
 
     fn detail(&self) -> String {
-        let ret_ty = self.func.ret_type(self.ctx.db());
-        let ret = if ret_ty.is_unit() {
-            // Omit the return type if it is the unit type
-            String::new()
-        } else {
-            format!(" {}", self.ty_display())
-        };
-
-        format!("fn({}){}", self.params_display(), ret)
-    }
-
-    fn params_display(&self) -> String {
-        if let Some(self_param) = self.func.self_param(self.ctx.db()) {
-            let params = self
-                .func
-                .assoc_fn_params(self.ctx.db())
-                .into_iter()
-                .skip(1) // skip the self param because we are manually handling that
-                .map(|p| p.ty().display(self.ctx.db()).to_string());
-
-            std::iter::once(self_param.display(self.ctx.db()).to_owned()).chain(params).join(", ")
-        } else {
-            let params = self
-                .func
-                .assoc_fn_params(self.ctx.db())
-                .into_iter()
-                .map(|p| p.ty().display(self.ctx.db()).to_string())
-                .join(", ");
-            params
-        }
-    }
-
-    fn ty_display(&self) -> String {
-        let ret_ty = self.func.ret_type(self.ctx.db());
-
-        format!("-> {}", ret_ty.display(self.ctx.db()))
+        let ty = self.func.ret_type(self.ctx.db());
+        format!("-> {}", ty.display(self.ctx.db()))
     }
 
     fn add_arg(&self, arg: &str, ty: &Type) -> String {
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index cebb8f4008..6c0e227227 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -63,11 +63,11 @@ pub(crate) mod fragments {
     }
 
     pub(crate) fn stmt(p: &mut Parser) {
-        expressions::stmt(p, expressions::StmtWithSemi::No, true)
+        expressions::stmt(p, expressions::StmtWithSemi::No)
     }
 
     pub(crate) fn stmt_optional_semi(p: &mut Parser) {
-        expressions::stmt(p, expressions::StmtWithSemi::Optional, false)
+        expressions::stmt(p, expressions::StmtWithSemi::Optional)
     }
 
     pub(crate) fn opt_visibility(p: &mut Parser) {
@@ -133,7 +133,7 @@ pub(crate) mod fragments {
                 continue;
             }
 
-            expressions::stmt(p, expressions::StmtWithSemi::Optional, true);
+            expressions::stmt(p, expressions::StmtWithSemi::Optional);
         }
 
         m.complete(p, MACRO_STMTS);
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 0d9dc93489..5f885edfd5 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -54,7 +54,7 @@ fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
     !forbid
 }
 
-pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
+pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
     let m = p.start();
     // test attr_on_expr_stmt
     // fn foo() {
@@ -90,7 +90,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
         p.error(format!("attributes are not allowed on {:?}", kind));
     }
 
-    if p.at(T!['}']) || (prefer_expr && p.at(EOF)) {
+    if p.at(T!['}']) {
         // test attr_on_last_expr_in_block
         // fn foo() {
         //     { #[A] bar!()? }
@@ -198,7 +198,7 @@ pub(super) fn expr_block_contents(p: &mut Parser) {
             continue;
         }
 
-        stmt(p, StmtWithSemi::Yes, false)
+        stmt(p, StmtWithSemi::Yes)
     }
 }
 
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 6097178b6f..064931aece 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1336,7 +1336,6 @@ pub enum Expr {
     Literal(Literal),
     LoopExpr(LoopExpr),
     MacroCall(MacroCall),
-    MacroStmts(MacroStmts),
     MatchExpr(MatchExpr),
     MethodCallExpr(MethodCallExpr),
     ParenExpr(ParenExpr),
@@ -3035,9 +3034,6 @@ impl From<LoopExpr> for Expr {
 impl From<MacroCall> for Expr {
     fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) }
 }
-impl From<MacroStmts> for Expr {
-    fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
-}
 impl From<MatchExpr> for Expr {
     fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
 }
@@ -3082,8 +3078,8 @@ impl AstNode for Expr {
         match kind {
             ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
             | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR
-            | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS
-            | MATCH_EXPR | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
+            | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MATCH_EXPR
+            | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
             | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
             | YIELD_EXPR => true,
             _ => false,
@@ -3109,7 +3105,6 @@ impl AstNode for Expr {
             LITERAL => Expr::Literal(Literal { syntax }),
             LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
             MACRO_CALL => Expr::MacroCall(MacroCall { syntax }),
-            MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
             MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
             METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
             PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
@@ -3147,7 +3142,6 @@ impl AstNode for Expr {
             Expr::Literal(it) => &it.syntax,
             Expr::LoopExpr(it) => &it.syntax,
             Expr::MacroCall(it) => &it.syntax,
-            Expr::MacroStmts(it) => &it.syntax,
             Expr::MatchExpr(it) => &it.syntax,
             Expr::MethodCallExpr(it) => &it.syntax,
             Expr::ParenExpr(it) => &it.syntax,
diff --git a/docs/dev/style.md b/docs/dev/style.md
index e4a1672cab..c4eb7bc7ae 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -787,27 +787,6 @@ assert!(0 > x);
 
 **Rationale:** Less-then comparisons are more intuitive, they correspond spatially to [real line](https://en.wikipedia.org/wiki/Real_line).
 
-## If-let
-
-Avoid `if let ... { } else { }` construct, use `match` instead.
-
-```rust
-// GOOD
-match ctx.expected_type.as_ref() {
-    Some(expected_type) => completion_ty == expected_type && !expected_type.is_unit(),
-    None => false,
-}
-
-// BAD
-if let Some(expected_type) = ctx.expected_type.as_ref() {
-    completion_ty == expected_type && !expected_type.is_unit()
-} else {
-    false
-}
-```
-
-**Rational:** `match` is almost always more compact.
-The `else` branch can get a more precise pattern: `None` or `Err(_)` instead of `_`.
 
 ## Token names
 
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index ad93fbe3bd..e084f0df65 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -11,7 +11,7 @@ anyhow = "1.0.26"
 flate2 = "1.0"
 proc-macro2 = "1.0.8"
 quote = "1.0.2"
-ungrammar = "=1.12"
+ungrammar = "=1.11"
 walkdir = "2.3.1"
 write-json = "0.1.0"
 xshell = "0.1"


Test patch:
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index 991a32b150..f8e6f70e87 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -174,6 +174,18 @@ fn f() {
     );
 }
 
+#[test]
+fn unresolved_macro_diag() {
+    check_diagnostics(
+        r#"
+fn f() {
+    m!();
+  //^^^^ unresolved macro call
+}
+      "#,
+    );
+}
+
 #[test]
 fn dollar_crate_in_builtin_macro() {
     check_diagnostics(
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index af4f8bb115..fb3afaedc3 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -215,22 +215,6 @@ fn expr_macro_expanded_in_various_places() {
     );
 }
 
-#[test]
-fn expr_macro_expanded_in_stmts() {
-    check_infer(
-        r#"
-        macro_rules! id { ($($es:tt)*) => { $($es)* } }
-        fn foo() {
-            id! { let a = (); }
-        }
-        "#,
-        expect![[r#"
-            !0..8 'leta=();': ()
-            57..84 '{     ...); } }': ()
-        "#]],
-    );
-}
-
 #[test]
 fn infer_type_value_macro_having_same_name() {
     check_infer(
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index eca0bcc18b..3a168bb4b4 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -662,11 +662,12 @@ fn test_tt_to_stmts() {
         LITERAL@12..13
           INT_NUMBER@12..13 "1"
     SEMICOLON@13..14 ";"
-  PATH_EXPR@14..15
-    PATH@14..15
-      PATH_SEGMENT@14..15
-        NAME_REF@14..15
-          IDENT@14..15 "a""#,
+  EXPR_STMT@14..15
+    PATH_EXPR@14..15
+      PATH@14..15
+        PATH_SEGMENT@14..15
+          NAME_REF@14..15
+            IDENT@14..15 "a""#,
     );
 }