Repository: rust-analyzer/rust-analyzer
Pull request #8046 (2021-03-16 07:51:16)

Prefer match to if let else
bors r+
🤖


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 2efae6a014..b2d009e38f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1811,9 +1811,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
 [[package]]
 name = "ungrammar"
-version = "1.12.2"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df6586a7c530704efe803d49a0b4132dcbdb4063163df39110548e6b5f2373ba"
+checksum = "84c629795d377049f2a1dc5f42cf505dc5ba8b28a5df0a03f4183a24480e4a6a"
 
 [[package]]
 name = "unicase"
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 52939e990f..c5161dadd8 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -52,7 +52,6 @@ use hir_ty::{
     autoderef,
     display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter},
     method_resolution::{self, TyFingerprint},
-    primitive::UintTy,
     to_assoc_type_id,
     traits::{FnTrait, Solution, SolutionVariables},
     AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate,
@@ -1632,10 +1631,6 @@ impl Type {
         matches!(self.ty.value.interned(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
     }
 
-    pub fn is_usize(&self) -> bool {
-        matches!(self.ty.value.interned(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
-    }
-
     pub fn remove_ref(&self) -> Option<Type> {
         match &self.ty.value.interned(&Interner) {
             TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 7052058f2a..8934ae6c9a 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -519,7 +519,7 @@ impl ExprCollector<'_> {
             }
             ast::Expr::MacroCall(e) => {
                 let mut ids = vec![];
-                self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| {
+                self.collect_macro_call(e, syntax_ptr.clone(), |this, expansion| {
                     ids.push(match expansion {
                         Some(it) => this.collect_expr(it),
                         None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -527,17 +527,6 @@ impl ExprCollector<'_> {
                 });
                 ids[0]
             }
-            ast::Expr::MacroStmts(e) => {
-                // FIXME:  these statements should be held by some hir containter
-                for stmt in e.statements() {
-                    self.collect_stmt(stmt);
-                }
-                if let Some(expr) = e.expr() {
-                    self.collect_expr(expr)
-                } else {
-                    self.alloc_expr(Expr::Missing, syntax_ptr)
-                }
-            }
         }
     }
 
@@ -545,7 +534,6 @@ impl ExprCollector<'_> {
         &mut self,
         e: ast::MacroCall,
         syntax_ptr: AstPtr<ast::Expr>,
-        is_error_recoverable: bool,
         mut collector: F,
     ) {
         // File containing the macro call. Expansion errors will be attached here.
@@ -579,7 +567,7 @@ impl ExprCollector<'_> {
             Some((mark, expansion)) => {
                 // FIXME: Statements are too complicated to recover from error for now.
                 // It is because we don't have any hygiene for local variable expansion right now.
-                if !is_error_recoverable && res.err.is_some() {
+                if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
                     self.expander.exit(self.db, mark);
                     collector(self, None);
                 } else {
@@ -603,55 +591,56 @@ impl ExprCollector<'_> {
     }
 
     fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
-        let stmt = match s {
-            ast::Stmt::LetStmt(stmt) => {
-                self.check_cfg(&stmt)?;
-
-                let pat = self.collect_pat_opt(stmt.pat());
-                let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
-                let initializer = stmt.initializer().map(|e| self.collect_expr(e));
-                vec![Statement::Let { pat, type_ref, initializer }]
-            }
-            ast::Stmt::ExprStmt(stmt) => {
-                self.check_cfg(&stmt)?;
-
-                // Note that macro could be expended to multiple statements
-                if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
-                    let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
-                    let mut stmts = vec![];
-
-                    self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
-                        match expansion {
-                            Some(expansion) => {
-                                let statements: ast::MacroStmts = expansion;
-
-                                statements.statements().for_each(|stmt| {
-                                    if let Some(mut r) = this.collect_stmt(stmt) {
-                                        stmts.append(&mut r);
+        let stmt =
+            match s {
+                ast::Stmt::LetStmt(stmt) => {
+                    self.check_cfg(&stmt)?;
+
+                    let pat = self.collect_pat_opt(stmt.pat());
+                    let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
+                    let initializer = stmt.initializer().map(|e| self.collect_expr(e));
+                    vec![Statement::Let { pat, type_ref, initializer }]
+                }
+                ast::Stmt::ExprStmt(stmt) => {
+                    self.check_cfg(&stmt)?;
+
+                    // Note that macro could be expended to multiple statements
+                    if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
+                        let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
+                        let mut stmts = vec![];
+
+                        self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| {
+                            match expansion {
+                                Some(expansion) => {
+                                    let statements: ast::MacroStmts = expansion;
+
+                                    statements.statements().for_each(|stmt| {
+                                        if let Some(mut r) = this.collect_stmt(stmt) {
+                                            stmts.append(&mut r);
+                                        }
+                                    });
+                                    if let Some(expr) = statements.expr() {
+                                        stmts.push(Statement::Expr(this.collect_expr(expr)));
                                     }
-                                });
-                                if let Some(expr) = statements.expr() {
-                                    stmts.push(Statement::Expr(this.collect_expr(expr)));
+                                }
+                                None => {
+                                    stmts.push(Statement::Expr(
+                                        this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
+                                    ));
                                 }
                             }
-                            None => {
-                                stmts.push(Statement::Expr(
-                                    this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
-                                ));
-                            }
-                        }
-                    });
-                    stmts
-                } else {
-                    vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
+                        });
+                        stmts
+                    } else {
+                        vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
+                    }
                 }
-            }
-            ast::Stmt::Item(item) => {
-                self.check_cfg(&item)?;
+                ast::Stmt::Item(item) => {
+                    self.check_cfg(&item)?;
 
-                return None;
-            }
-        };
+                    return None;
+                }
+            };
 
         Some(stmt)
     }
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
index 7188bb299d..ac7474f63f 100644
--- a/crates/hir_def/src/diagnostics.rs
+++ b/crates/hir_def/src/diagnostics.rs
@@ -97,7 +97,7 @@ impl Diagnostic for UnresolvedImport {
 
 // Diagnostic: unresolved-macro-call
 //
-// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
+// This diagnostic is triggered if rust-analyzer is unable to resolove path to a
 // macro in a macro invocation.
 #[derive(Debug)]
 pub struct UnresolvedMacroCall {
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 86239d903c..09bcb10dc0 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -110,11 +110,6 @@ impl ItemTree {
                     // still need to collect inner items.
                     ctx.lower_inner_items(e.syntax())
                 },
-                ast::ExprStmt(stmt) => {
-                    // Macros can expand to stmt. We return an empty item tree in this case, but
-                    // still need to collect inner items.
-                    ctx.lower_inner_items(stmt.syntax())
-                },
                 _ => {
                     panic!("cannot create item tree from {:?} {}", syntax, syntax);
                 },
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 81cf652b0d..9ed48c506c 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -13,7 +13,7 @@ use hir_expand::{
     builtin_macro::find_builtin_macro,
     name::{AsName, Name},
     proc_macro::ProcMacroExpander,
-    HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
+    HirFileId, MacroCallId, MacroDefId, MacroDefKind,
 };
 use hir_expand::{InFile, MacroCallLoc};
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -1455,8 +1455,7 @@ impl ModCollector<'_, '_> {
         let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
 
         // Case 1: try to resolve in legacy scope and expand macro_rules
-        let mut error = None;
-        match macro_call_as_call_id(
+        if let Ok(Ok(macro_call_id)) = macro_call_as_call_id(
             &ast_id,
             self.def_collector.db,
             self.def_collector.def_map.krate,
@@ -1469,28 +1468,16 @@ impl ModCollector<'_, '_> {
                     )
                 })
             },
-            &mut |err| error = Some(err),
+            &mut |_err| (),
         ) {
-            Ok(Ok(macro_call_id)) => {
-                self.def_collector.unexpanded_macros.push(MacroDirective {
-                    module_id: self.module_id,
-                    ast_id,
-                    legacy: Some(macro_call_id),
-                    depth: self.macro_depth + 1,
-                });
+            self.def_collector.unexpanded_macros.push(MacroDirective {
+                module_id: self.module_id,
+                ast_id,
+                legacy: Some(macro_call_id),
+                depth: self.macro_depth + 1,
+            });
 
-                return;
-            }
-            Ok(Err(_)) => {
-                // Built-in macro failed eager expansion.
-                self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
-                    self.module_id,
-                    MacroCallKind::FnLike(ast_id.ast_id),
-                    error.unwrap().to_string(),
-                ));
-                return;
-            }
-            Err(UnresolvedMacro) => (),
+            return;
         }
 
         // Case 2: resolve in module scope, expand during name resolution.
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index a3070f1f94..9086e6c176 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -401,14 +401,13 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
 
     match parent.kind() {
         MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
-        MACRO_STMTS => FragmentKind::Statement,
         ITEM_LIST => FragmentKind::Items,
         LET_STMT => {
             // FIXME: Handle Pattern
             FragmentKind::Expr
         }
         EXPR_STMT => FragmentKind::Statements,
-        BLOCK_EXPR => FragmentKind::Statements,
+        BLOCK_EXPR => FragmentKind::Expr,
         ARG_LIST => FragmentKind::Expr,
         TRY_EXPR => FragmentKind::Expr,
         TUPLE_EXPR => FragmentKind::Expr,
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 7795f446f5..66f8fe8a32 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -300,7 +300,7 @@ impl InferenceTable {
                 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2))
                 | (TyKind::Array(ty1), TyKind::Array(ty2))
                 | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1),
-                _ => true, /* we checked equals_ctor already */
+                _ => false,
             }
         } else {
             self.unify_inner_trivial(&ty1, &ty2, depth)
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 8503852802..503910dde2 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -31,7 +31,6 @@ use hir_def::{
     GenericDefId, HasModule, LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId,
 };
 use itertools::Itertools;
-use smallvec::SmallVec;
 
 use crate::{
     db::HirDatabase,
@@ -273,7 +272,7 @@ impl Ty {
 
 /// A list of substitutions for generic parameters.
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Substs(SmallVec<[Ty; 2]>);
+pub struct Substs(Arc<[Ty]>);
 
 impl TypeWalk for Substs {
     fn walk(&self, f: &mut impl FnMut(&Ty)) {
@@ -287,27 +286,19 @@ impl TypeWalk for Substs {
         f: &mut impl FnMut(&mut Ty, DebruijnIndex),
         binders: DebruijnIndex,
     ) {
-        for t in &mut self.0 {
+        for t in make_mut_slice(&mut self.0) {
             t.walk_mut_binders(f, binders);
         }
     }
 }
 
 impl Substs {
-    pub fn interned(&self, _: &Interner) -> &[Ty] {
-        &self.0
-    }
-
     pub fn empty() -> Substs {
-        Substs(SmallVec::new())
+        Substs(Arc::new([]))
     }
 
     pub fn single(ty: Ty) -> Substs {
-        Substs({
-            let mut v = SmallVec::new();
-            v.push(ty);
-            v
-        })
+        Substs(Arc::new([ty]))
     }
 
     pub fn prefix(&self, n: usize) -> Substs {
@@ -325,10 +316,6 @@ impl Substs {
         &self.0[0]
     }
 
-    pub fn from_iter(_interner: &Interner, elements: impl IntoIterator<Item = Ty>) -> Self {
-        Substs(elements.into_iter().collect())
-    }
-
     /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
     pub(crate) fn type_params_for_generics(
         db: &dyn HirDatabase,
@@ -613,13 +600,13 @@ impl CallableSig {
 
     pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
         CallableSig {
-            params_and_return: fn_ptr.substs.interned(&Interner).iter().cloned().collect(),
+            params_and_return: Arc::clone(&fn_ptr.substs.0),
             is_varargs: fn_ptr.sig.variadic,
         }
     }
 
     pub fn from_substs(substs: &Substs) -> CallableSig {
-        CallableSig { params_and_return: substs.iter().cloned().collect(), is_varargs: false }
+        CallableSig { params_and_return: Arc::clone(&substs.0), is_varargs: false }
     }
 
     pub fn params(&self) -> &[Ty] {
@@ -662,7 +649,7 @@ impl Ty {
         TyKind::Function(FnPointer {
             num_args: sig.params().len(),
             sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs },
-            substs: Substs::from_iter(&Interner, sig.params_and_return.iter().cloned()),
+            substs: Substs(sig.params_and_return),
         })
         .intern(&Interner)
     }
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 6ab757bfcd..b4c650fa1e 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -31,7 +31,7 @@ use crate::{
     traits::chalk::{Interner, ToChalk},
     utils::{
         all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
-        variant_data,
+        make_mut_slice, variant_data,
     },
     AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, FnPointer, FnSig, GenericPredicate,
     ImplTraitId, OpaqueTy, PolyFnSig, ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait,
@@ -150,9 +150,8 @@ impl<'a> TyLoweringContext<'a> {
         let ty = match type_ref {
             TypeRef::Never => TyKind::Never.intern(&Interner),
             TypeRef::Tuple(inner) => {
-                let inner_tys = inner.iter().map(|tr| self.lower_ty(tr));
-                TyKind::Tuple(inner_tys.len(), Substs::from_iter(&Interner, inner_tys))
-                    .intern(&Interner)
+                let inner_tys: Arc<[Ty]> = inner.iter().map(|tr| self.lower_ty(tr)).collect();
+                TyKind::Tuple(inner_tys.len(), Substs(inner_tys)).intern(&Interner)
             }
             TypeRef::Path(path) => {
                 let (ty, res_) = self.lower_path(path);
@@ -639,7 +638,7 @@ impl<'a> TyLoweringContext<'a> {
     ) -> TraitRef {
         let mut substs = self.trait_ref_substs_from_path(segment, resolved);
         if let Some(self_ty) = explicit_self_ty {
-            substs.0[0] = self_ty;
+            make_mut_slice(&mut substs.0)[0] = self_ty;
         }
         TraitRef { trait_: resolved, substs }
     }
diff --git a/crates/hir_ty/src/traits/chalk/interner.rs b/crates/hir_ty/src/traits/chalk/interner.rs
index 94e94a26df..1dc3f497d4 100644
--- a/crates/hir_ty/src/traits/chalk/interner.rs
+++ b/crates/hir_ty/src/traits/chalk/interner.rs
@@ -5,7 +5,6 @@ use super::tls;
 use base_db::salsa::InternId;
 use chalk_ir::{GenericArg, Goal, GoalData};
 use hir_def::TypeAliasId;
-use smallvec::SmallVec;
 use std::{fmt, sync::Arc};
 
 #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
@@ -34,7 +33,7 @@ impl chalk_ir::interner::Interner for Interner {
     type InternedGenericArg = chalk_ir::GenericArgData<Self>;
     type InternedGoal = Arc<GoalData<Self>>;
     type InternedGoals = Vec<Goal<Self>>;
-    type InternedSubstitution = SmallVec<[GenericArg<Self>; 2]>;
+    type InternedSubstitution = Vec<GenericArg<Self>>;
     type InternedProgramClause = Arc<chalk_ir::ProgramClauseData<Self>>;
     type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>;
     type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
@@ -266,13 +265,13 @@ impl chalk_ir::interner::Interner for Interner {
     fn intern_substitution<E>(
         &self,
         data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>,
-    ) -> Result<Self::InternedSubstitution, E> {
+    ) -> Result<Vec<GenericArg<Self>>, E> {
         data.into_iter().collect()
     }
 
     fn substitution_data<'a>(
         &self,
-        substitution: &'a Self::InternedSubstitution,
+        substitution: &'a Vec<GenericArg<Self>>,
     ) -> &'a [GenericArg<Self>] {
         substitution
     }
diff --git a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
index b8834d283d..aa7072f25c 100644
--- a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
+++ b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
@@ -1,7 +1,7 @@
 use hir::{known, HasSource, Name};
 use syntax::{
     ast::{self, NameOwner},
-    AstNode,
+    AstNode, TextRange,
 };
 
 use crate::{
@@ -51,19 +51,12 @@ pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext)
     }
 
     let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?;
-    let len_fn = get_impl_method(ctx, &impl_, &known::len)?;
-    if !len_fn.ret_type(ctx.sema.db).is_usize() {
-        cov_mark::hit!(len_fn_different_return_type);
-        return None;
-    }
-
     if get_impl_method(ctx, &impl_, &known::is_empty).is_some() {
         cov_mark::hit!(is_empty_already_implemented);
         return None;
     }
 
-    let node = len_fn.source(ctx.sema.db)?;
-    let range = node.syntax().value.text_range();
+    let range = get_text_range_of_len_function(ctx, &impl_)?;
 
     acc.add(
         AssistId("generate_is_empty_from_len", AssistKind::Generate),
@@ -96,6 +89,13 @@ fn get_impl_method(
     ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func))
 }
 
+fn get_text_range_of_len_function(ctx: &AssistContext, impl_: &ast::Impl) -> Option<TextRange> {
+    let db = ctx.sema.db;
+    let func = get_impl_method(ctx, impl_, &known::len)?;
+    let node = func.source(db)?;
+    Some(node.syntax().value.text_range())
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -157,23 +157,6 @@ impl MyStruct {
         );
     }
 
-    #[test]
-    fn len_fn_different_return_type() {
-        cov_mark::check!(len_fn_different_return_type);
-        check_assist_not_applicable(
-            generate_is_empty_from_len,
-            r#"
-struct MyStruct { data: Vec<String> }
-
-impl MyStruct {
-    p$0ub fn len(&self) -> u32 {
-        self.data.len()
-    }
-}
-"#,
-        );
-    }
-
     #[test]
     fn generate_is_empty() {
         check_assist(
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index cebb8f4008..6c0e227227 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -63,11 +63,11 @@ pub(crate) mod fragments {
     }
 
     pub(crate) fn stmt(p: &mut Parser) {
-        expressions::stmt(p, expressions::StmtWithSemi::No, true)
+        expressions::stmt(p, expressions::StmtWithSemi::No)
     }
 
     pub(crate) fn stmt_optional_semi(p: &mut Parser) {
-        expressions::stmt(p, expressions::StmtWithSemi::Optional, false)
+        expressions::stmt(p, expressions::StmtWithSemi::Optional)
     }
 
     pub(crate) fn opt_visibility(p: &mut Parser) {
@@ -133,7 +133,7 @@ pub(crate) mod fragments {
                 continue;
             }
 
-            expressions::stmt(p, expressions::StmtWithSemi::Optional, true);
+            expressions::stmt(p, expressions::StmtWithSemi::Optional);
         }
 
         m.complete(p, MACRO_STMTS);
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 0d9dc93489..5f885edfd5 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -54,7 +54,7 @@ fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
     !forbid
 }
 
-pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
+pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
     let m = p.start();
     // test attr_on_expr_stmt
     // fn foo() {
@@ -90,7 +90,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
         p.error(format!("attributes are not allowed on {:?}", kind));
     }
 
-    if p.at(T!['}']) || (prefer_expr && p.at(EOF)) {
+    if p.at(T!['}']) {
         // test attr_on_last_expr_in_block
         // fn foo() {
         //     { #[A] bar!()? }
@@ -198,7 +198,7 @@ pub(super) fn expr_block_contents(p: &mut Parser) {
             continue;
         }
 
-        stmt(p, StmtWithSemi::Yes, false)
+        stmt(p, StmtWithSemi::Yes)
     }
 }
 
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 6097178b6f..064931aece 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1336,7 +1336,6 @@ pub enum Expr {
     Literal(Literal),
     LoopExpr(LoopExpr),
     MacroCall(MacroCall),
-    MacroStmts(MacroStmts),
     MatchExpr(MatchExpr),
     MethodCallExpr(MethodCallExpr),
     ParenExpr(ParenExpr),
@@ -3035,9 +3034,6 @@ impl From<LoopExpr> for Expr {
 impl From<MacroCall> for Expr {
     fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) }
 }
-impl From<MacroStmts> for Expr {
-    fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
-}
 impl From<MatchExpr> for Expr {
     fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
 }
@@ -3082,8 +3078,8 @@ impl AstNode for Expr {
         match kind {
             ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
             | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR
-            | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS
-            | MATCH_EXPR | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
+            | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MATCH_EXPR
+            | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
             | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
             | YIELD_EXPR => true,
             _ => false,
@@ -3109,7 +3105,6 @@ impl AstNode for Expr {
             LITERAL => Expr::Literal(Literal { syntax }),
             LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
             MACRO_CALL => Expr::MacroCall(MacroCall { syntax }),
-            MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
             MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
             METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
             PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
@@ -3147,7 +3142,6 @@ impl AstNode for Expr {
             Expr::Literal(it) => &it.syntax,
             Expr::LoopExpr(it) => &it.syntax,
             Expr::MacroCall(it) => &it.syntax,
-            Expr::MacroStmts(it) => &it.syntax,
             Expr::MatchExpr(it) => &it.syntax,
             Expr::MethodCallExpr(it) => &it.syntax,
             Expr::ParenExpr(it) => &it.syntax,
diff --git a/docs/dev/style.md b/docs/dev/style.md
index c4eb7bc7ae..e4a1672cab 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -787,6 +787,27 @@ assert!(0 > x);
 
 **Rationale:** Less-then comparisons are more intuitive, they correspond spatially to [real line](https://en.wikipedia.org/wiki/Real_line).
 
+## If-let
+
+Avoid `if let ... { } else { }` construct, use `match` instead.
+
+```rust
+// GOOD
+match ctx.expected_type.as_ref() {
+    Some(expected_type) => completion_ty == expected_type && !expected_type.is_unit(),
+    None => false,
+}
+
+// BAD
+if let Some(expected_type) = ctx.expected_type.as_ref() {
+    completion_ty == expected_type && !expected_type.is_unit()
+} else {
+    false
+}
+```
+
+**Rational:** `match` is almost always more compact.
+The `else` branch can get a more precise pattern: `None` or `Err(_)` instead of `_`.
 
 ## Token names
 
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index ad93fbe3bd..e084f0df65 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -11,7 +11,7 @@ anyhow = "1.0.26"
 flate2 = "1.0"
 proc-macro2 = "1.0.8"
 quote = "1.0.2"
-ungrammar = "=1.12"
+ungrammar = "=1.11"
 walkdir = "2.3.1"
 write-json = "0.1.0"
 xshell = "0.1"


Test patch:
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index c22ef46fd6..1b8e885b05 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -155,48 +155,3 @@ fn inactive_via_cfg_attr() {
         "#,
     );
 }
-
-#[test]
-fn unresolved_legacy_scope_macro() {
-    check_diagnostics(
-        r#"
-        //- /lib.rs
-          macro_rules! m { () => {} }
-
-          m!();
-          m2!();
-        //^^^^^^ unresolved macro call
-        "#,
-    );
-}
-
-#[test]
-fn unresolved_module_scope_macro() {
-    check_diagnostics(
-        r#"
-        //- /lib.rs
-          mod mac {
-            #[macro_export]
-            macro_rules! m { () => {} }
-          }
-
-          self::m!();
-          self::m2!();
-        //^^^^^^^^^^^^ unresolved macro call
-        "#,
-    );
-}
-
-#[test]
-fn builtin_macro_fails_expansion() {
-    check_diagnostics(
-        r#"
-        //- /lib.rs
-          #[rustc_builtin_macro]
-          macro_rules! include { () => {} }
-
-          include!("doesntexist");
-        //^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
-        "#,
-    );
-}
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index af4f8bb115..fb3afaedc3 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -215,22 +215,6 @@ fn expr_macro_expanded_in_various_places() {
     );
 }
 
-#[test]
-fn expr_macro_expanded_in_stmts() {
-    check_infer(
-        r#"
-        macro_rules! id { ($($es:tt)*) => { $($es)* } }
-        fn foo() {
-            id! { let a = (); }
-        }
-        "#,
-        expect![[r#"
-            !0..8 'leta=();': ()
-            57..84 '{     ...); } }': ()
-        "#]],
-    );
-}
-
 #[test]
 fn infer_type_value_macro_having_same_name() {
     check_infer(
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 93d3ad020a..e185b1c0a1 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -1699,7 +1699,7 @@ fn super_trait_assoc_type_bounds() {
 
 #[test]
 fn fn_trait() {
-    check_infer_with_mismatches(
+    check_infer(
         r#"
         trait FnOnce<Args> {
             type Output;
@@ -1727,7 +1727,7 @@ fn fn_trait() {
 
 #[test]
 fn fn_ptr_and_item() {
-    check_infer_with_mismatches(
+    check_infer(
         r#"
         #[lang="fn_once"]
         trait FnOnce<Args> {
@@ -1743,12 +1743,12 @@ fn fn_ptr_and_item() {
         struct Bar<T>(T);
 
         impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
-            fn foo(&self) -> (A1, R) { loop {} }
+            fn foo(&self) -> (A1, R) {}
         }
 
         enum Opt<T> { None, Some(T) }
         impl<T> Opt<T> {
-            fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> { loop {} }
+            fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> {}
         }
 
         fn test() {
@@ -1765,23 +1765,19 @@ fn fn_ptr_and_item() {
             80..84 'args': Args
             139..143 'self': &Self
             243..247 'self': &Bar<F>
-            260..271 '{ loop {} }': (A1, R)
-            262..269 'loop {}': !
-            267..269 '{}': ()
-            355..359 'self': Opt<T>
-            361..362 'f': F
-            377..388 '{ loop {} }': Opt<U>
-            379..386 'loop {}': !
-            384..386 '{}': ()
-            402..518 '{     ...(f); }': ()
-            412..415 'bar': Bar<fn(u8) -> u32>
-            441..444 'bar': Bar<fn(u8) -> u32>
-            441..450 'bar.foo()': (u8, u32)
-            461..464 'opt': Opt<u8>
-            483..484 'f': fn(u8) -> u32
-            505..508 'opt': Opt<u8>
-            505..515 'opt.map(f)': Opt<u32>
-            513..514 'f': fn(u8) -> u32
+            260..262 '{}': ()
+            346..350 'self': Opt<T>
+            352..353 'f': F
+            368..370 '{}': ()
+            384..500 '{     ...(f); }': ()
+            394..397 'bar': Bar<fn(u8) -> u32>
+            423..426 'bar': Bar<fn(u8) -> u32>
+            423..432 'bar.foo()': (u8, u32)
+            443..446 'opt': Opt<u8>
+            465..466 'f': fn(u8) -> u32
+            487..490 'opt': Opt<u8>
+            487..497 'opt.map(f)': Opt<u32>
+            495..496 'f': fn(u8) -> u32
         "#]],
     );
 }
@@ -1863,7 +1859,7 @@ fn fn_trait_deref_with_ty_default() {
 
 #[test]
 fn closure_1() {
-    check_infer_with_mismatches(
+    check_infer(
         r#"
         #[lang = "fn_once"]
         trait FnOnce<Args> {
@@ -1872,7 +1868,7 @@ fn closure_1() {
 
         enum Option<T> { Some(T), None }
         impl<T> Option<T> {
-            fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} }
+            fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {}
         }
 
         fn test() {
@@ -1885,39 +1881,37 @@ fn closure_1() {
         expect![[r#"
             147..151 'self': Option<T>
             153..154 'f': F
-            172..183 '{ loop {} }': Option<U>
-            174..181 'loop {}': !
-            179..181 '{}': ()
-            197..316 '{     ... 1); }': ()
-            207..208 'x': Option<u32>
-            211..223 'Option::Some': Some<u32>(u32) -> Option<u32>
-            211..229 'Option...(1u32)': Option<u32>
-            224..228 '1u32': u32
-            235..236 'x': Option<u32>
-            235..251 'x.map(...v + 1)': Option<u32>
-            241..250 '|v| v + 1': |u32| -> u32
-            242..243 'v': u32
-            245..246 'v': u32
-            245..250 'v + 1': u32
-            249..250 '1': u32
-            257..258 'x': Option<u32>
-            257..273 'x.map(... 1u64)': Option<u64>
-            263..272 '|_v| 1u64': |u32| -> u64
-            264..266 '_v': u32
-            268..272 '1u64': u64
-            283..284 'y': Option<i64>
-            300..301 'x': Option<u32>
-            300..313 'x.map(|_v| 1)': Option<i64>
-            306..312 '|_v| 1': |u32| -> i64
-            307..309 '_v': u32
-            311..312 '1': i64
+            172..174 '{}': ()
+            188..307 '{     ... 1); }': ()
+            198..199 'x': Option<u32>
+            202..214 'Option::Some': Some<u32>(u32) -> Option<u32>
+            202..220 'Option...(1u32)': Option<u32>
+            215..219 '1u32': u32
+            226..227 'x': Option<u32>
+            226..242 'x.map(...v + 1)': Option<u32>
+            232..241 '|v| v + 1': |u32| -> u32
+            233..234 'v': u32
+            236..237 'v': u32
+            236..241 'v + 1': u32
+            240..241 '1': u32
+            248..249 'x': Option<u32>
+            248..264 'x.map(... 1u64)': Option<u64>
+            254..263 '|_v| 1u64': |u32| -> u64
+            255..257 '_v': u32
+            259..263 '1u64': u64
+            274..275 'y': Option<i64>
+            291..292 'x': Option<u32>
+            291..304 'x.map(|_v| 1)': Option<i64>
+            297..303 '|_v| 1': |u32| -> i64
+            298..300 '_v': u32
+            302..303 '1': i64
         "#]],
     );
 }
 
 #[test]
 fn closure_2() {
-    check_infer_with_mismatches(
+    check_infer(
         r#"
         trait FnOnce<Args> {
             type Output;
@@ -1957,22 +1951,22 @@ fn closure_2() {
 
 #[test]
 fn closure_as_argument_inference_order() {
-    check_infer_with_mismatches(
+    check_infer(
         r#"
         #[lang = "fn_once"]
         trait FnOnce<Args> {
             type Output;
         }
 
-        fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} }
-        fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} }
+        fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
+        fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
 
         struct S;
         impl S {
             fn method(self) -> u64;
 
-            fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U { loop {} }
-            fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U { loop {} }
+            fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {}
+            fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {}
         }
 
         fn test() {
@@ -1985,60 +1979,52 @@ fn closure_as_argument_inference_order() {
         expect![[r#"
             94..95 'x': T
             100..101 'f': F
-            111..122 '{ loop {} }': U
-            113..120 'loop {}': !
-            118..120 '{}': ()
-            156..157 'f': F
-            162..163 'x': T
-            173..184 '{ loop {} }': U
-            175..182 'loop {}': !
-            180..182 '{}': ()
-            219..223 'self': S
-            271..275 'self': S
-            277..278 'x': T
-            283..284 'f': F
-            294..305 '{ loop {} }': U
-            296..303 'loop {}': !
-            301..303 '{}': ()
-            343..347 'self': S
-            349..350 'f': F
-            355..356 'x': T
-            366..377 '{ loop {} }': U
-            368..375 'loop {}': !
-            373..375 '{}': ()
-            391..550 '{     ... S); }': ()
-            401..403 'x1': u64
-            406..410 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
-            406..429 'foo1(S...hod())': u64
-            411..412 'S': S
-            414..428 '|s| s.method()': |S| -> u64
-            415..416 's': S
-            418..419 's': S
-            418..428 's.method()': u64
-            439..441 'x2': u64
-            444..448 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
-            444..467 'foo2(|...(), S)': u64
-            449..463 '|s| s.method()': |S| -> u64
-            450..451 's': S
-            453..454 's': S
-            453..463 's.method()': u64
-            465..466 'S': S
-            477..479 'x3': u64
-            482..483 'S': S
-            482..507 'S.foo1...hod())': u64
-            489..490 'S': S
-            492..506 '|s| s.method()': |S| -> u64
-            493..494 's': S
-            496..497 's': S
-            496..506 's.method()': u64
-            517..519 'x4': u64
-            522..523 'S': S
-            522..547 'S.foo2...(), S)': u64
-            529..543 '|s| s.method()': |S| -> u64
-            530..531 's': S
-            533..534 's': S
-            533..543 's.method()': u64
-            545..546 'S': S
+            111..113 '{}': ()
+            147..148 'f': F
+            153..154 'x': T
+            164..166 '{}': ()
+            201..205 'self': S
+            253..257 'self': S
+            259..260 'x': T
+            265..266 'f': F
+            276..278 '{}': ()
+            316..320 'self': S
+            322..323 'f': F
+            328..329 'x': T
+            339..341 '{}': ()
+            355..514 '{     ... S); }': ()
+            365..367 'x1': u64
+            370..374 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
+            370..393 'foo1(S...hod())': u64
+            375..376 'S': S
+            378..392 '|s| s.method()': |S| -> u64
+            379..380 's': S
+            382..383 's': S
+            382..392 's.method()': u64
+            403..405 'x2': u64
+            408..412 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
+            408..431 'foo2(|...(), S)': u64
+            413..427 '|s| s.method()': |S| -> u64
+            414..415 's': S
+            417..418 's': S
+            417..427 's.method()': u64
+            429..430 'S': S
+            441..443 'x3': u64
+            446..447 'S': S
+            446..471 'S.foo1...hod())': u64
+            453..454 'S': S
+            456..470 '|s| s.method()': |S| -> u64
+            457..458 's': S
+            460..461 's': S
+            460..470 's.method()': u64
+            481..483 'x4': u64
+            486..487 'S': S
+            486..511 'S.foo2...(), S)': u64
+            493..507 '|s| s.method()': |S| -> u64
+            494..495 's': S
+            497..498 's': S
+            497..507 's.method()': u64
+            509..510 'S': S
         "#]],
     );
 }
@@ -2550,7 +2536,7 @@ fn test() {
 
 #[test]
 fn iterator_chain() {
-    check_infer_with_mismatches(
+    check_infer(
         r#"
         //- /main.rs
         #[lang = "fn_once"]
@@ -2953,7 +2939,7 @@ fn infer_closure_arg() {
 
 #[test]
 fn infer_fn_trait_arg() {
-    check_infer_with_mismatches(
+    check_infer(
         r#"
         //- /lib.rs deps:std
 
@@ -3000,8 +2986,7 @@ fn infer_fn_trait_arg() {
 
 #[test]
 fn infer_box_fn_arg() {
-    // The type mismatch is a bug
-    check_infer_with_mismatches(
+    check_infer(
         r#"
         //- /lib.rs deps:std
 
@@ -3040,7 +3025,7 @@ fn infer_box_fn_arg() {
         fn foo() {
             let s = Option::None;
             let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
-            f(&s);
+            f(&s)
         }
         "#,
         expect![[r#"
@@ -3052,7 +3037,7 @@ fn infer_box_fn_arg() {
             406..417 '&self.inner': &*mut T
             407..411 'self': &Box<T>
             407..417 'self.inner': *mut T
-            478..576 '{     ...&s); }': ()
+            478..575 '{     ...(&s) }': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)>
             488..489 's': Option<i32>
             492..504 'Option::None': Option<i32>
             514..515 'f': Box<dyn FnOnce(&Option<i32>)>
@@ -3064,7 +3049,6 @@ fn infer_box_fn_arg() {
             568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)>
             570..572 '&s': &Option<i32>
             571..572 's': Option<i32>
-            549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|_| -> ()>
         "#]],
     );
 }
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index eca0bcc18b..3a168bb4b4 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -662,11 +662,12 @@ fn test_tt_to_stmts() {
         LITERAL@12..13
           INT_NUMBER@12..13 "1"
     SEMICOLON@13..14 ";"
-  PATH_EXPR@14..15
-    PATH@14..15
-      PATH_SEGMENT@14..15
-        NAME_REF@14..15
-          IDENT@14..15 "a""#,
+  EXPR_STMT@14..15
+    PATH_EXPR@14..15
+      PATH@14..15
+        PATH_SEGMENT@14..15
+          NAME_REF@14..15
+            IDENT@14..15 "a""#,
     );
 }