Repository: rust-analyzer/rust-analyzer
Pull request #3968 (2020-04-13 17:24:36)

Remove format from syntax_bridge hot path
Although only around 1% speed up by running:

```
Measure-Command {start-process .\target\release\rust-analyzer "analysis-stats -q ." -NoNewWindow -wait}
```


Patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 00f299ff18..02a3b62287 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -20,14 +20,25 @@ jobs:
     name: Audit Rust vulnerabilities
     runs-on: ubuntu-latest
     steps:
+    - name: Install Rust toolchain
+      uses: actions-rs/toolchain@v1
+      with:
+        toolchain: stable
+        profile: minimal
+        override: true
+
     - name: Checkout repository
       uses: actions/checkout@v2
 
-    - uses: actions-rs/install@v0.1
+    - run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/
+
+    - name: Cache cargo
+      uses: actions/cache@v1
       with:
-        crate: cargo-audit
-        use-tool-cache: true
+        path: ~/.cargo/
+        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
 
+    - run: cargo install cargo-audit
     - run: cargo audit
 
   rust:
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
index 2d6d44980e..722f207e24 100644
--- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
@@ -40,7 +40,7 @@ enum AddMissingImplMembersMode {
 // }
 //
 // impl Trait<u32> for () {
-//     fn foo(&self) -> u32 { todo!() }
+//     fn foo(&self) -> u32 { unimplemented!() }
 //
 // }
 // ```
@@ -165,7 +165,7 @@ fn add_missing_impl_members_inner(
 
 fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
     if fn_def.body().is_none() {
-        fn_def.with_body(make::block_from_expr(make::expr_todo()))
+        fn_def.with_body(make::block_from_expr(make::expr_unimplemented()))
     } else {
         fn_def
     }
@@ -215,8 +215,8 @@ impl Foo for S {
     fn bar(&self) {}
     <|>type Output;
     const CONST: usize = 42;
-    fn foo(&self) { todo!() }
-    fn baz(&self) { todo!() }
+    fn foo(&self) { unimplemented!() }
+    fn baz(&self) { unimplemented!() }
 
 }",
         );
@@ -250,7 +250,7 @@ struct S;
 
 impl Foo for S {
     fn bar(&self) {}
-    <|>fn foo(&self) { todo!() }
+    <|>fn foo(&self) { unimplemented!() }
 
 }",
         );
@@ -268,7 +268,7 @@ impl Foo for S { <|> }",
 trait Foo { fn foo(&self); }
 struct S;
 impl Foo for S {
-    <|>fn foo(&self) { todo!() }
+    <|>fn foo(&self) { unimplemented!() }
 }",
         );
     }
@@ -285,7 +285,7 @@ impl Foo<u32> for S { <|> }",
 trait Foo<T> { fn foo(&self, t: T) -> &T; }
 struct S;
 impl Foo<u32> for S {
-    <|>fn foo(&self, t: u32) -> &u32 { todo!() }
+    <|>fn foo(&self, t: u32) -> &u32 { unimplemented!() }
 }",
         );
     }
@@ -302,7 +302,7 @@ impl<U> Foo<U> for S { <|> }",
 trait Foo<T> { fn foo(&self, t: T) -> &T; }
 struct S;
 impl<U> Foo<U> for S {
-    <|>fn foo(&self, t: U) -> &U { todo!() }
+    <|>fn foo(&self, t: U) -> &U { unimplemented!() }
 }",
         );
     }
@@ -319,7 +319,7 @@ impl Foo for S {}<|>",
 trait Foo { fn foo(&self); }
 struct S;
 impl Foo for S {
-    <|>fn foo(&self) { todo!() }
+    <|>fn foo(&self) { unimplemented!() }
 }",
         )
     }
@@ -342,7 +342,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo for S {
-    <|>fn foo(&self, bar: foo::Bar) { todo!() }
+    <|>fn foo(&self, bar: foo::Bar) { unimplemented!() }
 }",
         );
     }
@@ -365,7 +365,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo for S {
-    <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() }
+    <|>fn foo(&self, bar: foo::Bar<u32>) { unimplemented!() }
 }",
         );
     }
@@ -388,7 +388,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo<u32> for S {
-    <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() }
+    <|>fn foo(&self, bar: foo::Bar<u32>) { unimplemented!() }
 }",
         );
     }
@@ -414,7 +414,7 @@ mod foo {
 struct Param;
 struct S;
 impl foo::Foo<Param> for S {
-    <|>fn foo(&self, bar: Param) { todo!() }
+    <|>fn foo(&self, bar: Param) { unimplemented!() }
 }",
         );
     }
@@ -439,7 +439,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo for S {
-    <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { todo!() }
+    <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { unimplemented!() }
 }",
         );
     }
@@ -464,7 +464,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo for S {
-    <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { todo!() }
+    <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { unimplemented!() }
 }",
         );
     }
@@ -487,7 +487,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo for S {
-    <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { todo!() }
+    <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { unimplemented!() }
 }",
         );
     }
@@ -544,7 +544,7 @@ trait Foo {
 struct S;
 impl Foo for S {
     <|>type Output;
-    fn foo(&self) { todo!() }
+    fn foo(&self) { unimplemented!() }
 }"#,
         )
     }
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs
deleted file mode 100644
index 5cbb98d73f..0000000000
--- a/crates/ra_assists/src/handlers/reorder_fields.rs
+++ /dev/null
@@ -1,224 +0,0 @@
-use std::collections::HashMap;
-
-use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
-use itertools::Itertools;
-use ra_ide_db::RootDatabase;
-use ra_syntax::{
-    algo,
-    ast::{self, Path, RecordLit, RecordPat},
-    match_ast, AstNode, SyntaxKind,
-    SyntaxKind::*,
-    SyntaxNode,
-};
-
-use crate::{
-    assist_ctx::{Assist, AssistCtx},
-    AssistId,
-};
-
-// Assist: reorder_fields
-//
-// Reorder the fields of record literals and record patterns in the same order as in
-// the definition.
-//
-// ```
-// struct Foo {foo: i32, bar: i32};
-// const test: Foo = <|>Foo {bar: 0, foo: 1}
-// ```
-// ->
-// ```
-// struct Foo {foo: i32, bar: i32};
-// const test: Foo = Foo {foo: 1, bar: 0}
-// ```
-//
-pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> {
-    reorder::<RecordLit>(ctx.clone()).or_else(|| reorder::<RecordPat>(ctx))
-}
-
-fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> {
-    let record = ctx.find_node_at_offset::<R>()?;
-    let path = record.syntax().children().find_map(Path::cast)?;
-
-    let ranks = compute_fields_ranks(&path, &ctx)?;
-
-    let fields = get_fields(&record.syntax());
-    let sorted_fields = sorted_by_rank(&fields, |node| {
-        *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())
-    });
-
-    if sorted_fields == fields {
-        return None;
-    }
-
-    ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| {
-        for (old, new) in fields.iter().zip(&sorted_fields) {
-            algo::diff(old, new).into_text_edit(edit.text_edit_builder());
-        }
-        edit.target(record.syntax().text_range())
-    })
-}
-
-fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
-    match node.kind() {
-        RECORD_LIT => vec![RECORD_FIELD],
-        RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT],
-        _ => vec![],
-    }
-}
-
-fn get_field_name(node: &SyntaxNode) -> String {
-    let res = match_ast! {
-        match node {
-            ast::RecordField(field) => field.field_name().map(|it| it.to_string()),
-            ast::RecordFieldPat(field) => field.field_name().map(|it| it.to_string()),
-            _ => None,
-        }
-    };
-    res.unwrap_or_default()
-}
-
-fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> {
-    let kinds = get_fields_kind(record);
-    record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect()
-}
-
-fn sorted_by_rank(
-    fields: &[SyntaxNode],
-    get_rank: impl Fn(&SyntaxNode) -> usize,
-) -> Vec<SyntaxNode> {
-    fields.iter().cloned().sorted_by_key(get_rank).collect()
-}
-
-fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<Struct> {
-    match sema.resolve_path(path) {
-        Some(PathResolution::Def(ModuleDef::Adt(Adt::Struct(s)))) => Some(s),
-        _ => None,
-    }
-}
-
-fn compute_fields_ranks(path: &Path, ctx: &AssistCtx) -> Option<HashMap<String, usize>> {
-    Some(
-        struct_definition(path, ctx.sema)?
-            .fields(ctx.db)
-            .iter()
-            .enumerate()
-            .map(|(idx, field)| (field.name(ctx.db).to_string(), idx))
-            .collect(),
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::helpers::{check_assist, check_assist_not_applicable};
-
-    use super::*;
-
-    #[test]
-    fn not_applicable_if_sorted() {
-        check_assist_not_applicable(
-            reorder_fields,
-            r#"
-        struct Foo {
-            foo: i32,
-            bar: i32,
-        }
-
-        const test: Foo = <|>Foo { foo: 0, bar: 0 };
-        "#,
-        )
-    }
-
-    #[test]
-    fn trivial_empty_fields() {
-        check_assist_not_applicable(
-            reorder_fields,
-            r#"
-        struct Foo {};
-        const test: Foo = <|>Foo {}
-        "#,
-        )
-    }
-
-    #[test]
-    fn reorder_struct_fields() {
-        check_assist(
-            reorder_fields,
-            r#"
-        struct Foo {foo: i32, bar: i32};
-        const test: Foo = <|>Foo {bar: 0, foo: 1}
-        "#,
-            r#"
-        struct Foo {foo: i32, bar: i32};
-        const test: Foo = <|>Foo {foo: 1, bar: 0}
-        "#,
-        )
-    }
-
-    #[test]
-    fn reorder_struct_pattern() {
-        check_assist(
-            reorder_fields,
-            r#"
-        struct Foo { foo: i64, bar: i64, baz: i64 }
-
-        fn f(f: Foo) -> {
-            match f {
-                <|>Foo { baz: 0, ref mut bar, .. } => (),
-                _ => ()
-            }
-        }
-        "#,
-            r#"
-        struct Foo { foo: i64, bar: i64, baz: i64 }
-
-        fn f(f: Foo) -> {
-            match f {
-                <|>Foo { ref mut bar, baz: 0, .. } => (),
-                _ => ()
-            }
-        }
-        "#,
-        )
-    }
-
-    #[test]
-    fn reorder_with_extra_field() {
-        check_assist(
-            reorder_fields,
-            r#"
-            struct Foo {
-                foo: String,
-                bar: String,
-            }
-
-            impl Foo {
-                fn new() -> Foo {
-                    let foo = String::new();
-                    <|>Foo {
-                        bar: foo.clone(),
-                        extra: "Extra field",
-                        foo,
-                    }
-                }
-            }
-            "#,
-            r#"
-            struct Foo {
-                foo: String,
-                bar: String,
-            }
-
-            impl Foo {
-                fn new() -> Foo {
-                    let foo = String::new();
-                    <|>Foo {
-                        foo,
-                        bar: foo.clone(),
-                        extra: "Extra field",
-                    }
-                }
-            }
-            "#,
-        )
-    }
-}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index a00136da1c..5ba5254fd0 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -129,7 +129,6 @@ mod handlers {
     mod replace_unwrap_with_match;
     mod split_import;
     mod add_from_impl_for_enum;
-    mod reorder_fields;
 
     pub(crate) fn all() -> &'static [AssistHandler] {
         &[
@@ -171,7 +170,6 @@ mod handlers {
             // These are manually sorted for better priorities
             add_missing_impl_members::add_missing_impl_members,
             add_missing_impl_members::add_missing_default_members,
-            reorder_fields::reorder_fields,
         ]
     }
 }
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 58ae6ce418..226fb45348 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -139,7 +139,7 @@ impl SourceAnalyzer {
         &self,
         db: &dyn HirDatabase,
         field: &ast::FieldExpr,
-    ) -> Option<StructField> {
+    ) -> Option<crate::StructField> {
         let expr_id = self.expr_id(db, &field.clone().into())?;
         self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into())
     }
@@ -148,19 +148,21 @@ impl SourceAnalyzer {
         &self,
         db: &dyn HirDatabase,
         field: &ast::RecordField,
-    ) -> Option<(StructField, Option<Local>)> {
-        let expr = field.expr()?;
-        let expr_id = self.expr_id(db, &expr)?;
-        let local = if field.name_ref().is_some() {
-            None
-        } else {
-            let local_name = field.field_name()?.as_name();
-            let path = ModPath::from_segments(PathKind::Plain, once(local_name));
-            match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
-                Some(ValueNs::LocalBinding(pat_id)) => {
-                    Some(Local { pat_id, parent: self.resolver.body_owner()? })
-                }
-                _ => None,
+    ) -> Option<(crate::StructField, Option<Local>)> {
+        let (expr_id, local) = match field.expr() {
+            Some(it) => (self.expr_id(db, &it)?, None),
+            None => {
+                let src = InFile { file_id: self.file_id, value: field };
+                let expr_id = self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?;
+                let local_name = field.name_ref()?.as_name();
+                let path = ModPath::from_segments(PathKind::Plain, once(local_name));
+                let local = match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
+                    Some(ValueNs::LocalBinding(pat_id)) => {
+                        Some(Local { pat_id, parent: self.resolver.body_owner()? })
+                    }
+                    _ => None,
+                };
+                (expr_id, local)
             }
         };
         let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?;
@@ -317,7 +319,8 @@ fn scope_for_offset(
             if source.file_id != offset.file_id {
                 return None;
             }
-            let syntax_node_ptr = source.value.syntax_node_ptr();
+            let syntax_node_ptr =
+                source.value.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
             Some((syntax_node_ptr, scope))
         })
         // find containing scope
@@ -396,7 +399,8 @@ fn adjust(
             if source.file_id != file_id {
                 return None;
             }
-            let syntax_node_ptr = source.value.syntax_node_ptr();
+            let syntax_node_ptr =
+                source.value.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
             Some((syntax_node_ptr, scope))
         })
         .map(|(ptr, scope)| (ptr.range(), scope))
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 7c0d936910..be4b0accb8 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -4,6 +4,7 @@ use std::sync::Arc;
 
 use either::Either;
 use hir_expand::{
+    hygiene::Hygiene,
     name::{AsName, Name},
     InFile,
 };
@@ -12,7 +13,7 @@ use ra_prof::profile;
 use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner};
 
 use crate::{
-    body::CfgExpander, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace,
+    attr::Attrs, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace,
     type_ref::TypeRef, visibility::RawVisibility, EnumId, HasModule, LocalEnumVariantId,
     LocalStructFieldId, Lookup, ModuleId, StructId, UnionId, VariantId,
 };
@@ -124,9 +125,8 @@ fn lower_enum(
 
 impl VariantData {
     fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self {
-        let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate);
         let mut trace = Trace::new_for_arena();
-        match lower_struct(db, &mut expander, &mut trace, &flavor) {
+        match lower_struct(db, &mut trace, &flavor, module_id) {
             StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
             StructKind::Record => VariantData::Record(trace.into_arena()),
             StructKind::Unit => VariantData::Unit,
@@ -178,9 +178,8 @@ impl HasChildSource for VariantId {
                 it.lookup(db).container.module(db),
             ),
         };
-        let mut expander = CfgExpander::new(db, src.file_id, module_id.krate);
         let mut trace = Trace::new_for_map();
-        lower_struct(db, &mut expander, &mut trace, &src);
+        lower_struct(db, &mut trace, &src, module_id);
         src.with_value(trace.into_map())
     }
 }
@@ -194,15 +193,16 @@ pub enum StructKind {
 
 fn lower_struct(
     db: &dyn DefDatabase,
-    expander: &mut CfgExpander,
     trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>,
     ast: &InFile<ast::StructKind>,
+    module_id: ModuleId,
 ) -> StructKind {
+    let crate_graph = db.crate_graph();
     match &ast.value {
         ast::StructKind::Tuple(fl) => {
             for (i, fd) in fl.fields().enumerate() {
-                let attrs = expander.parse_attrs(&fd);
-                if !expander.is_cfg_enabled(&attrs) {
+                let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id));
+                if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) {
                     continue;
                 }
 
@@ -219,8 +219,8 @@ fn lower_struct(
         }
         ast::StructKind::Record(fl) => {
             for fd in fl.fields() {
-                let attrs = expander.parse_attrs(&fd);
-                if !expander.is_cfg_enabled(&attrs) {
+                let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id));
+                if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) {
                     continue;
                 }
 
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 2f2e3e5ba2..7b0c506b16 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -93,7 +93,6 @@ impl Attrs {
     }
 
     pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
-        // FIXME: handle cfg_attr :-)
         self.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false))
     }
 }
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index eafaf48c17..e09996c6f8 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -9,14 +9,11 @@ use drop_bomb::DropBomb;
 use either::Either;
 use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId};
 use ra_arena::{map::ArenaMap, Arena};
-use ra_cfg::CfgOptions;
-use ra_db::CrateId;
 use ra_prof::profile;
 use ra_syntax::{ast, AstNode, AstPtr};
 use rustc_hash::FxHashMap;
 
 use crate::{
-    attr::Attrs,
     db::DefDatabase,
     expr::{Expr, ExprId, Pat, PatId},
     item_scope::BuiltinShadowMode,
@@ -27,59 +24,25 @@ use crate::{
     AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId,
 };
 
-/// A subser of Exander that only deals with cfg attributes. We only need it to
-/// avoid cyclic queries in crate def map during enum processing.
-pub(crate) struct CfgExpander {
-    cfg_options: CfgOptions,
-    hygiene: Hygiene,
-}
-
 pub(crate) struct Expander {
-    cfg_expander: CfgExpander,
     crate_def_map: Arc<CrateDefMap>,
     current_file_id: HirFileId,
+    hygiene: Hygiene,
     ast_id_map: Arc<AstIdMap>,
     module: ModuleId,
     recursive_limit: usize,
 }
 
-impl CfgExpander {
-    pub(crate) fn new(
-        db: &dyn DefDatabase,
-        current_file_id: HirFileId,
-        krate: CrateId,
-    ) -> CfgExpander {
-        let hygiene = Hygiene::new(db.upcast(), current_file_id);
-        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
-        CfgExpander { cfg_options, hygiene }
-    }
-
-    pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs {
-        Attrs::new(owner, &self.hygiene)
-    }
-
-    pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
-        attrs.is_cfg_enabled(&self.cfg_options)
-    }
-}
-
 impl Expander {
     pub(crate) fn new(
         db: &dyn DefDatabase,
         current_file_id: HirFileId,
         module: ModuleId,
     ) -> Expander {
-        let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
         let crate_def_map = db.crate_def_map(module.krate);
+        let hygiene = Hygiene::new(db.upcast(), current_file_id);
         let ast_id_map = db.ast_id_map(current_file_id);
-        Expander {
-            cfg_expander,
-            crate_def_map,
-            current_file_id,
-            ast_id_map,
-            module,
-            recursive_limit: 0,
-        }
+        Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module, recursive_limit: 0 }
     }
 
     pub(crate) fn enter_expand<T: ast::AstNode>(
@@ -112,7 +75,7 @@ impl Expander {
                         ast_id_map: mem::take(&mut self.ast_id_map),
                         bomb: DropBomb::new("expansion mark dropped"),
                     };
-                    self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
+                    self.hygiene = Hygiene::new(db.upcast(), file_id);
                     self.current_file_id = file_id;
                     self.ast_id_map = db.ast_id_map(file_id);
                     self.recursive_limit += 1;
@@ -128,7 +91,7 @@ impl Expander {
     }
 
     pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
-        self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
+        self.hygiene = Hygiene::new(db.upcast(), mark.file_id);
         self.current_file_id = mark.file_id;
         self.ast_id_map = mem::take(&mut mark.ast_id_map);
         self.recursive_limit -= 1;
@@ -139,16 +102,8 @@ impl Expander {
         InFile { file_id: self.current_file_id, value }
     }
 
-    pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs {
-        self.cfg_expander.parse_attrs(owner)
-    }
-
-    pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
-        self.cfg_expander.is_cfg_enabled(attrs)
-    }
-
     fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
-        Path::from_src(path, &self.cfg_expander.hygiene)
+        Path::from_src(path, &self.hygiene)
     }
 
     fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
@@ -187,7 +142,7 @@ pub struct Body {
     pub item_scope: ItemScope,
 }
 
-pub type ExprPtr = AstPtr<ast::Expr>;
+pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>;
 pub type ExprSource = InFile<ExprPtr>;
 
 pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
@@ -285,7 +240,7 @@ impl BodySourceMap {
     }
 
     pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
-        let src = node.map(|it| AstPtr::new(it));
+        let src = node.map(|it| Either::Left(AstPtr::new(it)));
         self.expr_map.get(&src).cloned()
     }
 
@@ -294,6 +249,11 @@ impl BodySourceMap {
         self.expansions.get(&src).cloned()
     }
 
+    pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> {
+        let src = node.map(|it| Either::Right(AstPtr::new(it)));
+        self.expr_map.get(&src).cloned()
+    }
+
     pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
         self.pat_map_back[pat].clone()
     }
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 79abe55ce6..9d6ee095ef 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -2,7 +2,9 @@
 //! representation.
 
 use either::Either;
+
 use hir_expand::{
+    hygiene::Hygiene,
     name::{name, AsName, Name},
     MacroDefId, MacroDefKind,
 };
@@ -16,8 +18,10 @@ use ra_syntax::{
 };
 use test_utils::tested_by;
 
+use super::{ExprSource, PatSource};
 use crate::{
     adt::StructKind,
+    attr::Attrs,
     body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax},
     builtin_type::{BuiltinFloat, BuiltinInt},
     db::DefDatabase,
@@ -27,14 +31,12 @@ use crate::{
     },
     item_scope::BuiltinShadowMode,
     path::GenericArgs,
+    path::Path,
     type_ref::{Mutability, TypeRef},
-    AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
-    StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
+    AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, HasModule, Intern,
+    ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
 };
 
-use super::{ExprSource, PatSource};
-use ast::AstChildren;
-
 pub(super) fn lower(
     db: &dyn DefDatabase,
     def: DefWithBodyId,
@@ -102,6 +104,7 @@ impl ExprCollector<'_> {
     }
 
     fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
+        let ptr = Either::Left(ptr);
         let src = self.expander.to_source(ptr);
         let id = self.make_expr(expr, Ok(src.clone()));
         self.source_map.expr_map.insert(src, id);
@@ -112,6 +115,13 @@ impl ExprCollector<'_> {
     fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
         self.make_expr(expr, Err(SyntheticSyntax))
     }
+    fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
+        let ptr = Either::Right(ptr);
+        let src = self.expander.to_source(ptr);
+        let id = self.make_expr(expr, Ok(src.clone()));
+        self.source_map.expr_map.insert(src, id);
+        id
+    }
     fn empty_block(&mut self) -> ExprId {
         self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None })
     }
@@ -281,7 +291,7 @@ impl ExprCollector<'_> {
             ast::Expr::ParenExpr(e) => {
                 let inner = self.collect_expr_opt(e.expr());
                 // make the paren expr point to the inner expression as well
-                let src = self.expander.to_source(syntax_ptr);
+                let src = self.expander.to_source(Either::Left(syntax_ptr));
                 self.source_map.expr_map.insert(src, inner);
                 inner
             }
@@ -290,6 +300,7 @@ impl ExprCollector<'_> {
                 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
             }
             ast::Expr::RecordLit(e) => {
+                let crate_graph = self.db.crate_graph();
                 let path = e.path().and_then(|path| self.expander.parse_path(path));
                 let mut field_ptrs = Vec::new();
                 let record_lit = if let Some(nfl) = e.record_field_list() {
@@ -297,17 +308,31 @@ impl ExprCollector<'_> {
                         .fields()
                         .inspect(|field| field_ptrs.push(AstPtr::new(field)))
                         .filter_map(|field| {
-                            let attrs = self.expander.parse_attrs(&field);
-                            if !self.expander.is_cfg_enabled(&attrs) {
+                            let module_id = ContainerId::DefWithBodyId(self.def).module(self.db);
+                            let attrs = Attrs::new(
+                                &field,
+                                &Hygiene::new(self.db.upcast(), self.expander.current_file_id),
+                            );
+
+                            if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) {
                                 return None;
                             }
-                            let name = field.field_name()?.as_name();
 
                             Some(RecordLitField {
-                                name,
-                                expr: match field.expr() {
-                                    Some(e) => self.collect_expr(e),
-                                    None => self.missing_expr(),
+                                name: field
+                                    .name_ref()
+                                    .map(|nr| nr.as_name())
+                                    .unwrap_or_else(Name::missing),
+                                expr: if let Some(e) = field.expr() {
+                                    self.collect_expr(e)
+                                } else if let Some(nr) = field.name_ref() {
+                                    // field shorthand
+                                    self.alloc_expr_field_shorthand(
+                                        Expr::Path(Path::from_name_ref(&nr)),
+                                        AstPtr::new(&field),
+                                    )
+                                } else {
+                                    self.missing_expr()
                                 },
                             })
                         })
@@ -599,8 +624,8 @@ impl ExprCollector<'_> {
             }
             ast::Pat::TupleStructPat(p) => {
                 let path = p.path().and_then(|path| self.expander.parse_path(path));
-                let (args, ellipsis) = self.collect_tuple_pat(p.args());
-                Pat::TupleStruct { path, args, ellipsis }
+                let args = p.args().map(|p| self.collect_pat(p)).collect();
+                Pat::TupleStruct { path, args }
             }
             ast::Pat::RefPat(p) => {
                 let pat = self.collect_pat_opt(p.pat());
@@ -617,10 +642,10 @@ impl ExprCollector<'_> {
             }
             ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()),
             ast::Pat::TuplePat(p) => {
-                let (args, ellipsis) = self.collect_tuple_pat(p.args());
-                Pat::Tuple { args, ellipsis }
+                let args = p.args().map(|p| self.collect_pat(p)).collect();
+                Pat::Tuple(args)
             }
-            ast::Pat::PlaceholderPat(_) => Pat::Wild,
+            ast::Pat::PlaceholderPat(_) | ast::Pat::DotDotPat(_) => Pat::Wild,
             ast::Pat::RecordPat(p) => {
                 let path = p.path().and_then(|path| self.expander.parse_path(path));
                 let record_field_pat_list =
@@ -638,7 +663,7 @@ impl ExprCollector<'_> {
                 let iter = record_field_pat_list.record_field_pats().filter_map(|f| {
                     let ast_pat = f.pat()?;
                     let pat = self.collect_pat(ast_pat);
-                    let name = f.field_name()?.as_name();
+                    let name = f.name()?.as_name();
                     Some(RecordFieldPat { name, pat })
                 });
                 fields.extend(iter);
@@ -666,9 +691,7 @@ impl ExprCollector<'_> {
                     Pat::Missing
                 }
             }
-            ast::Pat::DotDotPat(_) => unreachable!(
-                "`DotDotPat` requires special handling and should not be mapped to a Pat."
-            ),
+
             // FIXME: implement
             ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
         };
@@ -683,19 +706,6 @@ impl ExprCollector<'_> {
             self.missing_pat()
         }
     }
-
-    fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) {
-        // Find the location of the `..`, if there is one. Note that we do not
-        // consider the possiblity of there being multiple `..` here.
-        let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::DotDotPat(_)));
-        // We want to skip the `..` pattern here, since we account for it above.
-        let args = args
-            .filter(|p| !matches!(p, ast::Pat::DotDotPat(_)))
-            .map(|p| self.collect_pat(p))
-            .collect();
-
-        (args, ellipsis)
-    }
 }
 
 impl From<ast::BinOp> for BinaryOp {
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 56a20c5bd1..b8fbf0ed4b 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -20,7 +20,7 @@ use crate::{
     type_ref::{Mutability, TypeBound, TypeRef},
     visibility::RawVisibility,
     AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule,
-    ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
+    ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -218,17 +218,10 @@ impl ImplData {
         let mut items = Vec::new();
 
         if let Some(item_list) = src.value.item_list() {
-            let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id);
-            items.extend(collect_impl_items(
-                db,
-                &mut expander,
-                item_list.impl_items(),
-                src.file_id,
-                id,
-            ));
+            items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id));
             items.extend(collect_impl_items_in_macros(
                 db,
-                &mut expander,
+                module_id,
                 &src.with_value(item_list),
                 id,
             ));
@@ -275,17 +268,18 @@ impl ConstData {
 
 fn collect_impl_items_in_macros(
     db: &dyn DefDatabase,
-    expander: &mut Expander,
+    module_id: ModuleId,
     impl_def: &InFile<ast::ItemList>,
     id: ImplId,
 ) -> Vec<AssocItemId> {
+    let mut expander = Expander::new(db, impl_def.file_id, module_id);
     let mut res = Vec::new();
 
     // We set a limit to protect against infinite recursion
     let limit = 100;
 
     for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) {
-        res.extend(collect_impl_items_in_macro(db, expander, m, id, limit))
+        res.extend(collect_impl_items_in_macro(db, &mut expander, m, id, limit))
     }
 
     res
@@ -306,7 +300,6 @@ fn collect_impl_items_in_macro(
         let items: InFile<ast::MacroItems> = expander.to_source(items);
         let mut res = collect_impl_items(
             db,
-            expander,
             items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
             items.file_id,
             id,
@@ -326,26 +319,32 @@ fn collect_impl_items_in_macro(
 
 fn collect_impl_items(
     db: &dyn DefDatabase,
-    expander: &mut Expander,
     impl_items: impl Iterator<Item = ImplItem>,
     file_id: crate::HirFileId,
     id: ImplId,
 ) -> Vec<AssocItemId> {
     let items = db.ast_id_map(file_id);
+    let crate_graph = db.crate_graph();
+    let module_id = id.lookup(db).container.module(db);
 
     impl_items
         .filter_map(|item_node| match item_node {
             ast::ImplItem::FnDef(it) => {
-                let attrs = expander.parse_attrs(&it);
-                if !expander.is_cfg_enabled(&attrs) {
-                    return None;
-                }
                 let def = FunctionLoc {
                     container: AssocContainerId::ImplId(id),
                     ast_id: AstId::new(file_id, items.ast_id(&it)),
                 }
                 .intern(db);
-                Some(def.into())
+
+                if !db
+                    .function_data(def)
+                    .attrs
+                    .is_cfg_enabled(&crate_graph[module_id.krate].cfg_options)
+                {
+                    None
+                } else {
+                    Some(def.into())
+                }
             }
             ast::ImplItem::ConstDef(it) => {
                 let def = ConstLoc {
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs
index a0cdad529b..e11bdf3ec2 100644
--- a/crates/ra_hir_def/src/expr.rs
+++ b/crates/ra_hir_def/src/expr.rs
@@ -374,7 +374,7 @@ pub struct RecordFieldPat {
 pub enum Pat {
     Missing,
     Wild,
-    Tuple { args: Vec<PatId>, ellipsis: Option<usize> },
+    Tuple(Vec<PatId>),
     Or(Vec<PatId>),
     Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool },
     Range { start: ExprId, end: ExprId },
@@ -382,7 +382,7 @@ pub enum Pat {
     Path(Path),
     Lit(ExprId),
     Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
-    TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> },
+    TupleStruct { path: Option<Path>, args: Vec<PatId> },
     Ref { pat: PatId, mutability: Mutability },
 }
 
@@ -393,7 +393,7 @@ impl Pat {
             Pat::Bind { subpat, .. } => {
                 subpat.iter().copied().for_each(f);
             }
-            Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
+            Pat::Or(args) | Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
                 args.iter().copied().for_each(f);
             }
             Pat::Ref { pat, .. } => f(*pat),
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 98c74fe257..8fe3f8617f 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -462,14 +462,6 @@ impl DefCollector<'_> {
                 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
                     tested_by!(glob_enum);
                     // glob import from enum => just import all the variants
-
-                    // XXX: urgh, so this works by accident! Here, we look at
-                    // the enum data, and, in theory, this might require us to
-                    // look back at the crate_def_map, creating a cycle. For
-                    // example, `enum E { crate::some_macro!(); }`. Luckely, the
-                    // only kind of macro that is allowed inside enum is a
-                    // `cfg_macro`, and we don't need to run name resolution for
-                    // it, but this is sheer luck!
                     let enum_data = self.db.enum_data(e);
                     let resolutions = enum_data
                         .variants
@@ -985,7 +977,11 @@ impl ModCollector<'_, '_> {
     }
 
     fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
-        attrs.is_cfg_enabled(self.def_collector.cfg_options)
+        // FIXME: handle cfg_attr :-)
+        attrs
+            .by_key("cfg")
+            .tt_values()
+            .all(|tt| self.def_collector.cfg_options.is_cfg_enabled(tt) != Some(false))
     }
 }
 
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 91c7b3e094..904080341a 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -134,6 +134,11 @@ impl Path {
         lower::lower_path(path, hygiene)
     }
 
+    /// Converts an `ast::NameRef` into a single-identifier `Path`.
+    pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
+        Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] }
+    }
+
     /// Converts a known mod path to `Path`.
     pub(crate) fn from_known_path(
         path: ModPath,
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index fecce224ee..25cc1e9fce 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -83,15 +83,6 @@ impl AsName for ast::Name {
     }
 }
 
-impl AsName for ast::NameOrNameRef {
-    fn as_name(&self) -> Name {
-        match self {
-            ast::NameOrNameRef::Name(it) => it.as_name(),
-            ast::NameOrNameRef::NameRef(it) => it.as_name(),
-        }
-    }
-}
-
 impl AsName for tt::Ident {
     fn as_name(&self) -> Name {
         Name::resolve(&self.text)
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs
index a64be9848e..9e9a9d0475 100644
--- a/crates/ra_hir_ty/src/_match.rs
+++ b/crates/ra_hir_ty/src/_match.rs
@@ -289,7 +289,7 @@ impl PatStack {
         Self::from_slice(&self.0[1..])
     }
 
-    fn replace_head_with<T: Into<PatIdOrWild> + Copy>(&self, pat_ids: &[T]) -> PatStack {
+    fn replace_head_with(&self, pat_ids: &[PatId]) -> PatStack {
         let mut patterns: PatStackInner = smallvec![];
         for pat in pat_ids {
             patterns.push((*pat).into());
@@ -320,14 +320,12 @@ impl PatStack {
         constructor: &Constructor,
     ) -> MatchCheckResult<Option<PatStack>> {
         let result = match (self.head().as_pat(cx), constructor) {
-            (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => {
-                if ellipsis.is_some() {
-                    // If there are ellipsis here, we should add the correct number of
-                    // Pat::Wild patterns to `pat_ids`. We should be able to use the
-                    // constructors arity for this, but at the time of writing we aren't
-                    // correctly calculating this arity when ellipsis are present.
-                    return Err(MatchCheckErr::NotImplemented);
-                }
+            (Pat::Tuple(ref pat_ids), Constructor::Tuple { arity }) => {
+                debug_assert_eq!(
+                    pat_ids.len(),
+                    *arity,
+                    "we type check before calling this code, so we should never hit this case",
+                );
 
                 Some(self.replace_head_with(pat_ids))
             }
@@ -353,47 +351,19 @@ impl PatStack {
                     Some(self.to_tail())
                 }
             }
-            (
-                Pat::TupleStruct { args: ref pat_ids, ellipsis, .. },
-                Constructor::Enum(enum_constructor),
-            ) => {
+            (Pat::TupleStruct { args: ref pat_ids, .. }, Constructor::Enum(enum_constructor)) => {
                 let pat_id = self.head().as_id().expect("we know this isn't a wild");
                 if !enum_variant_matches(cx, pat_id, *enum_constructor) {
                     None
                 } else {
-                    let constructor_arity = constructor.arity(cx)?;
-                    if let Some(ellipsis_position) = ellipsis {
-                        // If there are ellipsis in the pattern, the ellipsis must take the place
-                        // of at least one sub-pattern, so `pat_ids` should be smaller than the
-                        // constructor arity.
-                        if pat_ids.len() < constructor_arity {
-                            let mut new_patterns: Vec<PatIdOrWild> = vec![];
-
-                            for pat_id in &pat_ids[0..ellipsis_position] {
-                                new_patterns.push((*pat_id).into());
-                            }
-
-                            for _ in 0..(constructor_arity - pat_ids.len()) {
-                                new_patterns.push(PatIdOrWild::Wild);
-                            }
-
-                            for pat_id in &pat_ids[ellipsis_position..pat_ids.len()] {
-                                new_patterns.push((*pat_id).into());
-                            }
-
-                            Some(self.replace_head_with(&new_patterns))
-                        } else {
-                            return Err(MatchCheckErr::MalformedMatchArm);
-                        }
-                    } else {
-                        // If there is no ellipsis in the tuple pattern, the number
-                        // of patterns must equal the constructor arity.
-                        if pat_ids.len() == constructor_arity {
-                            Some(self.replace_head_with(pat_ids))
-                        } else {
-                            return Err(MatchCheckErr::MalformedMatchArm);
-                        }
+                    // If the enum variant matches, then we need to confirm
+                    // that the number of patterns aligns with the expected
+                    // number of patterns for that enum variant.
+                    if pat_ids.len() != constructor.arity(cx)? {
+                        return Err(MatchCheckErr::MalformedMatchArm);
                     }
+
+                    Some(self.replace_head_with(pat_ids))
                 }
             }
             (Pat::Or(_), _) => return Err(MatchCheckErr::NotImplemented),
@@ -674,11 +644,7 @@ impl Constructor {
 fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> {
     let res = match pat.as_pat(cx) {
         Pat::Wild => None,
-        // FIXME somehow create the Tuple constructor with the proper arity. If there are
-        // ellipsis, the arity is not equal to the number of patterns.
-        Pat::Tuple { args: pats, ellipsis } if ellipsis.is_none() => {
-            Some(Constructor::Tuple { arity: pats.len() })
-        }
+        Pat::Tuple(pats) => Some(Constructor::Tuple { arity: pats.len() }),
         Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] {
             Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)),
             _ => return Err(MatchCheckErr::NotImplemented),
@@ -1006,47 +972,6 @@ mod tests {
         check_no_diagnostic(content);
     }
 
-    #[test]
-    fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() {
-        let content = r"
-            fn test_fn() {
-                match (false, true, false) {
-                    (false, ..) => {},
-                    (true, ..) => {},
-                }
-            }
-        ";
-
-        check_no_diagnostic(content);
-    }
-
-    #[test]
-    fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() {
-        let content = r"
-            fn test_fn() {
-                match (false, true, false) {
-                    (.., false) => {},
-                    (.., true) => {},
-                }
-            }
-        ";
-
-        check_no_diagnostic(content);
-    }
-
-    #[test]
-    fn tuple_of_bools_with_ellipsis_no_diagnostic() {
-        let content = r"
-            fn test_fn() {
-                match (false, true, false) {
-                    (..) => {},
-                }
-            }
-        ";
-
-        check_no_diagnostic(content);
-    }
-
     #[test]
     fn tuple_of_tuple_and_bools_no_arms() {
         let content = r"
@@ -1390,9 +1315,8 @@ mod tests {
             }
         ";
 
-        // Match statements with arms that don't match the
-        // expression pattern do not fire this diagnostic.
-        check_no_diagnostic(content);
+        // Match arms with the incorrect type are filtered out.
+        check_diagnostic(content);
     }
 
     #[test]
@@ -1406,9 +1330,8 @@ mod tests {
             }
         ";
 
-        // Match statements with arms that don't match the
-        // expression pattern do not fire this diagnostic.
-        check_no_diagnostic(content);
+        // Match arms with the incorrect type are filtered out.
+        check_diagnostic(content);
     }
 
     #[test]
@@ -1421,9 +1344,8 @@ mod tests {
             }
         ";
 
-        // Match statements with arms that don't match the
-        // expression pattern do not fire this diagnostic.
-        check_no_diagnostic(content);
+        // Match arms with the incorrect type are filtered out.
+        check_diagnostic(content);
     }
 
     #[test]
@@ -1461,163 +1383,6 @@ mod tests {
         // we don't create a diagnostic).
         check_no_diagnostic(content);
     }
-
-    #[test]
-    fn expr_diverges() {
-        let content = r"
-            enum Either {
-                A,
-                B,
-            }
-            fn test_fn() {
-                match loop {} {
-                    Either::A => (),
-                    Either::B => (),
-                }
-            }
-        ";
-
-        check_no_diagnostic(content);
-    }
-
-    #[test]
-    fn expr_loop_with_break() {
-        let content = r"
-            enum Either {
-                A,
-                B,
-            }
-            fn test_fn() {
-                match loop { break Foo::A } {
-                    Either::A => (),
-                    Either::B => (),
-                }
-            }
-        ";
-
-        check_no_diagnostic(content);
-    }
-
-    #[test]
-    fn expr_partially_diverges() {
-        let content = r"
-            enum Either<T> {
-                A(T),
-                B,
-            }
-            fn foo() -> Either<!> {
-                Either::B
-            }
-            fn test_fn() -> u32 {
-                match foo() {
-                    Either::A(val) => val,
-                    Either::B => 0,
-                }
-            }
-        ";
-
-        check_no_diagnostic(content);
-    }
-
-    #[test]
-    fn enum_tuple_partial_ellipsis_no_diagnostic() {
-        let content = r"
-            enum Either {
-                A(bool, bool, bool, bool),
-                B,
-            }
-            fn test_fn() {
-                match Either::B {
-                    Either::A(true, .., true) => {},
-                    Either::A(true, .., false) => {},
-                    Either::A(false, .., true) => {},
-                    Either::A(false, .., false) => {},
-                    Either::B => {},
-                }
-            }
-        ";
-
-        check_no_diagnostic(content);
-    }
-
-    #[test]
-    fn enum_tuple_partial_ellipsis_2_no_diagnostic() {
-        let content = r"
-            enum Either {
-                A(bool, bool, bool, bool),
-                B,
-            }
-            fn test_fn() {
-                match Either::B {
-                    Either::A(true, .., true) => {},
-                    Either::A(true, .., false) => {},
-                    Either::A(.., true) => {},
-                    Either::A(.., false) => {},
-                    Either::B => {},
-                }
-            }
-        ";
-
-        check_no_diagnostic(content);
-    }
-
-    #[test]
-    fn enum_tuple_partial_ellipsis_missing_arm() {
-        let content = r"
-            enum Either {
-                A(bool, bool, bool, bool),
-                B,
-            }
-            fn test_fn() {
-                match Either::B {
-                    Either::A(true, .., true) => {},
-                    Either::A(true, .., false) => {},
-                    Either::A(false, .., false) => {},
-                    Either::B => {},
-                }
-            }
-        ";
-
-        check_diagnostic(content);
-    }
-
-    #[test]
-    fn enum_tuple_partial_ellipsis_2_missing_arm() {
-        let content = r"
-            enum Either {
-                A(bool, bool, bool, bool),
-                B,
-            }
-            fn test_fn() {
-                match Either::B {
-                    Either::A(true, .., true) => {},
-                    Either::A(true, .., false) => {},
-                    Either::A(.., true) => {},
-                    Either::B => {},
-                }
-            }
-        ";
-
-        check_diagnostic(content);
-    }
-
-    #[test]
-    fn enum_tuple_ellipsis_no_diagnostic() {
-        let content = r"
-            enum Either {
-                A(bool, bool, bool, bool),
-                B,
-            }
-            fn test_fn() {
-                match Either::B {
-                    Either::A(..) => {},
-                    Either::B => {},
-                }
-            }
-        ";
-
-        check_no_diagnostic(content);
-    }
 }
 
 #[cfg(test)]
@@ -1687,75 +1452,4 @@ mod false_negatives {
         // We do not currently handle patterns with internal `or`s.
         check_no_diagnostic(content);
     }
-
-    #[test]
-    fn expr_diverges_missing_arm() {
-        let content = r"
-            enum Either {
-                A,
-                B,
-            }
-            fn test_fn() {
-                match loop {} {
-                    Either::A => (),
-                }
-            }
-        ";
-
-        // This is a false negative.
-        // Even though the match expression diverges, rustc fails
-        // to compile here since `Either::B` is missing.
-        check_no_diagnostic(content);
-    }
-
-    #[test]
-    fn expr_loop_missing_arm() {
-        let content = r"
-            enum Either {
-                A,
-                B,
-            }
-            fn test_fn() {
-                match loop { break Foo::A } {
-                    Either::A => (),
-                }
-            }
-        ";
-
-        // This is a false negative.
-        // We currently infer the type of `loop { break Foo::A }` to `!`, which
-        // causes us to skip the diagnostic since `Either::A` doesn't type check
-        // with `!`.
-        check_no_diagnostic(content);
-    }
-
-    #[test]
-    fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
-        let content = r"
-            fn test_fn() {
-                match (false, true, false) {
-                    (false, ..) => {},
-                }
-            }
-        ";
-
-        // This is a false negative.
-        // We don't currently handle tuple patterns with ellipsis.
-        check_no_diagnostic(content);
-    }
-
-    #[test]
-    fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
-        let content = r"
-            fn test_fn() {
-                match (false, true, false) {
-                    (.., false) => {},
-                }
-            }
-        ";
-
-        // This is a false negative.
-        // We don't currently handle tuple patterns with ellipsis.
-        check_no_diagnostic(content);
-    }
 }
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 33da16b487..1462b053f0 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -11,7 +11,7 @@ use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
 use ra_prof::profile;
 
 use crate::{
-    method_resolution::{CrateImplDefs, TyFingerprint},
+    method_resolution::CrateImplDefs,
     traits::{chalk, AssocTyValue, Impl},
     Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty,
     TyDefId, TypeCtor, ValueTyDefId,
@@ -65,12 +65,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>;
 
     #[salsa::invoke(crate::traits::impls_for_trait_query)]
-    fn impls_for_trait(
-        &self,
-        krate: CrateId,
-        trait_: TraitId,
-        self_ty_fp: Option<TyFingerprint>,
-    ) -> Arc<[ImplId]>;
+    fn impls_for_trait(&self, krate: CrateId, trait_: TraitId) -> Arc<[ImplId]>;
 
     // Interned IDs for Chalk integration
     #[salsa::interned]
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index 21abbcf1e2..827b687de1 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -89,19 +89,21 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
         let (_, source_map) = db.body_with_source_map(self.func.into());
 
         if let Ok(source_ptr) = source_map.expr_syntax(id) {
-            let root = source_ptr.file_syntax(db.upcast());
-            if let ast::Expr::RecordLit(record_lit) = &source_ptr.value.to_node(&root) {
-                if let Some(field_list) = record_lit.record_field_list() {
-                    let variant_data = variant_data(db.upcast(), variant_def);
-                    let missed_fields = missed_fields
-                        .into_iter()
-                        .map(|idx| variant_data.fields()[idx].name.clone())
-                        .collect();
-                    self.sink.push(MissingFields {
-                        file: source_ptr.file_id,
-                        field_list: AstPtr::new(&field_list),
-                        missed_fields,
-                    })
+            if let Some(expr) = source_ptr.value.as_ref().left() {
+                let root = source_ptr.file_syntax(db.upcast());
+                if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
+                    if let Some(field_list) = record_lit.record_field_list() {
+                        let variant_data = variant_data(db.upcast(), variant_def);
+                        let missed_fields = missed_fields
+                            .into_iter()
+                            .map(|idx| variant_data.fields()[idx].name.clone())
+                            .collect();
+                        self.sink.push(MissingFields {
+                            file: source_ptr.file_id,
+                            field_list: AstPtr::new(&field_list),
+                            missed_fields,
+                        })
+                    }
                 }
             }
         }
@@ -161,6 +163,12 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
 
         let mut seen = Matrix::empty();
         for pat in pats {
+            // We skip any patterns whose type we cannot resolve.
+            //
+            // This could lead to false positives in this diagnostic, so
+            // it might be better to skip the entire diagnostic if we either
+            // cannot resolve a match arm or determine that the match arm has
+            // the wrong type.
             if let Some(pat_ty) = infer.type_of_pat.get(pat) {
                 // We only include patterns whose type matches the type
                 // of the match expression. If we had a InvalidMatchArmPattern
@@ -183,15 +191,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
                     // to the matrix here.
                     let v = PatStack::from_pattern(pat);
                     seen.push(&cx, v);
-                    continue;
                 }
             }
-
-            // If we can't resolve the type of a pattern, or the pattern type doesn't
-            // fit the match expression, we skip this diagnostic. Skipping the entire
-            // diagnostic rather than just not including this match arm is preferred
-            // to avoid the chance of false positives.
-            return;
         }
 
         match is_useful(&cx, &seen, &PatStack::from_wild()) {
@@ -204,16 +205,18 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
         }
 
         if let Ok(source_ptr) = source_map.expr_syntax(id) {
-            let root = source_ptr.file_syntax(db.upcast());
-            if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) {
-                if let (Some(match_expr), Some(arms)) =
-                    (match_expr.expr(), match_expr.match_arm_list())
-                {
-                    self.sink.push(MissingMatchArms {
-                        file: source_ptr.file_id,
-                        match_expr: AstPtr::new(&match_expr),
-                        arms: AstPtr::new(&arms),
-                    })
+            if let Some(expr) = source_ptr.value.as_ref().left() {
+                let root = source_ptr.file_syntax(db.upcast());
+                if let ast::Expr::MatchExpr(match_expr) = expr.to_node(&root) {
+                    if let (Some(match_expr), Some(arms)) =
+                        (match_expr.expr(), match_expr.match_arm_list())
+                    {
+                        self.sink.push(MissingMatchArms {
+                            file: source_ptr.file_id,
+                            match_expr: AstPtr::new(&match_expr),
+                            arms: AstPtr::new(&arms),
+                        })
+                    }
                 }
             }
         }
@@ -244,8 +247,9 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
             let (_, source_map) = db.body_with_source_map(self.func.into());
 
             if let Ok(source_ptr) = source_map.expr_syntax(id) {
-                self.sink
-                    .push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value });
+                if let Some(expr) = source_ptr.value.left() {
+                    self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr });
+                }
             }
         }
     }
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 8ec4d4ace0..078476f76a 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -85,7 +85,7 @@ impl<'a> InferenceContext<'a> {
         let body = Arc::clone(&self.body); // avoid borrow checker problem
 
         let is_non_ref_pat = match &body[pat] {
-            Pat::Tuple { .. }
+            Pat::Tuple(..)
             | Pat::Or(..)
             | Pat::TupleStruct { .. }
             | Pat::Record { .. }
@@ -116,7 +116,7 @@ impl<'a> InferenceContext<'a> {
         let expected = expected;
 
         let ty = match &body[pat] {
-            Pat::Tuple { ref args, .. } => {
+            Pat::Tuple(ref args) => {
                 let expectations = match expected.as_tuple() {
                     Some(parameters) => &*parameters.0,
                     _ => &[],
@@ -155,7 +155,7 @@ impl<'a> InferenceContext<'a> {
                 let subty = self.infer_pat(*pat, expectation, default_bm);
                 Ty::apply_one(TypeCtor::Ref(*mutability), subty)
             }
-            Pat::TupleStruct { path: p, args: subpats, .. } => {
+            Pat::TupleStruct { path: p, args: subpats } => {
                 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm, pat)
             }
             Pat::Record { path: p, args: fields, ellipsis: _ } => {
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 657284fd01..74a0bc7db8 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -34,7 +34,7 @@ impl TyFingerprint {
     /// Creates a TyFingerprint for looking up an impl. Only certain types can
     /// have impls: if we have some `struct S`, we can have an `impl S`, but not
     /// `impl &S`. Hence, this will return `None` for reference types and such.
-    pub(crate) fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
+    fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
         match ty {
             Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)),
             _ => None,
@@ -45,7 +45,7 @@ impl TyFingerprint {
 #[derive(Debug, PartialEq, Eq)]
 pub struct CrateImplDefs {
     impls: FxHashMap<TyFingerprint, Vec<ImplId>>,
-    impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
+    impls_by_trait: FxHashMap<TraitId, Vec<ImplId>>,
 }
 
 impl CrateImplDefs {
@@ -59,14 +59,7 @@ impl CrateImplDefs {
             for impl_id in module_data.scope.impls() {
                 match db.impl_trait(impl_id) {
                     Some(tr) => {
-                        let self_ty = db.impl_self_ty(impl_id);
-                        let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
-                        res.impls_by_trait
-                            .entry(tr.value.trait_)
-                            .or_default()
-                            .entry(self_ty_fp)
-                            .or_default()
-                            .push(impl_id);
+                        res.impls_by_trait.entry(tr.value.trait_).or_default().push(impl_id);
                     }
                     None => {
                         let self_ty = db.impl_self_ty(impl_id);
@@ -86,39 +79,11 @@ impl CrateImplDefs {
     }
 
     pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ {
-        self.impls_by_trait
-            .get(&tr)
-            .into_iter()
-            .flat_map(|m| m.values().flat_map(|v| v.iter().copied()))
-    }
-
-    pub fn lookup_impl_defs_for_trait_and_ty(
-        &self,
-        tr: TraitId,
-        fp: TyFingerprint,
-    ) -> impl Iterator<Item = ImplId> + '_ {
-        self.impls_by_trait
-            .get(&tr)
-            .and_then(|m| m.get(&Some(fp)))
-            .into_iter()
-            .flatten()
-            .copied()
-            .chain(
-                self.impls_by_trait
-                    .get(&tr)
-                    .and_then(|m| m.get(&None))
-                    .into_iter()
-                    .flatten()
-                    .copied(),
-            )
+        self.impls_by_trait.get(&tr).into_iter().flatten().copied()
     }
 
     pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a {
-        self.impls
-            .values()
-            .chain(self.impls_by_trait.values().flat_map(|m| m.values()))
-            .flatten()
-            .copied()
+        self.impls.values().chain(self.impls_by_trait.values()).flatten().copied()
     }
 }
 
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 43d8d1e802..21e2333799 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -7,7 +7,7 @@ use ra_db::{impl_intern_key, salsa, CrateId};
 use ra_prof::profile;
 use rustc_hash::FxHashSet;
 
-use crate::{db::HirDatabase, method_resolution::TyFingerprint, DebruijnIndex};
+use crate::{db::HirDatabase, DebruijnIndex};
 
 use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
 
@@ -40,12 +40,7 @@ pub(crate) fn impls_for_trait_query(
     db: &dyn HirDatabase,
     krate: CrateId,
     trait_: TraitId,
-    self_ty_fp: Option<TyFingerprint>,
 ) -> Arc<[ImplId]> {
-    // FIXME: We could be a lot smarter here - because of the orphan rules and
-    // the fact that the trait and the self type need to be in the dependency
-    // tree of a crate somewhere for an impl to exist, we could skip looking in
-    // a lot of crates completely
     let mut impls = FxHashSet::default();
     // We call the query recursively here. On the one hand, this means we can
     // reuse results from queries for different crates; on the other hand, this
@@ -53,13 +48,10 @@ pub(crate) fn impls_for_trait_query(
     // ones the user is editing), so this may actually be a waste of memory. I'm
     // doing it like this mainly for simplicity for now.
     for dep in &db.crate_graph()[krate].dependencies {
-        impls.extend(db.impls_for_trait(dep.crate_id, trait_, self_ty_fp).iter());
+        impls.extend(db.impls_for_trait(dep.crate_id, trait_).iter());
     }
     let crate_impl_defs = db.impls_in_crate(krate);
-    match self_ty_fp {
-        Some(fp) => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp)),
-        None => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)),
-    }
+    impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_));
     impls.into_iter().collect()
 }
 
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index e05fea8430..c5f1b52324 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -16,8 +16,8 @@ use ra_db::{
 
 use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
 use crate::{
-    db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
-    ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
+    db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate,
+    ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
 };
 
 pub(super) mod tls;
@@ -647,22 +647,19 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
         debug!("impls_for_trait {:?}", trait_id);
         let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
 
-        let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
-
-        let self_ty_fp = TyFingerprint::for_impl(&ty);
-
         // Note: Since we're using impls_for_trait, only impls where the trait
         // can be resolved should ever reach Chalk. `impl_datum` relies on that
         // and will panic if the trait can't be resolved.
         let mut result: Vec<_> = self
             .db
-            .impls_for_trait(self.krate, trait_, self_ty_fp)
+            .impls_for_trait(self.krate, trait_)
             .iter()
             .copied()
             .map(Impl::ImplDef)
             .map(|impl_| impl_.to_chalk(self.db))
             .collect();
 
+        let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
         let arg: Option<Ty> =
             parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone()));
 
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index f95b6baf3d..ca57eceff7 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -208,20 +208,9 @@ mod tests {
         }
     }
 
-    fn call_info_helper(text: &str) -> Option<CallInfo> {
-        let (analysis, position) = single_file_with_position(text);
-        analysis.call_info(position).unwrap()
-    }
-
     fn call_info(text: &str) -> CallInfo {
-        let info = call_info_helper(text);
-        assert!(info.is_some());
-        info.unwrap()
-    }
-
-    fn no_call_info(text: &str) {
-        let info = call_info_helper(text);
-        assert!(info.is_none());
+        let (analysis, position) = single_file_with_position(text);
+        analysis.call_info(position).unwrap().unwrap()
     }
 
     #[test]
@@ -569,8 +558,9 @@ fn main() {
     }
 
     #[test]
+    #[should_panic]
     fn cant_call_named_structs() {
-        no_call_info(
+        let _ = call_info(
             r#"
 struct TS { x: u32, y: i32 }
 fn main() {
@@ -604,8 +594,9 @@ fn main() {
     }
 
     #[test]
+    #[should_panic]
     fn cant_call_enum_records() {
-        no_call_info(
+        let _ = call_info(
             r#"
 enum E {
     /// A Variant
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs
index a8b4ce114d..1b7d3122f8 100644
--- a/crates/ra_ide/src/completion/complete_pattern.rs
+++ b/crates/ra_ide/src/completion/complete_pattern.rs
@@ -7,10 +7,6 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
     if !ctx.is_pat_binding_or_const {
         return;
     }
-    if ctx.record_pat_syntax.is_some() {
-        return;
-    }
-
     // FIXME: ideally, we should look at the type we are matching against and
     // suggest variants + auto-imports
     ctx.scope().process_all_names(&mut |name, res| {
diff --git a/crates/ra_ide/src/completion/complete_record.rs b/crates/ra_ide/src/completion/complete_record.rs
index 83a553155b..f46bcee5c4 100644
--- a/crates/ra_ide/src/completion/complete_record.rs
+++ b/crates/ra_ide/src/completion/complete_record.rs
@@ -2,7 +2,7 @@
 use crate::completion::{CompletionContext, Completions};
 
 pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
-    let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
+    let missing_fields = match (ctx.record_lit_pat.as_ref(), ctx.record_lit_syntax.as_ref()) {
         (None, None) => return None,
         (Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"),
         (Some(record_pat), _) => ctx.sema.record_pattern_missing_fields(record_pat),
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs
index 2d8e0776ca..efde9bf731 100644
--- a/crates/ra_ide/src/completion/complete_unqualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs
@@ -3,14 +3,7 @@
 use crate::completion::{CompletionContext, Completions};
 
 pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
-    if !ctx.is_trivial_path {
-        return;
-    }
-
-    if ctx.is_pat_binding_or_const
-        || ctx.record_lit_syntax.is_some()
-        || ctx.record_pat_syntax.is_some()
-    {
+    if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const) {
         return;
     }
 
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 8b34015950..6637afaf70 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -30,7 +30,7 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) function_syntax: Option<ast::FnDef>,
     pub(super) use_item_syntax: Option<ast::UseItem>,
     pub(super) record_lit_syntax: Option<ast::RecordLit>,
-    pub(super) record_pat_syntax: Option<ast::RecordPat>,
+    pub(super) record_lit_pat: Option<ast::RecordPat>,
     pub(super) impl_def: Option<ast::ImplDef>,
     pub(super) is_param: bool,
     /// If a name-binding or reference to a const in a pattern.
@@ -93,7 +93,7 @@ impl<'a> CompletionContext<'a> {
             function_syntax: None,
             use_item_syntax: None,
             record_lit_syntax: None,
-            record_pat_syntax: None,
+            record_lit_pat: None,
             impl_def: None,
             is_param: false,
             is_pat_binding_or_const: false,
@@ -182,11 +182,6 @@ impl<'a> CompletionContext<'a> {
                 self.is_param = true;
                 return;
             }
-            // FIXME: remove this (V) duplication and make the check more precise
-            if name_ref.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
-                self.record_pat_syntax =
-                    self.sema.find_node_at_offset_with_macros(&original_file, offset);
-            }
             self.classify_name_ref(original_file, name_ref, offset);
         }
 
@@ -216,9 +211,8 @@ impl<'a> CompletionContext<'a> {
                 self.is_param = true;
                 return;
             }
-            // FIXME: remove this (^) duplication and make the check more precise
             if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
-                self.record_pat_syntax =
+                self.record_lit_pat =
                     self.sema.find_node_at_offset_with_macros(&original_file, offset);
             }
         }
@@ -233,7 +227,7 @@ impl<'a> CompletionContext<'a> {
         self.name_ref_syntax =
             find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
         let name_range = name_ref.syntax().text_range();
-        if ast::RecordField::for_field_name(&name_ref).is_some() {
+        if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() {
             self.record_lit_syntax =
                 self.sema.find_node_at_offset_with_macros(&original_file, offset);
         }
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 45b9f78023..da9f55a696 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -235,10 +235,7 @@ fn should_show_param_hint(
     param_name: &str,
     argument: &ast::Expr,
 ) -> bool {
-    if param_name.is_empty()
-        || is_argument_similar_to_param(argument, param_name)
-        || Some(param_name) == fn_signature.name.as_ref().map(String::as_str)
-    {
+    if param_name.is_empty() || is_argument_similar_to_param(argument, param_name) {
         return false;
     }
 
@@ -250,7 +247,10 @@ fn should_show_param_hint(
 
     // avoid displaying hints for common functions like map, filter, etc.
     // or other obvious words used in std
-    parameters_len != 1 || !is_obvious_param(param_name)
+    if parameters_len == 1 && is_obvious_param(param_name) {
+        return false;
+    }
+    true
 }
 
 fn is_argument_similar_to_param(argument: &ast::Expr, param_name: &str) -> bool {
@@ -1086,8 +1086,6 @@ impl Test {
     }
 
     fn no_hints_expected(&self, _: i32, test_var: i32) {}
-
-    fn frob(&self, frob: bool) {}
 }
 
 struct Param {}
@@ -1095,8 +1093,6 @@ struct Param {}
 fn different_order(param: &Param) {}
 fn different_order_mut(param: &mut Param) {}
 
-fn twiddle(twiddle: bool) {}
-
 fn main() {
     let container: TestVarContainer = TestVarContainer { test_var: 42 };
     let test: Test = Test {};
@@ -1109,9 +1105,6 @@ fn main() {
     let test_var: i32 = 55;
     test_processed.no_hints_expected(22, test_var);
     test_processed.no_hints_expected(33, container.test_var);
-    test_processed.frob(false);
-
-    twiddle(true);
 
     let param_begin: Param = Param {};
     different_order(&param_begin);
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index 49a8c74fba..e9934844e3 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -216,7 +216,7 @@ pub fn classify_name_ref(
         }
     }
 
-    if let Some(record_field) = ast::RecordField::for_field_name(name_ref) {
+    if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
         tested_by!(goto_def_for_record_fields; force);
         tested_by!(goto_def_for_field_init_shorthand; force);
         if let Some((field, local)) = sema.resolve_record_field(&record_field) {
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 9fb5cb0583..31e9b22e7d 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -607,12 +607,13 @@ impl<'a> TreeSink for TtTreeSink<'a> {
             let text: SmolStr = match self.cursor.token_tree() {
                 Some(tt::TokenTree::Leaf(leaf)) => {
                     // Mark the range if needed
-                    let id = match leaf {
-                        tt::Leaf::Ident(ident) => ident.id,
-                        tt::Leaf::Punct(punct) => punct.id,
-                        tt::Leaf::Literal(lit) => lit.id,
+                    let (text, id) = match leaf {
+                        tt::Leaf::Ident(ident) => (ident.text.clone(), ident.id),
+                        tt::Leaf::Punct(punct) => {
+                            (SmolStr::new_inline_from_ascii(1, &[punct.char as u8]), punct.id)
+                        }
+                        tt::Leaf::Literal(lit) => (lit.text.clone(), lit.id),
                     };
-                    let text = SmolStr::new(format!("{}", leaf));
                     let range = TextRange::offset_len(self.text_pos, TextUnit::of_str(&text));
                     self.token_map.insert(id, range);
                     self.cursor = self.cursor.bump();
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index c2a6e82e9b..d0530955e0 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -282,10 +282,13 @@ fn name_ref(p: &mut Parser) {
 }
 
 fn name_ref_or_index(p: &mut Parser) {
-    assert!(p.at(IDENT) || p.at(INT_NUMBER));
-    let m = p.start();
-    p.bump_any();
-    m.complete(p, NAME_REF);
+    if p.at(IDENT) || p.at(INT_NUMBER) {
+        let m = p.start();
+        p.bump_any();
+        m.complete(p, NAME_REF);
+    } else {
+        p.err_and_bump("expected identifier");
+    }
 }
 
 fn error_block(p: &mut Parser, message: &str) {
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index cb30b25a89..a1bd530638 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -619,39 +619,26 @@ pub(crate) fn record_field_list(p: &mut Parser) {
     let m = p.start();
     p.bump(T!['{']);
     while !p.at(EOF) && !p.at(T!['}']) {
-        let m = p.start();
-        // test record_literal_field_with_attr
-        // fn main() {
-        //     S { #[cfg(test)] field: 1 }
-        // }
-        attributes::outer_attributes(p);
-
         match p.current() {
-            IDENT | INT_NUMBER => {
-                // test_err record_literal_before_ellipsis_recovery
-                // fn main() {
-                //     S { field ..S::default() }
-                // }
-                if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) {
-                    name_ref_or_index(p);
-                    p.expect(T![:]);
+            // test record_literal_field_with_attr
+            // fn main() {
+            //     S { #[cfg(test)] field: 1 }
+            // }
+            IDENT | INT_NUMBER | T![#] => {
+                let m = p.start();
+                attributes::outer_attributes(p);
+                name_ref_or_index(p);
+                if p.eat(T![:]) {
+                    expr(p);
                 }
-                expr(p);
                 m.complete(p, RECORD_FIELD);
             }
             T![.] if p.at(T![..]) => {
-                m.abandon(p);
                 p.bump(T![..]);
                 expr(p);
             }
-            T!['{'] => {
-                error_block(p, "expected a field");
-                m.abandon(p);
-            }
-            _ => {
-                p.err_and_bump("expected identifier");
-                m.abandon(p);
-            }
+            T!['{'] => error_block(p, "expected a field"),
+            _ => p.err_and_bump("expected identifier"),
         }
         if !p.at(T!['}']) {
             p.expect(T![,]);
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index 68fb2fc733..936d27575c 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -192,30 +192,14 @@ fn record_field_pat_list(p: &mut Parser) {
         match p.current() {
             // A trailing `..` is *not* treated as a DOT_DOT_PAT.
             T![.] if p.at(T![..]) => p.bump(T![..]),
-            T!['{'] => error_block(p, "expected ident"),
 
-            c => {
-                let m = p.start();
-                match c {
-                    // test record_field_pat
-                    // fn foo() {
-                    //     let S { 0: 1 } = ();
-                    //     let S { x: 1 } = ();
-                    // }
-                    IDENT | INT_NUMBER if p.nth(1) == T![:] => {
-                        name_ref_or_index(p);
-                        p.bump(T![:]);
-                        pattern(p);
-                    }
-                    T![box] => {
-                        // FIXME: not all box patterns should be allowed
-                        box_pat(p);
-                    }
-                    _ => {
-                        bind_pat(p, false);
-                    }
-                }
-                m.complete(p, RECORD_FIELD_PAT);
+            IDENT | INT_NUMBER if p.nth(1) == T![:] => record_field_pat(p),
+            T!['{'] => error_block(p, "expected ident"),
+            T![box] => {
+                box_pat(p);
+            }
+            _ => {
+                bind_pat(p, false);
             }
         }
         if !p.at(T!['}']) {
@@ -226,6 +210,26 @@ fn record_field_pat_list(p: &mut Parser) {
     m.complete(p, RECORD_FIELD_PAT_LIST);
 }
 
+// test record_field_pat
+// fn foo() {
+//     let S { 0: 1 } = ();
+//     let S { x: 1 } = ();
+// }
+fn record_field_pat(p: &mut Parser) {
+    assert!(p.at(IDENT) || p.at(INT_NUMBER));
+    assert!(p.nth(1) == T![:]);
+
+    let m = p.start();
+
+    if !p.eat(INT_NUMBER) {
+        name(p)
+    }
+
+    p.bump_any();
+    pattern(p);
+    m.complete(p, RECORD_FIELD_PAT);
+}
+
 // test placeholder_pat
 // fn main() { let _ = (); }
 fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 7fca5661ef..99c6b72197 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -18,8 +18,8 @@ use crate::{
 pub use self::{
     expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp},
     extensions::{
-        AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents,
-        StructKind, TypeBoundKind, VisibilityKind,
+        AttrKind, FieldKind, PathSegmentKind, SelfParamKind, SlicePatComponents, StructKind,
+        TypeBoundKind, VisibilityKind,
     },
     generated::{nodes::*, tokens::*},
     tokens::*,
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index f2ea5088e7..76b7655e68 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -1,8 +1,6 @@
 //! Various extension methods to ast Nodes, which are hard to code-generate.
 //! Extensions for various expressions live in a sibling `expr_extensions` module.
 
-use std::fmt;
-
 use itertools::Itertools;
 use ra_parser::SyntaxKind;
 
@@ -189,64 +187,6 @@ impl ast::StructDef {
     }
 }
 
-impl ast::RecordField {
-    pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordField> {
-        let candidate =
-            field_name.syntax().parent().and_then(ast::RecordField::cast).or_else(|| {
-                field_name.syntax().ancestors().nth(4).and_then(ast::RecordField::cast)
-            })?;
-        if candidate.field_name().as_ref() == Some(field_name) {
-            Some(candidate)
-        } else {
-            None
-        }
-    }
-
-    /// Deals with field init shorthand
-    pub fn field_name(&self) -> Option<ast::NameRef> {
-        if let Some(name_ref) = self.name_ref() {
-            return Some(name_ref);
-        }
-        if let Some(ast::Expr::PathExpr(expr)) = self.expr() {
-            let path = expr.path()?;
-            let segment = path.segment()?;
-            let name_ref = segment.name_ref()?;
-            if path.qualifier().is_none() {
-                return Some(name_ref);
-            }
-        }
-        None
-    }
-}
-
-pub enum NameOrNameRef {
-    Name(ast::Name),
-    NameRef(ast::NameRef),
-}
-
-impl fmt::Display for NameOrNameRef {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            NameOrNameRef::Name(it) => fmt::Display::fmt(it, f),
-            NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f),
-        }
-    }
-}
-
-impl ast::RecordFieldPat {
-    /// Deals with field init shorthand
-    pub fn field_name(&self) -> Option<NameOrNameRef> {
-        if let Some(name_ref) = self.name_ref() {
-            return Some(NameOrNameRef::NameRef(name_ref));
-        }
-        if let Some(ast::Pat::BindPat(pat)) = self.pat() {
-            let name = pat.name()?;
-            return Some(NameOrNameRef::Name(name));
-        }
-        None
-    }
-}
-
 impl ast::EnumVariant {
     pub fn parent_enum(&self) -> ast::EnumDef {
         self.syntax()
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs
index 188f0df968..f1098755b6 100644
--- a/crates/ra_syntax/src/ast/generated/nodes.rs
+++ b/crates/ra_syntax/src/ast/generated/nodes.rs
@@ -1806,8 +1806,8 @@ impl AstNode for RecordFieldPat {
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
 impl ast::AttrsOwner for RecordFieldPat {}
+impl ast::NameOwner for RecordFieldPat {}
 impl RecordFieldPat {
-    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
     pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 }
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 0f4a50be47..f39559e9ea 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -100,9 +100,6 @@ pub fn expr_empty_block() -> ast::Expr {
 pub fn expr_unimplemented() -> ast::Expr {
     expr_from_text("unimplemented!()")
 }
-pub fn expr_todo() -> ast::Expr {
-    expr_from_text("todo!()")
-}
 pub fn expr_path(path: ast::Path) -> ast::Expr {
     expr_from_text(&path.to_string())
 }
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index a796e78b12..f0e16dc2bf 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -19,11 +19,6 @@
 //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256>
 //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md>
 
-#[allow(unused)]
-macro_rules! eprintln {
-    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
-}
-
 mod syntax_node;
 mod syntax_error;
 mod parsing;
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index e9ee0b888f..75cf2dae50 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -163,7 +163,10 @@ pub fn analysis_stats(
                 if let Ok(src) = src {
                     let original_file = src.file_id.original_file(db);
                     let line_index = host.analysis().file_line_index(original_file).unwrap();
-                    let text_range = src.value.syntax_node_ptr().range();
+                    let text_range = src.value.either(
+                        |it| it.syntax_node_ptr().range(),
+                        |it| it.syntax_node_ptr().range(),
+                    );
                     let (start, end) = (
                         line_index.line_col(text_range.start()),
                         line_index.line_col(text_range.end()),
@@ -189,7 +192,12 @@ pub fn analysis_stats(
                         // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
                         // But also, we should just turn the type mismatches into diagnostics and provide these
                         let root = db.parse_or_expand(src.file_id).unwrap();
-                        let node = src.map(|e| e.to_node(&root).syntax().clone());
+                        let node = src.map(|e| {
+                            e.either(
+                                |p| p.to_node(&root).syntax().clone(),
+                                |p| p.to_node(&root).syntax().clone(),
+                            )
+                        });
                         let original_range = original_range(db, node.as_ref());
                         let path = db.file_relative_path(original_range.file_id);
                         let line_index =
diff --git a/docs/user/assists.md b/docs/user/assists.md
index 1d95104237..754131f6fe 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -175,7 +175,7 @@ trait Trait<T> {
 }
 
 impl Trait<u32> for () {
-    fn foo(&self) -> u32 { todo!() }
+    fn foo(&self) -> u32 { unimplemented!() }
 
 }
 ```
@@ -582,21 +582,6 @@ impl Walrus {
 }
 ```
 
-## `reorder_fields`
-
-Reorder the fields of record literals and record patterns in the same order as in
-the definition.
-
-```rust
-// BEFORE
-struct Foo {foo: i32, bar: i32};
-const test: Foo = ┃Foo {bar: 0, foo: 1}
-
-// AFTER
-struct Foo {foo: i32, bar: i32};
-const test: Foo = Foo {foo: 1, bar: 0}
-```
-
 ## `replace_if_let_with_match`
 
 Replaces `if let` with an else branch with a `match` expression.
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 35a05131c8..21c1c9f232 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -66,44 +66,23 @@ export class Config {
         return vscode.workspace.getConfiguration(this.rootSection);
     }
 
-    /**
-     * Beware that postfix `!` operator erases both `null` and `undefined`.
-     * This is why the following doesn't work as expected:
-     *
-     * ```ts
-     * const nullableNum = vscode
-     *  .workspace
-     *  .getConfiguration
-     *  .getConfiguration("rust-analyer")
-     *  .get<number | null>(path)!;
-     *
-     * // What happens is that type of `nullableNum` is `number` but not `null | number`:
-     * const fullFledgedNum: number = nullableNum;
-     * ```
-     * So this getter handles this quirk by not requiring the caller to use postfix `!`
-     */
-    private get<T>(path: string): T {
-        return this.cfg.get<T>(path)!;
-    }
-
-    get serverPath() { return this.get<null | string>("serverPath"); }
-    get channel() { return this.get<UpdatesChannel>("updates.channel"); }
-    get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); }
-    get traceExtension() { return this.get<boolean>("trace.extension"); }
-
+    get serverPath() { return this.cfg.get<null | string>("serverPath")!; }
+    get channel() { return this.cfg.get<UpdatesChannel>("updates.channel")!; }
+    get askBeforeDownload() { return this.cfg.get<boolean>("updates.askBeforeDownload")!; }
+    get traceExtension() { return this.cfg.get<boolean>("trace.extension")!; }
 
     get inlayHints() {
         return {
-            typeHints: this.get<boolean>("inlayHints.typeHints"),
-            parameterHints: this.get<boolean>("inlayHints.parameterHints"),
-            chainingHints: this.get<boolean>("inlayHints.chainingHints"),
-            maxLength: this.get<null | number>("inlayHints.maxLength"),
+            typeHints: this.cfg.get<boolean>("inlayHints.typeHints")!,
+            parameterHints: this.cfg.get<boolean>("inlayHints.parameterHints")!,
+            chainingHints: this.cfg.get<boolean>("inlayHints.chainingHints")!,
+            maxLength: this.cfg.get<null | number>("inlayHints.maxLength")!,
         };
     }
 
     get checkOnSave() {
         return {
-            command: this.get<string>("checkOnSave.command"),
+            command: this.cfg.get<string>("checkOnSave.command")!,
         };
     }
 }
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index da74f03d2d..6a8bd942e1 100644
--- a/editors/code/src/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -229,13 +229,13 @@ interface InlaysDecorations {
 }
 
 interface RustSourceFile {
-    /**
-     * Source of the token to cancel in-flight inlay hints request if any.
-     */
+    /*
+    * Source of the token to cancel in-flight inlay hints request if any.
+    */
     inlaysRequest: null | vscode.CancellationTokenSource;
     /**
-     * Last applied decorations.
-     */
+    * Last applied decorations.
+    */
     cachedDecorations: null | InlaysDecorations;
 
     document: RustDocument;
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 9c02f7c6f0..69cba91684 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -511,7 +511,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
             T![..],
             T!['}']
         }
-        struct RecordFieldPat: AttrsOwner { NameRef, T![:], Pat }
+        struct RecordFieldPat: AttrsOwner, NameOwner { T![:], Pat }
 
         struct TupleStructPat { Path, T!['('], args: [Pat], T![')'] }
         struct TuplePat { T!['('], args: [Pat], T![')'] }


Test patch:
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index b63b4d81a2..64444ee3aa 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -180,7 +180,7 @@ trait Trait<T> {
 }
 
 impl Trait<u32> for () {
-    fn foo(&self) -> u32 { todo!() }
+    fn foo(&self) -> u32 { unimplemented!() }
 
 }
 "#####,
@@ -606,21 +606,6 @@ impl Walrus {
     )
 }
 
-#[test]
-fn doctest_reorder_fields() {
-    check(
-        "reorder_fields",
-        r#####"
-struct Foo {foo: i32, bar: i32};
-const test: Foo = <|>Foo {bar: 0, foo: 1}
-"#####,
-        r#####"
-struct Foo {foo: i32, bar: i32};
-const test: Foo = Foo {foo: 1, bar: 0}
-"#####,
-    )
-}
-
 #[test]
 fn doctest_replace_if_let_with_match() {
     check(
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index 87165ac33a..496fc6b081 100644
--- a/crates/ra_hir_def/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -32,9 +32,6 @@ fn typing_inside_a_function_should_not_invalidate_def_map() {
 
         use crate::foo::bar::Baz;
 
-        enum E { A, B }
-        use E::*;
-
         fn foo() -> i32 {
             1 + 1
         }
@@ -49,9 +46,6 @@ fn typing_inside_a_function_should_not_invalidate_def_map() {
 
         use crate::foo::bar::Baz;
 
-        enum E { A, B }
-        use E::*;
-
         fn foo() -> i32 { 92 }
         ",
     );
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 81fc0f63a8..54e31602fb 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -82,7 +82,9 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
 
         for (expr, ty) in inference_result.type_of_expr.iter() {
             let syntax_ptr = match body_source_map.expr_syntax(expr) {
-                Ok(sp) => sp.map(|ast| ast.syntax_node_ptr()),
+                Ok(sp) => {
+                    sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()))
+                }
                 Err(SyntheticSyntax) => continue,
             };
             types.push((syntax_ptr.clone(), ty));
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index 07cbc521a3..6e5d2247ca 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -1,8 +1,7 @@
+use super::{infer, infer_with_mismatches};
 use insta::assert_snapshot;
 use test_utils::covers;
 
-use super::{infer, infer_with_mismatches};
-
 #[test]
 fn infer_pattern() {
     assert_snapshot!(
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast b/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast
deleted file mode 100644
index 75043c9c04..0000000000
--- a/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast
+++ /dev/null
@@ -1,49 +0,0 @@
-SOURCE_FILE@[0; 45)
-  FN_DEF@[0; 44)
-    FN_KW@[0; 2) "fn"
-    WHITESPACE@[2; 3) " "
-    NAME@[3; 7)
-      IDENT@[3; 7) "main"
-    PARAM_LIST@[7; 9)
-      L_PAREN@[7; 8) "("
-      R_PAREN@[8; 9) ")"
-    WHITESPACE@[9; 10) " "
-    BLOCK_EXPR@[10; 44)
-      BLOCK@[10; 44)
-        L_CURLY@[10; 11) "{"
-        WHITESPACE@[11; 16) "\n    "
-        RECORD_LIT@[16; 42)
-          PATH@[16; 17)
-            PATH_SEGMENT@[16; 17)
-              NAME_REF@[16; 17)
-                IDENT@[16; 17) "S"
-          WHITESPACE@[17; 18) " "
-          RECORD_FIELD_LIST@[18; 42)
-            L_CURLY@[18; 19) "{"
-            WHITESPACE@[19; 20) " "
-            RECORD_FIELD@[20; 40)
-              NAME_REF@[20; 25)
-                IDENT@[20; 25) "field"
-              WHITESPACE@[25; 26) " "
-              RANGE_EXPR@[26; 40)
-                DOT2@[26; 28) ".."
-                CALL_EXPR@[28; 40)
-                  PATH_EXPR@[28; 38)
-                    PATH@[28; 38)
-                      PATH@[28; 29)
-                        PATH_SEGMENT@[28; 29)
-                          NAME_REF@[28; 29)
-                            IDENT@[28; 29) "S"
-                      COLON2@[29; 31) "::"
-                      PATH_SEGMENT@[31; 38)
-                        NAME_REF@[31; 38)
-                          IDENT@[31; 38) "default"
-                  ARG_LIST@[38; 40)
-                    L_PAREN@[38; 39) "("
-                    R_PAREN@[39; 40) ")"
-            WHITESPACE@[40; 41) " "
-            R_CURLY@[41; 42) "}"
-        WHITESPACE@[42; 43) "\n"
-        R_CURLY@[43; 44) "}"
-  WHITESPACE@[44; 45) "\n"
-error [25; 25): expected COLON
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs b/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs
deleted file mode 100644
index a4e5b2f693..0000000000
--- a/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    S { field ..S::default() }
-}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast b/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast
index 89a6117996..f4206858bf 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast
@@ -35,11 +35,8 @@ SOURCE_FILE@[0; 112)
               L_CURLY@[27; 28) "{"
               WHITESPACE@[28; 29) " "
               RECORD_FIELD@[29; 30)
-                PATH_EXPR@[29; 30)
-                  PATH@[29; 30)
-                    PATH_SEGMENT@[29; 30)
-                      NAME_REF@[29; 30)
-                        IDENT@[29; 30) "x"
+                NAME_REF@[29; 30)
+                  IDENT@[29; 30) "x"
               COMMA@[30; 31) ","
               WHITESPACE@[31; 32) " "
               RECORD_FIELD@[32; 37)
@@ -65,11 +62,8 @@ SOURCE_FILE@[0; 112)
               L_CURLY@[48; 49) "{"
               WHITESPACE@[49; 50) " "
               RECORD_FIELD@[50; 51)
-                PATH_EXPR@[50; 51)
-                  PATH@[50; 51)
-                    PATH_SEGMENT@[50; 51)
-                      NAME_REF@[50; 51)
-                        IDENT@[50; 51) "x"
+                NAME_REF@[50; 51)
+                  IDENT@[50; 51) "x"
               COMMA@[51; 52) ","
               WHITESPACE@[52; 53) " "
               RECORD_FIELD@[53; 58)
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast b/crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast
index fcd099de98..c2614543ca 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast
@@ -44,20 +44,18 @@ SOURCE_FILE@[0; 119)
             RECORD_FIELD_PAT_LIST@[40; 56)
               L_CURLY@[40; 41) "{"
               WHITESPACE@[41; 42) " "
-              RECORD_FIELD_PAT@[42; 43)
-                BIND_PAT@[42; 43)
-                  NAME@[42; 43)
-                    IDENT@[42; 43) "f"
+              BIND_PAT@[42; 43)
+                NAME@[42; 43)
+                  IDENT@[42; 43) "f"
               COMMA@[43; 44) ","
               WHITESPACE@[44; 45) " "
-              RECORD_FIELD_PAT@[45; 54)
-                BIND_PAT@[45; 54)
-                  REF_KW@[45; 48) "ref"
-                  WHITESPACE@[48; 49) " "
-                  MUT_KW@[49; 52) "mut"
-                  WHITESPACE@[52; 53) " "
-                  NAME@[53; 54)
-                    IDENT@[53; 54) "g"
+              BIND_PAT@[45; 54)
+                REF_KW@[45; 48) "ref"
+                WHITESPACE@[48; 49) " "
+                MUT_KW@[49; 52) "mut"
+                WHITESPACE@[52; 53) " "
+                NAME@[53; 54)
+                  IDENT@[53; 54) "g"
               WHITESPACE@[54; 55) " "
               R_CURLY@[55; 56) "}"
           WHITESPACE@[56; 57) " "
@@ -81,7 +79,7 @@ SOURCE_FILE@[0; 119)
               L_CURLY@[73; 74) "{"
               WHITESPACE@[74; 75) " "
               RECORD_FIELD_PAT@[75; 79)
-                NAME_REF@[75; 76)
+                NAME@[75; 76)
                   IDENT@[75; 76) "h"
                 COLON@[76; 77) ":"
                 WHITESPACE@[77; 78) " "
@@ -112,7 +110,7 @@ SOURCE_FILE@[0; 119)
               L_CURLY@[101; 102) "{"
               WHITESPACE@[102; 103) " "
               RECORD_FIELD_PAT@[103; 107)
-                NAME_REF@[103; 104)
+                NAME@[103; 104)
                   IDENT@[103; 104) "h"
                 COLON@[104; 105) ":"
                 WHITESPACE@[105; 106) " "
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast
index 1d245f8f31..f756730704 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast
@@ -44,17 +44,16 @@ SOURCE_FILE@[0; 118)
               RECORD_FIELD_PAT_LIST@[50; 81)
                 L_CURLY@[50; 51) "{"
                 WHITESPACE@[51; 52) " "
-                RECORD_FIELD_PAT@[52; 57)
-                  BOX_PAT@[52; 57)
-                    BOX_KW@[52; 55) "box"
-                    WHITESPACE@[55; 56) " "
-                    BIND_PAT@[56; 57)
-                      NAME@[56; 57)
-                        IDENT@[56; 57) "i"
+                BOX_PAT@[52; 57)
+                  BOX_KW@[52; 55) "box"
+                  WHITESPACE@[55; 56) " "
+                  BIND_PAT@[56; 57)
+                    NAME@[56; 57)
+                      IDENT@[56; 57) "i"
                 COMMA@[57; 58) ","
                 WHITESPACE@[58; 59) " "
                 RECORD_FIELD_PAT@[59; 79)
-                  NAME_REF@[59; 60)
+                  NAME@[59; 60)
                     IDENT@[59; 60) "j"
                   COLON@[60; 61) ":"
                   WHITESPACE@[61; 62) " "
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast
index cac2ffdcf8..0d786f597c 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast
@@ -25,8 +25,7 @@ SOURCE_FILE@[0; 63)
               L_CURLY@[21; 22) "{"
               WHITESPACE@[22; 23) " "
               RECORD_FIELD_PAT@[23; 27)
-                NAME_REF@[23; 24)
-                  INT_NUMBER@[23; 24) "0"
+                INT_NUMBER@[23; 24) "0"
                 COLON@[24; 25) ":"
                 WHITESPACE@[25; 26) " "
                 LITERAL_PAT@[26; 27)
@@ -55,7 +54,7 @@ SOURCE_FILE@[0; 63)
               L_CURLY@[46; 47) "{"
               WHITESPACE@[47; 48) " "
               RECORD_FIELD_PAT@[48; 52)
-                NAME_REF@[48; 49)
+                NAME@[48; 49)
                   IDENT@[48; 49) "x"
                 COLON@[49; 50) ":"
                 WHITESPACE@[50; 51) " "
diff --git a/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast b/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast
index d0623ba904..9b5954ebd2 100644
--- a/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast
@@ -68,16 +68,14 @@ SOURCE_FILE@[0; 170)
               RECORD_FIELD_PAT_LIST@[59; 67)
                 L_CURLY@[59; 60) "{"
                 WHITESPACE@[60; 61) " "
-                RECORD_FIELD_PAT@[61; 62)
-                  BIND_PAT@[61; 62)
-                    NAME@[61; 62)
-                      IDENT@[61; 62) "a"
+                BIND_PAT@[61; 62)
+                  NAME@[61; 62)
+                    IDENT@[61; 62) "a"
                 COMMA@[62; 63) ","
                 WHITESPACE@[63; 64) " "
-                RECORD_FIELD_PAT@[64; 65)
-                  BIND_PAT@[64; 65)
-                    NAME@[64; 65)
-                      IDENT@[64; 65) "b"
+                BIND_PAT@[64; 65)
+                  NAME@[64; 65)
+                    IDENT@[64; 65) "b"
                 WHITESPACE@[65; 66) " "
                 R_CURLY@[66; 67) "}"
             COLON@[67; 68) ":"
diff --git a/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rast b/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rast
index 5e96b695bb..b30030de36 100644
--- a/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rast
@@ -71,16 +71,14 @@ SOURCE_FILE@[0; 137)
               RECORD_FIELD_PAT_LIST@[58; 66)
                 L_CURLY@[58; 59) "{"
                 WHITESPACE@[59; 60) " "
-                RECORD_FIELD_PAT@[60; 61)
-                  BIND_PAT@[60; 61)
-                    NAME@[60; 61)
-                      IDENT@[60; 61) "a"
+                BIND_PAT@[60; 61)
+                  NAME@[60; 61)
+                    IDENT@[60; 61) "a"
                 COMMA@[61; 62) ","
                 WHITESPACE@[62; 63) " "
-                RECORD_FIELD_PAT@[63; 64)
-                  BIND_PAT@[63; 64)
-                    NAME@[63; 64)
-                      IDENT@[63; 64) "b"
+                BIND_PAT@[63; 64)
+                  NAME@[63; 64)
+                    IDENT@[63; 64) "b"
                 WHITESPACE@[64; 65) " "
                 R_CURLY@[65; 66) "}"
             COLON@[66; 67) ":"
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 4164bfd5ed..3b60c55f3f 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -395,7 +395,7 @@ pub fn skip_slow_tests() -> bool {
     should_skip
 }
 
-const REWRITE: bool = false;
+const REWRITE: bool = true;
 
 /// Asserts that `expected` and `actual` strings are equal. If they differ only
 /// in trailing or leading whitespace the test won't fail and
diff --git a/xtask/tests/tidy-tests/main.rs b/xtask/tests/tidy-tests/main.rs
index 4f525fcd04..80911a68e8 100644
--- a/xtask/tests/tidy-tests/main.rs
+++ b/xtask/tests/tidy-tests/main.rs
@@ -20,16 +20,7 @@ fn rust_files_are_tidy() {
 }
 
 fn check_todo(path: &Path, text: &str) {
-    let whitelist = &[
-        // This file itself is whitelisted since this test itself contains matches.
-        "tests/cli.rs",
-        // Some of our assists generate `todo!()` so those files are whitelisted.
-        "doc_tests/generated.rs",
-        "handlers/add_missing_impl_members.rs",
-        // To support generating `todo!()` in assists, we have `expr_todo()` in ast::make.
-        "ast/make.rs",
-    ];
-    if whitelist.iter().any(|p| path.ends_with(p)) {
+    if path.ends_with("tests/cli.rs") {
         return;
     }
     if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {