Repository: rust-analyzer/rust-analyzer
Pull request #9069 (2021-05-30 21:48:29)

minor: Don't force-disable incremental
1.52.1 turns incremental off regardless of this setting, so this is unnecessary. Removing this allow manually overriding Cargo to enable incremental.

bors r+


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 15ccf4146d..192f0efc2a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -146,9 +146,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.68"
+version = "1.0.67"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
+checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
 
 [[package]]
 name = "cfg"
@@ -169,9 +169,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.68.0"
+version = "0.67.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea1552e7666a857f5417e6051ce705ea6856ab2cda39be7605e5b626fa47416b"
+checksum = "751a3cd9eeb24d7165e9f90daf1f10a23ffa16a7986f349027f8dfb60f51ee0c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -181,9 +181,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.68.0"
+version = "0.67.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19d7d5f1448dbac493541e97221f7f4c32326c4c76c6ecf543daf72a1dd93e66"
+checksum = "4236da905504740d3f72cc8f0509aa01321cc236208e2c33b55eda2db74bc495"
 dependencies = [
  "bitflags",
  "chalk-derive",
@@ -192,9 +192,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-recursive"
-version = "0.68.0"
+version = "0.67.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0df406d2927321021b48acd193459dd33c913732155c93442d03f5ae8275385"
+checksum = "7d0b123fe45a34c4cd5cb329650a0d163525d2acbe9d754a4538d3340884002e"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -205,9 +205,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.68.0"
+version = "0.67.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0cbfcd5daa5ab8b1c9e5e10e83b0ac26271480f6ae5b5f35e5b19e1f6a0e6e37"
+checksum = "9c54788f0ae3b38e2bb2266f395d462d988c64f92dbd55c68219908fd1ce7ddc"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -281,9 +281,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.5"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
+checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94"
 dependencies = [
  "cfg-if",
  "crossbeam-utils",
@@ -294,10 +294,11 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.5"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
+checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278"
 dependencies = [
+ "autocfg",
  "cfg-if",
  "lazy_static",
 ]
@@ -424,11 +425,21 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
 
+[[package]]
+name = "fsevent"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97f347202c95c98805c216f9e1df210e8ebaec9fdb2365700a43c10797a35e63"
+dependencies = [
+ "bitflags",
+ "fsevent-sys",
+]
+
 [[package]]
 name = "fsevent-sys"
-version = "4.0.0"
+version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c0e564d24da983c053beff1bb7178e237501206840a3e6bf4e267b9e8ae734a"
+checksum = "ca6f5e6817058771c10f0eb0f05ddf1e35844266f972004fe8e4b21fda295bd5"
 dependencies = [
  "libc",
 ]
@@ -765,9 +776,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.95"
+version = "0.2.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
+checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
 
 [[package]]
 name = "libloading"
@@ -870,18 +881,18 @@ checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
 
 [[package]]
 name = "memmap2"
-version = "0.2.3"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4"
+checksum = "397d1a6d6d0563c0f5462bbdae662cf6c784edf5e828e40c7257f85d82bf56dd"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "memoffset"
-version = "0.6.4"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
+checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
 dependencies = [
  "autocfg",
 ]
@@ -929,13 +940,14 @@ dependencies = [
 
 [[package]]
 name = "notify"
-version = "5.0.0-pre.9"
+version = "5.0.0-pre.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b89869d77edd64db917d7903abeadc166f93686b342c56cc0ca51acb68441d09"
+checksum = "46bbbcd078f1f00ddb7a9abe70b96e91229b44b0b3afdec610f8e5137f8f014b"
 dependencies = [
  "bitflags",
  "crossbeam-channel",
  "filetime",
+ "fsevent",
  "fsevent-sys",
  "inotify",
  "libc",
@@ -1348,9 +1360,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_lexer"
-version = "721.0.0"
+version = "720.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ba1f60e2942dc7dc5ea64edeaae01cfba2303871b14936e1af0f54d5420b3d1"
+checksum = "a025b453b0ae85335336f991f920ca9af5c0dc851171cb9035a16cea5619e9b2"
 dependencies = [
  "unicode-xid",
 ]
@@ -1816,9 +1828,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-normalization"
-version = "0.1.18"
+version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33717dca7ac877f497014e10d73f3acf948c342bee31b5ca7892faf94ccc6b49"
+checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef"
 dependencies = [
  "tinyvec",
 ]
@@ -1946,18 +1958,18 @@ dependencies = [
 
 [[package]]
 name = "xshell"
-version = "0.1.14"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c640362f1b150e186b76e88606e4b01a7b2f1d56cc50fcc184ddb683fb567c23"
+checksum = "eb15bb1b41eb14efe628006294c294e10c366e03a0283b9c2063fc27d97934c6"
 dependencies = [
  "xshell-macros",
 ]
 
 [[package]]
 name = "xshell-macros"
-version = "0.1.14"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0607c095c96c1d8420ce4a018a0954fb15d73d5eb59b521a05a0f04cffc05059"
+checksum = "cf7ed94a2c75b9bcc57031229be2b57ee47ba71122f71aabef8610ec66a97e52"
 
 [[package]]
 name = "xtask"
diff --git a/Cargo.toml b/Cargo.toml
index 498cf7d626..e237b13dc1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,10 +3,6 @@ resolver = "2"
 members = ["xtask/", "lib/*", "crates/*"]
 
 [profile.dev]
-# We do want incremental builds, but they are broken at the moment :(
-# https://github.com/rust-lang/rust/issues/85003#issuecomment-833796289
-incremental = false
-
 # Disabling debug info speeds up builds a bunch,
 # and we don't rely on it for debugging that much.
 debug = 0
@@ -21,9 +17,6 @@ text-size.opt-level = 3
 miniz_oxide.opt-level = 3
 
 [profile.release]
-# We do want incremental release builds, but they are broken at the moment :(
-# https://github.com/rust-lang/rust/issues/85003#issuecomment-833796289
-incremental = false
 debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger.
 
 [profile.test]
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index c3d02424d6..a9994082a2 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -18,9 +18,9 @@ ena = "0.14.0"
 log = "0.4.8"
 rustc-hash = "1.1.0"
 scoped-tls = "1"
-chalk-solve = { version = "0.68", default-features = false }
-chalk-ir = "0.68"
-chalk-recursive = "0.68"
+chalk-solve = { version = "0.67", default-features = false }
+chalk-ir = "0.67"
+chalk-recursive = "0.67"
 la-arena = { version = "0.2.0", path = "../../lib/arena" }
 
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index 4e042bf422..b108fd559c 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -383,7 +383,7 @@ pub(crate) fn associated_ty_data_query(
     // Lower bounds -- we could/should maybe move this to a separate query in `lower`
     let type_alias_data = db.type_alias_data(type_alias);
     let generic_params = generics(db.upcast(), type_alias.into());
-    // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
+    let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
     let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
     let ctx = crate::TyLoweringContext::new(db, &resolver)
         .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
@@ -396,10 +396,8 @@ pub(crate) fn associated_ty_data_query(
         .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty))
         .collect();
 
-    // FIXME: Re-enable where clauses on associated types when an upstream chalk bug is fixed.
-    //        (rust-analyzer#9052)
-    // let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
-    let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses: vec![] };
+    let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
+    let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses };
     let datum = AssociatedTyDatum {
         trait_id: to_chalk_trait_id(trait_),
         id,
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 76d926157c..13d5b90c99 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -219,7 +219,8 @@ const ATTRIBUTES: &[AttrCompletion] = &[
     ),
     attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
     attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
-    attr("global_allocator", None, None),
+    // FIXME: resolve through macro resolution?
+    attr("global_allocator", None, None).prefer_inner(),
     attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
     attr("inline", Some("inline"), Some("inline")),
     attr("link", None, None),
@@ -238,7 +239,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[
     attr("no_mangle", None, None),
     attr("no_std", None, None).prefer_inner(),
     attr("non_exhaustive", None, None),
-    attr("panic_handler", None, None),
+    attr("panic_handler", None, None).prefer_inner(),
     attr(r#"path = "…""#, Some("path"), Some(r#"path ="${0:path}""#)),
     attr("proc_macro", None, None),
     attr("proc_macro_attribute", None, None),
@@ -608,7 +609,6 @@ mod tests {
                 at export_name = "…"
                 at link_name = "…"
                 at link_section = "…"
-                at global_allocator
                 at used
             "#]],
         );
@@ -732,9 +732,9 @@ mod tests {
     }
 
     #[test]
-    fn complete_attribute_on_fn() {
+    fn complete_attribute_on_expr() {
         check(
-            r#"#[$0] fn main() {}"#,
+            r#"fn main() { #[$0] foo() }"#,
             expect![[r#"
                 at allow(…)
                 at cfg(…)
@@ -742,35 +742,10 @@ mod tests {
                 at deny(…)
                 at forbid(…)
                 at warn(…)
-                at deprecated
-                at doc = "…"
-                at doc(hidden)
-                at doc(alias = "…")
-                at must_use
-                at no_mangle
-                at export_name = "…"
-                at link_name = "…"
-                at link_section = "…"
-                at cold
-                at ignore = "…"
-                at inline
-                at must_use
-                at panic_handler
-                at proc_macro
-                at proc_macro_derive(…)
-                at proc_macro_attribute
-                at should_panic
-                at target_feature = "…"
-                at test
-                at track_caller
             "#]],
         );
-    }
-
-    #[test]
-    fn complete_attribute_on_expr() {
         check(
-            r#"fn main() { #[$0] foo() }"#,
+            r#"fn main() { #[$0] foo(); }"#,
             expect![[r#"
                 at allow(…)
                 at cfg(…)
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index cb90e8a3e1..0ea5584893 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -128,19 +128,4 @@ fn outer(text: String) {
             "#]],
         )
     }
-
-    #[test]
-    fn completes_non_ident_pat_param() {
-        check(
-            r#"
-struct Bar { bar: u32 }
-
-fn foo(Bar { bar }: Bar) {}
-fn foo2($0) {}
-"#,
-            expect![[r#"
-                bn Bar { bar }: Bar
-            "#]],
-        )
-    }
 }
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 0d035c6115..e71a04b6ec 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -4,10 +4,7 @@ use std::iter;
 
 use syntax::{SyntaxKind, T};
 
-use crate::{
-    patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind,
-    CompletionKind, Completions,
-};
+use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
 
 pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
     // complete keyword "crate" in use stmt
@@ -47,7 +44,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
         cov_mark::hit!(no_keyword_completion_in_comments);
         return;
     }
-    if matches!(ctx.completion_location, Some(ImmediateLocation::RecordExpr(_))) {
+    if ctx.record_lit_syntax.is_some() {
         cov_mark::hit!(no_keyword_completion_in_record_lit);
         return;
     }
@@ -58,6 +55,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
     let expects_item = ctx.expects_item();
 
     if ctx.has_impl_or_trait_prev_sibling() {
+        // FIXME this also incorrectly shows up after a complete trait/impl
         add_keyword("where", "where ");
         return;
     }
@@ -79,8 +77,11 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
         add_keyword("pub", "pub ");
     }
 
-    if expects_item || expects_assoc_item || has_block_expr_parent {
+    if expects_item || expects_assoc_item || has_block_expr_parent || ctx.is_match_arm {
         add_keyword("unsafe", "unsafe ");
+    }
+
+    if expects_item || expects_assoc_item || has_block_expr_parent {
         add_keyword("fn", "fn $1($2) {\n    $0\n}");
         add_keyword("const", "const $0");
         add_keyword("type", "type $0");
@@ -102,9 +103,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
     }
 
     if ctx.expects_expression() {
-        if !has_block_expr_parent {
-            add_keyword("unsafe", "unsafe {\n    $0\n}");
-        }
         add_keyword("match", "match $1 {\n    $0\n}");
         add_keyword("while", "while $1 {\n    $0\n}");
         add_keyword("while let", "while let $1 = $2 {\n    $0\n}");
@@ -576,7 +574,6 @@ pub mod future {
         check(
             r#"fn main() { let _ = $0 }"#,
             expect![[r#"
-                kw unsafe
                 kw match
                 kw while
                 kw while let
@@ -637,7 +634,6 @@ fn foo() {
 }
 "#,
             expect![[r#"
-                kw unsafe
                 kw match
                 kw while
                 kw while let
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs
index 6a5746fb94..4f94157366 100644
--- a/crates/ide_completion/src/completions/mod_.rs
+++ b/crates/ide_completion/src/completions/mod_.rs
@@ -9,14 +9,14 @@ use ide_db::{
 };
 use rustc_hash::FxHashSet;
 
-use crate::{patterns::ImmediateLocation, CompletionItem};
+use crate::CompletionItem;
 
 use crate::{context::CompletionContext, item::CompletionKind, Completions};
 
 /// Complete mod declaration, i.e. `mod $0 ;`
 pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
-    let mod_under_caret = match &ctx.completion_location {
-        Some(ImmediateLocation::ModDeclaration(mod_under_caret)) => mod_under_caret,
+    let mod_under_caret = match &ctx.mod_declaration_under_caret {
+        Some(mod_under_caret) if mod_under_caret.item_list().is_none() => mod_under_caret,
         _ => return None,
     };
 
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs
index 227c08d010..e1526b70b8 100644
--- a/crates/ide_completion/src/completions/record.rs
+++ b/crates/ide_completion/src/completions/record.rs
@@ -2,21 +2,21 @@
 use ide_db::{helpers::FamousDefs, SymbolKind};
 use syntax::ast::Expr;
 
-use crate::{
-    item::CompletionKind, patterns::ImmediateLocation, CompletionContext, CompletionItem,
-    Completions,
-};
+use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions};
 
 pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
-    let missing_fields = match &ctx.completion_location {
-        Some(ImmediateLocation::RecordExpr(record_expr)) => {
-            let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
+    let missing_fields = match (ctx.record_pat_syntax.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),
+        (_, Some(record_lit)) => {
+            let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_lit.clone()));
             let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default();
             let impl_default_trait = default_trait
                 .zip(ty)
                 .map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[]));
 
-            let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
+            let missing_fields = ctx.sema.record_literal_missing_fields(record_lit);
             if impl_default_trait && !missing_fields.is_empty() {
                 let completion_text = "..Default::default()";
                 let mut item = CompletionItem::new(
@@ -32,10 +32,6 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
 
             missing_fields
         }
-        Some(ImmediateLocation::RecordPat(record_pat)) => {
-            ctx.sema.record_pattern_missing_fields(record_pat)
-        }
-        _ => return None,
     };
 
     for (field, ty) in missing_fields {
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 7c46c815d2..8d6440cb23 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -18,7 +18,7 @@ use text_edit::Indel;
 use crate::{
     patterns::{
         determine_location, determine_prev_sibling, for_is_prev2, inside_impl_trait_block,
-        is_in_loop_body, previous_token, ImmediateLocation, ImmediatePrevSibling,
+        is_in_loop_body, is_match_arm, previous_token, ImmediateLocation, ImmediatePrevSibling,
     },
     CompletionConfig,
 };
@@ -54,6 +54,11 @@ pub(crate) struct CompletionContext<'a> {
     /// The parent impl of the cursor position if it exists.
     pub(super) impl_def: Option<ast::Impl>,
 
+    /// RecordExpr the token is a field of
+    pub(super) record_lit_syntax: Option<ast::RecordExpr>,
+    /// RecordPat the token is a field of
+    pub(super) record_pat_syntax: Option<ast::RecordPat>,
+
     // potentially set if we are completing a lifetime
     pub(super) lifetime_syntax: Option<ast::Lifetime>,
     pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>,
@@ -66,7 +71,6 @@ pub(crate) struct CompletionContext<'a> {
 
     pub(super) completion_location: Option<ImmediateLocation>,
     pub(super) prev_sibling: Option<ImmediatePrevSibling>,
-    pub(super) attribute_under_caret: Option<ast::Attr>,
 
     /// FIXME: `ActiveParameter` is string-based, which is very very wrong
     pub(super) active_parameter: Option<ActiveParameter>,
@@ -91,10 +95,14 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) is_macro_call: bool,
     pub(super) is_path_type: bool,
     pub(super) has_type_args: bool,
+    pub(super) attribute_under_caret: Option<ast::Attr>,
+    pub(super) mod_declaration_under_caret: Option<ast::Module>,
     pub(super) locals: Vec<(String, Local)>,
 
+    // keyword patterns
     pub(super) previous_token: Option<SyntaxToken>,
     pub(super) in_loop_body: bool,
+    pub(super) is_match_arm: bool,
     pub(super) incomplete_let: bool,
 
     no_completion_required: bool,
@@ -149,6 +157,8 @@ impl<'a> CompletionContext<'a> {
             lifetime_param_syntax: None,
             function_def: None,
             use_item_syntax: None,
+            record_lit_syntax: None,
+            record_pat_syntax: None,
             impl_def: None,
             active_parameter: ActiveParameter::at(db, position),
             is_label_ref: false,
@@ -166,13 +176,15 @@ impl<'a> CompletionContext<'a> {
             is_macro_call: false,
             is_path_type: false,
             has_type_args: false,
+            attribute_under_caret: None,
+            mod_declaration_under_caret: None,
             previous_token: None,
             in_loop_body: false,
             completion_location: None,
             prev_sibling: None,
+            is_match_arm: false,
             no_completion_required: false,
             incomplete_let: false,
-            attribute_under_caret: None,
             locals,
         };
 
@@ -215,6 +227,7 @@ impl<'a> CompletionContext<'a> {
                 break;
             }
         }
+        ctx.fill_keyword_patterns(&speculative_file, offset);
         ctx.fill(&original_file, speculative_file, offset);
         Some(ctx)
     }
@@ -298,13 +311,31 @@ impl<'a> CompletionContext<'a> {
     }
 
     pub(crate) fn is_path_disallowed(&self) -> bool {
-        matches!(
-            self.completion_location,
-            Some(ImmediateLocation::Attribute(_))
-                | Some(ImmediateLocation::ModDeclaration(_))
-                | Some(ImmediateLocation::RecordPat(_))
-                | Some(ImmediateLocation::RecordExpr(_))
-        ) || self.attribute_under_caret.is_some()
+        self.record_lit_syntax.is_some()
+            || self.record_pat_syntax.is_some()
+            || self.attribute_under_caret.is_some()
+            || self.mod_declaration_under_caret.is_some()
+    }
+
+    fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) {
+        let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
+        let syntax_element = NodeOrToken::Token(fake_ident_token);
+        self.previous_token = previous_token(syntax_element.clone());
+        self.in_loop_body = is_in_loop_body(syntax_element.clone());
+        self.is_match_arm = is_match_arm(syntax_element.clone());
+
+        self.mod_declaration_under_caret =
+            find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
+                .filter(|module| module.item_list().is_none());
+        self.incomplete_let =
+            syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
+                it.syntax().text_range().end() == syntax_element.text_range().end()
+            });
+
+        let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone());
+        let fn_is_prev = self.previous_token_is(T![fn]);
+        let for_is_prev2 = for_is_prev2(syntax_element.clone());
+        self.no_completion_required = (fn_is_prev && !inside_impl_trait_block) || for_is_prev2;
     }
 
     fn fill_impl_def(&mut self) {
@@ -422,43 +453,25 @@ impl<'a> CompletionContext<'a> {
         file_with_fake_ident: SyntaxNode,
         offset: TextSize,
     ) {
-        let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
-        let syntax_element = NodeOrToken::Token(fake_ident_token);
-        self.previous_token = previous_token(syntax_element.clone());
-        self.attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast);
-        self.no_completion_required = {
-            let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone());
-            let fn_is_prev = self.previous_token_is(T![fn]);
-            let for_is_prev2 = for_is_prev2(syntax_element.clone());
-            (fn_is_prev && !inside_impl_trait_block) || for_is_prev2
-        };
-        self.in_loop_body = is_in_loop_body(syntax_element.clone());
-
-        self.incomplete_let =
-            syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
-                it.syntax().text_range().end() == syntax_element.text_range().end()
-            });
-
         let (expected_type, expected_name) = self.expected_type_and_name();
         self.expected_type = expected_type;
         self.expected_name = expected_name;
-
+        self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset);
         let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) {
             Some(it) => it,
             None => return,
         };
-        self.completion_location =
-            determine_location(&self.sema, original_file, offset, &name_like);
+        self.completion_location = determine_location(&name_like);
         self.prev_sibling = determine_prev_sibling(&name_like);
         match name_like {
             ast::NameLike::Lifetime(lifetime) => {
                 self.classify_lifetime(original_file, lifetime, offset);
             }
             ast::NameLike::NameRef(name_ref) => {
-                self.classify_name_ref(original_file, name_ref);
+                self.classify_name_ref(original_file, name_ref, offset);
             }
             ast::NameLike::Name(name) => {
-                self.classify_name(name);
+                self.classify_name(original_file, name, offset);
             }
         }
     }
@@ -492,7 +505,7 @@ impl<'a> CompletionContext<'a> {
         }
     }
 
-    fn classify_name(&mut self, name: ast::Name) {
+    fn classify_name(&mut self, original_file: &SyntaxNode, name: ast::Name, offset: TextSize) {
         if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
             self.is_pat_or_const = Some(PatternRefutability::Refutable);
             // if any of these is here our bind pat can't be a const pat anymore
@@ -530,12 +543,28 @@ impl<'a> CompletionContext<'a> {
 
             self.fill_impl_def();
         }
-
         self.is_param |= is_node::<ast::Param>(name.syntax());
+        if ast::RecordPatField::for_field_name(&name).is_some() {
+            self.record_pat_syntax =
+                self.sema.find_node_at_offset_with_macros(&original_file, offset);
+        }
     }
 
-    fn classify_name_ref(&mut self, original_file: &SyntaxNode, name_ref: ast::NameRef) {
+    fn classify_name_ref(
+        &mut self,
+        original_file: &SyntaxNode,
+        name_ref: ast::NameRef,
+        offset: TextSize,
+    ) {
         self.fill_impl_def();
+        if ast::RecordExprField::for_field_name(&name_ref).is_some() {
+            self.record_lit_syntax =
+                self.sema.find_node_at_offset_with_macros(original_file, offset);
+        }
+        if ast::RecordPatField::for_field_name_ref(&name_ref).is_some() {
+            self.record_pat_syntax =
+                self.sema.find_node_at_offset_with_macros(&original_file, offset);
+        }
 
         self.name_ref_syntax =
             find_node_at_offset(original_file, name_ref.syntax().text_range().start());
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 26516046bc..caf0ef39fc 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -1,18 +1,15 @@
 //! Patterns telling us certain facts about current syntax element, they are used in completion context
 
-use hir::Semantics;
-use ide_db::RootDatabase;
 use syntax::{
     algo::non_trivia_sibling,
     ast::{self, LoopBodyOwner},
-    match_ast, AstNode, Direction, SyntaxElement,
+    match_ast, AstNode, Direction, NodeOrToken, SyntaxElement,
     SyntaxKind::*,
-    SyntaxNode, SyntaxToken, TextSize, T,
+    SyntaxNode, SyntaxToken, T,
 };
 
 #[cfg(test)]
 use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable};
-
 /// Direct parent container of the cursor position
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub(crate) enum ImmediatePrevSibling {
@@ -22,7 +19,7 @@ pub(crate) enum ImmediatePrevSibling {
 }
 
 /// Direct parent container of the cursor position
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub(crate) enum ImmediateLocation {
     Use,
     Impl,
@@ -32,24 +29,10 @@ pub(crate) enum ImmediateLocation {
     IdentPat,
     BlockExpr,
     ItemList,
-    // Fake file ast node
-    Attribute(ast::Attr),
-    // Fake file ast node
-    ModDeclaration(ast::Module),
-    // Original file ast node
-    /// The record expr of the field name we are completing
-    RecordExpr(ast::RecordExpr),
-    // Original file ast node
-    /// The record pat of the field name we are completing
-    RecordPat(ast::RecordPat),
 }
 
 pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<ImmediatePrevSibling> {
-    let node = match name_like {
-        ast::NameLike::NameRef(name_ref) => maximize_name_ref(name_ref),
-        ast::NameLike::Name(n) => n.syntax().clone(),
-        ast::NameLike::Lifetime(lt) => lt.syntax().clone(),
-    };
+    let node = maximize_name_ref(name_like)?;
     let node = match node.parent().and_then(ast::MacroCall::cast) {
         // When a path is being typed after the name of a trait/type of an impl it is being
         // parsed as a macro, so when the trait/impl has a block following it an we are between the
@@ -94,37 +77,8 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<Immedi
     Some(res)
 }
 
-pub(crate) fn determine_location(
-    sema: &Semantics<RootDatabase>,
-    original_file: &SyntaxNode,
-    offset: TextSize,
-    name_like: &ast::NameLike,
-) -> Option<ImmediateLocation> {
-    let node = match name_like {
-        ast::NameLike::NameRef(name_ref) => {
-            if ast::RecordExprField::for_field_name(&name_ref).is_some() {
-                return sema
-                    .find_node_at_offset_with_macros(original_file, offset)
-                    .map(ImmediateLocation::RecordExpr);
-            }
-            if ast::RecordPatField::for_field_name_ref(&name_ref).is_some() {
-                return sema
-                    .find_node_at_offset_with_macros(original_file, offset)
-                    .map(ImmediateLocation::RecordPat);
-            }
-            maximize_name_ref(name_ref)
-        }
-        ast::NameLike::Name(name) => {
-            if ast::RecordPatField::for_field_name(&name).is_some() {
-                return sema
-                    .find_node_at_offset_with_macros(original_file, offset)
-                    .map(ImmediateLocation::RecordPat);
-            }
-            name.syntax().clone()
-        }
-        ast::NameLike::Lifetime(lt) => lt.syntax().clone(),
-    };
-
+pub(crate) fn determine_location(name_like: &ast::NameLike) -> Option<ImmediateLocation> {
+    let node = maximize_name_ref(name_like)?;
     let parent = match node.parent() {
         Some(parent) => match ast::MacroCall::cast(parent.clone()) {
             // When a path is being typed in an (Assoc)ItemList the parser will always emit a macro_call.
@@ -149,7 +103,6 @@ pub(crate) fn determine_location(
             }
         }
     };
-
     let res = match_ast! {
         match parent {
             ast::IdentPat(_it) => ImmediateLocation::IdentPat,
@@ -164,34 +117,36 @@ pub(crate) fn determine_location(
                 Some(TRAIT) => ImmediateLocation::Trait,
                 _ => return None,
             },
-            ast::Module(it) => if it.item_list().is_none() {
-                    ImmediateLocation::ModDeclaration(it)
-                } else {
-                    return None
-            },
-            ast::Attr(it) => ImmediateLocation::Attribute(it),
             _ => return None,
         }
     };
     Some(res)
 }
 
-fn maximize_name_ref(name_ref: &ast::NameRef) -> SyntaxNode {
-    // Maximize a nameref to its enclosing path if its the last segment of said path
-    if let Some(segment) = name_ref.syntax().parent().and_then(ast::PathSegment::cast) {
-        let p = segment.parent_path();
-        if p.parent_path().is_none() {
-            if let Some(it) = p
-                .syntax()
-                .ancestors()
-                .take_while(|it| it.text_range() == p.syntax().text_range())
-                .last()
-            {
-                return it;
+fn maximize_name_ref(name_like: &ast::NameLike) -> Option<SyntaxNode> {
+    // First walk the element we are completing up to its highest node that has the same text range
+    // as the element so that we can check in what context it immediately lies. We only do this for
+    // NameRef -> Path as that's the only thing that makes sense to being "expanded" semantically.
+    // We only wanna do this if the NameRef is the last segment of the path.
+    let node = match name_like {
+        ast::NameLike::NameRef(name_ref) => {
+            if let Some(segment) = name_ref.syntax().parent().and_then(ast::PathSegment::cast) {
+                let p = segment.parent_path();
+                if p.parent_path().is_none() {
+                    p.syntax()
+                        .ancestors()
+                        .take_while(|it| it.text_range() == p.syntax().text_range())
+                        .last()?
+                } else {
+                    return None;
+                }
+            } else {
+                return None;
             }
         }
-    }
-    name_ref.syntax().clone()
+        it @ ast::NameLike::Name(_) | it @ ast::NameLike::Lifetime(_) => it.syntax().clone(),
+    };
+    Some(node)
 }
 
 pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool {
@@ -212,6 +167,18 @@ fn test_inside_impl_trait_block() {
     check_pattern_is_not_applicable(r"impl A { fn f$0 }", inside_impl_trait_block);
 }
 
+pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
+    not_same_range_ancestor(element.clone()).filter(|it| it.kind() == MATCH_ARM).is_some()
+        && previous_sibling_or_ancestor_sibling(element)
+            .and_then(|it| it.into_token())
+            .filter(|it| it.kind() == FAT_ARROW)
+            .is_some()
+}
+#[test]
+fn test_is_match_arm() {
+    check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm);
+}
+
 pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> {
     element.into_token().and_then(|it| previous_non_trivia_token(it))
 }
@@ -249,6 +216,10 @@ pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
         .is_some()
 }
 
+pub(crate) fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> {
+    element.ancestors().skip_while(|it| it.text_range() == element.text_range()).next()
+}
+
 fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> {
     let mut token = token.prev_token();
     while let Some(inner) = token.clone() {
@@ -261,25 +232,31 @@ fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> {
     None
 }
 
+fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<SyntaxElement> {
+    let token_sibling = non_trivia_sibling(element.clone(), Direction::Prev);
+    if let Some(sibling) = token_sibling {
+        Some(sibling)
+    } else {
+        // if not trying to find first ancestor which has such a sibling
+        let range = element.text_range();
+        let top_node = element.ancestors().take_while(|it| it.text_range() == range).last()?;
+        let prev_sibling_node = top_node.ancestors().find(|it| {
+            non_trivia_sibling(NodeOrToken::Node(it.to_owned()), Direction::Prev).is_some()
+        })?;
+        non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev)
+    }
+}
+
 #[cfg(test)]
 mod tests {
-    use syntax::algo::find_node_at_offset;
-
-    use crate::test_utils::position;
-
     use super::*;
 
     fn check_location(code: &str, loc: impl Into<Option<ImmediateLocation>>) {
-        let (db, pos) = position(code);
-
-        let sema = Semantics::new(&db);
-        let original_file = sema.parse(pos.file_id);
-
-        let name_like = find_node_at_offset(original_file.syntax(), pos.offset).unwrap();
-        assert_eq!(
-            determine_location(&sema, original_file.syntax(), pos.offset, &name_like),
-            loc.into()
-        );
+        check_pattern_is_applicable(code, |e| {
+            let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike");
+            assert_eq!(determine_location(name), loc.into());
+            true
+        });
     }
 
     fn check_prev_sibling(code: &str, sibling: impl Into<Option<ImmediatePrevSibling>>) {
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 2106732cd7..a6c294245d 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -14,7 +14,7 @@ doctest = false
 cov-mark = { version = "1.1", features = ["thread-local"] }
 itertools = "0.10.0"
 rowan = "=0.13.0-pre.6"
-rustc_lexer = { version = "721.0.0", package = "rustc-ap-rustc_lexer" }
+rustc_lexer = { version = "720.0.0", package = "rustc-ap-rustc_lexer" }
 rustc-hash = "1.1.0"
 arrayvec = "0.7"
 once_cell = "1.3.1"


Test patch:
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 49add4ab99..7c0ff2170f 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -161,7 +161,7 @@ mod result {
 }
 
 #[test]
-fn infer_try_trait_v2() {
+fn infer_tryv2() {
     check_types(
         r#"
 //- /main.rs crate:main deps:core
@@ -172,41 +172,26 @@ fn test() {
 } //^ i32
 
 //- /core.rs crate:core
+#[prelude_import] use ops::*;
 mod ops {
-    mod try_trait {
-        pub trait Try: FromResidual {
-            type Output;
-            type Residual;
-        }
-        pub trait FromResidual<R = <Self as Try>::Residual> {}
+    trait Try {
+        type Output;
+        type Residual;
     }
-
-    pub use self::try_trait::FromResidual;
-    pub use self::try_trait::Try;
-}
-
-mov convert {
-    pub trait From<T> {}
-    impl<T> From<T> for T {}
 }
 
 #[prelude_import] use result::*;
 mod result {
-    use crate::convert::From;
-    use crate::ops::{Try, FromResidual};
-
-    pub enum Infallible {}
-    pub enum Result<O, E> {
+    enum Infallible {}
+    enum Result<O, E> {
         Ok(O),
         Err(E)
     }
 
-    impl<O, E> Try for Result<O, E> {
+    impl<O, E> crate::ops::Try for Result<O, E> {
         type Output = O;
         type Error = Result<Infallible, E>;
     }
-
-    impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {}
 }
 "#,
     );