aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yaml17
-rw-r--r--Cargo.lock4
-rw-r--r--crates/hir/src/lib.rs5
-rw-r--r--crates/hir_def/src/body/lower.rs105
-rw-r--r--crates/hir_def/src/diagnostics.rs2
-rw-r--r--crates/hir_def/src/item_tree.rs5
-rw-r--r--crates/hir_def/src/nameres/collector.rs33
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs45
-rw-r--r--crates/hir_expand/src/db.rs3
-rw-r--r--crates/hir_ty/src/infer/unify.rs2
-rw-r--r--crates/hir_ty/src/lib.rs27
-rw-r--r--crates/hir_ty/src/lower.rs9
-rw-r--r--crates/hir_ty/src/tests/macros.rs16
-rw-r--r--crates/hir_ty/src/tests/traits.rs216
-rw-r--r--crates/hir_ty/src/traits/chalk/interner.rs7
-rw-r--r--crates/ide_assists/src/handlers/generate_is_empty_from_len.rs35
-rw-r--r--crates/ide_completion/src/render.rs182
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs13
-rw-r--r--crates/ide_completion/src/render/function.rs27
-rw-r--r--crates/mbe/src/tests.rs11
-rw-r--r--crates/parser/src/grammar.rs6
-rw-r--r--crates/parser/src/grammar/expressions.rs6
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs10
-rw-r--r--xtask/Cargo.toml2
24 files changed, 538 insertions, 250 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 32c7cf7ef..ae9dccce9 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -13,6 +13,7 @@ env:
13 CARGO_NET_RETRY: 10 13 CARGO_NET_RETRY: 10
14 RUSTFLAGS: "-D warnings -W unreachable-pub" 14 RUSTFLAGS: "-D warnings -W unreachable-pub"
15 RUSTUP_MAX_RETRIES: 10 15 RUSTUP_MAX_RETRIES: 10
16 FETCH_DEPTH: 200
16 17
17jobs: 18jobs:
18 dist-x86_64-pc-windows-msvc: 19 dist-x86_64-pc-windows-msvc:
@@ -24,6 +25,8 @@ jobs:
24 steps: 25 steps:
25 - name: Checkout repository 26 - name: Checkout repository
26 uses: actions/checkout@v2 27 uses: actions/checkout@v2
28 with:
29 fetch-depth: ${{ env.FETCH_DEPTH }}
27 30
28 # We need to disable the existing toolchain to avoid updating rust-docs 31 # We need to disable the existing toolchain to avoid updating rust-docs
29 # which takes a long time. The fastest way to do this is to rename the 32 # which takes a long time. The fastest way to do this is to rename the
@@ -57,6 +60,8 @@ jobs:
57 steps: 60 steps:
58 - name: Checkout repository 61 - name: Checkout repository
59 uses: actions/checkout@v2 62 uses: actions/checkout@v2
63 with:
64 fetch-depth: ${{ env.FETCH_DEPTH }}
60 65
61 - name: Rename existing rust toolchain 66 - name: Rename existing rust toolchain
62 run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old 67 run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old
@@ -87,6 +92,8 @@ jobs:
87 steps: 92 steps:
88 - name: Checkout repository 93 - name: Checkout repository
89 uses: actions/checkout@v2 94 uses: actions/checkout@v2
95 with:
96 fetch-depth: ${{ env.FETCH_DEPTH }}
90 97
91 - name: Install Rust toolchain 98 - name: Install Rust toolchain
92 uses: actions-rs/toolchain@v1 99 uses: actions-rs/toolchain@v1
@@ -139,6 +146,8 @@ jobs:
139 146
140 - name: Checkout repository 147 - name: Checkout repository
141 uses: actions/checkout@v2 148 uses: actions/checkout@v2
149 with:
150 fetch-depth: ${{ env.FETCH_DEPTH }}
142 151
143 - name: Dist 152 - name: Dist
144 run: cargo xtask dist 153 run: cargo xtask dist
@@ -159,6 +168,8 @@ jobs:
159 steps: 168 steps:
160 - name: Checkout repository 169 - name: Checkout repository
161 uses: actions/checkout@v2 170 uses: actions/checkout@v2
171 with:
172 fetch-depth: ${{ env.FETCH_DEPTH }}
162 173
163 - name: Install Rust toolchain 174 - name: Install Rust toolchain
164 uses: actions-rs/toolchain@v1 175 uses: actions-rs/toolchain@v1
@@ -193,6 +204,8 @@ jobs:
193 204
194 - name: Checkout repository 205 - name: Checkout repository
195 uses: actions/checkout@v2 206 uses: actions/checkout@v2
207 with:
208 fetch-depth: ${{ env.FETCH_DEPTH }}
196 209
197 - name: Install Rust toolchain 210 - name: Install Rust toolchain
198 uses: actions-rs/toolchain@v1 211 uses: actions-rs/toolchain@v1
@@ -223,6 +236,8 @@ jobs:
223 236
224 - name: Checkout repository 237 - name: Checkout repository
225 uses: actions/checkout@v2 238 uses: actions/checkout@v2
239 with:
240 fetch-depth: ${{ env.FETCH_DEPTH }}
226 241
227 - name: Install Rust toolchain 242 - name: Install Rust toolchain
228 uses: actions-rs/toolchain@v1 243 uses: actions-rs/toolchain@v1
@@ -259,6 +274,8 @@ jobs:
259 274
260 - name: Checkout repository 275 - name: Checkout repository
261 uses: actions/checkout@v2 276 uses: actions/checkout@v2
277 with:
278 fetch-depth: ${{ env.FETCH_DEPTH }}
262 279
263 - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV 280 - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
264 - run: 'echo "HEAD_SHA: $HEAD_SHA"' 281 - run: 'echo "HEAD_SHA: $HEAD_SHA"'
diff --git a/Cargo.lock b/Cargo.lock
index b2d009e38..2efae6a01 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1811,9 +1811,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
1811 1811
1812[[package]] 1812[[package]]
1813name = "ungrammar" 1813name = "ungrammar"
1814version = "1.11.0" 1814version = "1.12.2"
1815source = "registry+https://github.com/rust-lang/crates.io-index" 1815source = "registry+https://github.com/rust-lang/crates.io-index"
1816checksum = "84c629795d377049f2a1dc5f42cf505dc5ba8b28a5df0a03f4183a24480e4a6a" 1816checksum = "df6586a7c530704efe803d49a0b4132dcbdb4063163df39110548e6b5f2373ba"
1817 1817
1818[[package]] 1818[[package]]
1819name = "unicase" 1819name = "unicase"
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index c5161dadd..52939e990 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -52,6 +52,7 @@ use hir_ty::{
52 autoderef, 52 autoderef,
53 display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter}, 53 display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter},
54 method_resolution::{self, TyFingerprint}, 54 method_resolution::{self, TyFingerprint},
55 primitive::UintTy,
55 to_assoc_type_id, 56 to_assoc_type_id,
56 traits::{FnTrait, Solution, SolutionVariables}, 57 traits::{FnTrait, Solution, SolutionVariables},
57 AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, 58 AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate,
@@ -1631,6 +1632,10 @@ impl Type {
1631 matches!(self.ty.value.interned(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..)) 1632 matches!(self.ty.value.interned(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
1632 } 1633 }
1633 1634
1635 pub fn is_usize(&self) -> bool {
1636 matches!(self.ty.value.interned(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
1637 }
1638
1634 pub fn remove_ref(&self) -> Option<Type> { 1639 pub fn remove_ref(&self) -> Option<Type> {
1635 match &self.ty.value.interned(&Interner) { 1640 match &self.ty.value.interned(&Interner) {
1636 TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), 1641 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 8934ae6c9..7052058f2 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -519,7 +519,7 @@ impl ExprCollector<'_> {
519 } 519 }
520 ast::Expr::MacroCall(e) => { 520 ast::Expr::MacroCall(e) => {
521 let mut ids = vec![]; 521 let mut ids = vec![];
522 self.collect_macro_call(e, syntax_ptr.clone(), |this, expansion| { 522 self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| {
523 ids.push(match expansion { 523 ids.push(match expansion {
524 Some(it) => this.collect_expr(it), 524 Some(it) => this.collect_expr(it),
525 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 525 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -527,6 +527,17 @@ impl ExprCollector<'_> {
527 }); 527 });
528 ids[0] 528 ids[0]
529 } 529 }
530 ast::Expr::MacroStmts(e) => {
531 // FIXME: these statements should be held by some hir containter
532 for stmt in e.statements() {
533 self.collect_stmt(stmt);
534 }
535 if let Some(expr) = e.expr() {
536 self.collect_expr(expr)
537 } else {
538 self.alloc_expr(Expr::Missing, syntax_ptr)
539 }
540 }
530 } 541 }
531 } 542 }
532 543
@@ -534,6 +545,7 @@ impl ExprCollector<'_> {
534 &mut self, 545 &mut self,
535 e: ast::MacroCall, 546 e: ast::MacroCall,
536 syntax_ptr: AstPtr<ast::Expr>, 547 syntax_ptr: AstPtr<ast::Expr>,
548 is_error_recoverable: bool,
537 mut collector: F, 549 mut collector: F,
538 ) { 550 ) {
539 // File containing the macro call. Expansion errors will be attached here. 551 // File containing the macro call. Expansion errors will be attached here.
@@ -567,7 +579,7 @@ impl ExprCollector<'_> {
567 Some((mark, expansion)) => { 579 Some((mark, expansion)) => {
568 // FIXME: Statements are too complicated to recover from error for now. 580 // FIXME: Statements are too complicated to recover from error for now.
569 // It is because we don't have any hygiene for local variable expansion right now. 581 // It is because we don't have any hygiene for local variable expansion right now.
570 if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() { 582 if !is_error_recoverable && res.err.is_some() {
571 self.expander.exit(self.db, mark); 583 self.expander.exit(self.db, mark);
572 collector(self, None); 584 collector(self, None);
573 } else { 585 } else {
@@ -591,56 +603,55 @@ impl ExprCollector<'_> {
591 } 603 }
592 604
593 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> { 605 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
594 let stmt = 606 let stmt = match s {
595 match s { 607 ast::Stmt::LetStmt(stmt) => {
596 ast::Stmt::LetStmt(stmt) => { 608 self.check_cfg(&stmt)?;
597 self.check_cfg(&stmt)?; 609
598 610 let pat = self.collect_pat_opt(stmt.pat());
599 let pat = self.collect_pat_opt(stmt.pat()); 611 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
600 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 612 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
601 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 613 vec![Statement::Let { pat, type_ref, initializer }]
602 vec![Statement::Let { pat, type_ref, initializer }] 614 }
603 } 615 ast::Stmt::ExprStmt(stmt) => {
604 ast::Stmt::ExprStmt(stmt) => { 616 self.check_cfg(&stmt)?;
605 self.check_cfg(&stmt)?; 617
606 618 // Note that macro could be expended to multiple statements
607 // Note that macro could be expended to multiple statements 619 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
608 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 620 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
609 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 621 let mut stmts = vec![];
610 let mut stmts = vec![]; 622
611 623 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
612 self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| { 624 match expansion {
613 match expansion { 625 Some(expansion) => {
614 Some(expansion) => { 626 let statements: ast::MacroStmts = expansion;
615 let statements: ast::MacroStmts = expansion; 627
616 628 statements.statements().for_each(|stmt| {
617 statements.statements().for_each(|stmt| { 629 if let Some(mut r) = this.collect_stmt(stmt) {
618 if let Some(mut r) = this.collect_stmt(stmt) { 630 stmts.append(&mut r);
619 stmts.append(&mut r);
620 }
621 });
622 if let Some(expr) = statements.expr() {
623 stmts.push(Statement::Expr(this.collect_expr(expr)));
624 } 631 }
625 } 632 });
626 None => { 633 if let Some(expr) = statements.expr() {
627 stmts.push(Statement::Expr( 634 stmts.push(Statement::Expr(this.collect_expr(expr)));
628 this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
629 ));
630 } 635 }
631 } 636 }
632 }); 637 None => {
633 stmts 638 stmts.push(Statement::Expr(
634 } else { 639 this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
635 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] 640 ));
636 } 641 }
642 }
643 });
644 stmts
645 } else {
646 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
637 } 647 }
638 ast::Stmt::Item(item) => { 648 }
639 self.check_cfg(&item)?; 649 ast::Stmt::Item(item) => {
650 self.check_cfg(&item)?;
640 651
641 return None; 652 return None;
642 } 653 }
643 }; 654 };
644 655
645 Some(stmt) 656 Some(stmt)
646 } 657 }
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
index ac7474f63..7188bb299 100644
--- a/crates/hir_def/src/diagnostics.rs
+++ b/crates/hir_def/src/diagnostics.rs
@@ -97,7 +97,7 @@ impl Diagnostic for UnresolvedImport {
97 97
98// Diagnostic: unresolved-macro-call 98// Diagnostic: unresolved-macro-call
99// 99//
100// This diagnostic is triggered if rust-analyzer is unable to resolove path to a 100// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
101// macro in a macro invocation. 101// macro in a macro invocation.
102#[derive(Debug)] 102#[derive(Debug)]
103pub struct UnresolvedMacroCall { 103pub struct UnresolvedMacroCall {
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 09bcb10dc..86239d903 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -110,6 +110,11 @@ impl ItemTree {
110 // still need to collect inner items. 110 // still need to collect inner items.
111 ctx.lower_inner_items(e.syntax()) 111 ctx.lower_inner_items(e.syntax())
112 }, 112 },
113 ast::ExprStmt(stmt) => {
114 // Macros can expand to stmt. We return an empty item tree in this case, but
115 // still need to collect inner items.
116 ctx.lower_inner_items(stmt.syntax())
117 },
113 _ => { 118 _ => {
114 panic!("cannot create item tree from {:?} {}", syntax, syntax); 119 panic!("cannot create item tree from {:?} {}", syntax, syntax);
115 }, 120 },
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 9ed48c506..81cf652b0 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -13,7 +13,7 @@ use hir_expand::{
13 builtin_macro::find_builtin_macro, 13 builtin_macro::find_builtin_macro,
14 name::{AsName, Name}, 14 name::{AsName, Name},
15 proc_macro::ProcMacroExpander, 15 proc_macro::ProcMacroExpander,
16 HirFileId, MacroCallId, MacroDefId, MacroDefKind, 16 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
17}; 17};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
@@ -1455,7 +1455,8 @@ impl ModCollector<'_, '_> {
1455 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); 1455 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
1456 1456
1457 // Case 1: try to resolve in legacy scope and expand macro_rules 1457 // Case 1: try to resolve in legacy scope and expand macro_rules
1458 if let Ok(Ok(macro_call_id)) = macro_call_as_call_id( 1458 let mut error = None;
1459 match macro_call_as_call_id(
1459 &ast_id, 1460 &ast_id,
1460 self.def_collector.db, 1461 self.def_collector.db,
1461 self.def_collector.def_map.krate, 1462 self.def_collector.def_map.krate,
@@ -1468,16 +1469,28 @@ impl ModCollector<'_, '_> {
1468 ) 1469 )
1469 }) 1470 })
1470 }, 1471 },
1471 &mut |_err| (), 1472 &mut |err| error = Some(err),
1472 ) { 1473 ) {
1473 self.def_collector.unexpanded_macros.push(MacroDirective { 1474 Ok(Ok(macro_call_id)) => {
1474 module_id: self.module_id, 1475 self.def_collector.unexpanded_macros.push(MacroDirective {
1475 ast_id, 1476 module_id: self.module_id,
1476 legacy: Some(macro_call_id), 1477 ast_id,
1477 depth: self.macro_depth + 1, 1478 legacy: Some(macro_call_id),
1478 }); 1479 depth: self.macro_depth + 1,
1480 });
1479 1481
1480 return; 1482 return;
1483 }
1484 Ok(Err(_)) => {
1485 // Built-in macro failed eager expansion.
1486 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
1487 self.module_id,
1488 MacroCallKind::FnLike(ast_id.ast_id),
1489 error.unwrap().to_string(),
1490 ));
1491 return;
1492 }
1493 Err(UnresolvedMacro) => (),
1481 } 1494 }
1482 1495
1483 // Case 2: resolve in module scope, expand during name resolution. 1496 // Case 2: resolve in module scope, expand during name resolution.
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index 1b8e885b0..c22ef46fd 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -155,3 +155,48 @@ fn inactive_via_cfg_attr() {
155 "#, 155 "#,
156 ); 156 );
157} 157}
158
159#[test]
160fn unresolved_legacy_scope_macro() {
161 check_diagnostics(
162 r#"
163 //- /lib.rs
164 macro_rules! m { () => {} }
165
166 m!();
167 m2!();
168 //^^^^^^ unresolved macro call
169 "#,
170 );
171}
172
173#[test]
174fn unresolved_module_scope_macro() {
175 check_diagnostics(
176 r#"
177 //- /lib.rs
178 mod mac {
179 #[macro_export]
180 macro_rules! m { () => {} }
181 }
182
183 self::m!();
184 self::m2!();
185 //^^^^^^^^^^^^ unresolved macro call
186 "#,
187 );
188}
189
190#[test]
191fn builtin_macro_fails_expansion() {
192 check_diagnostics(
193 r#"
194 //- /lib.rs
195 #[rustc_builtin_macro]
196 macro_rules! include { () => {} }
197
198 include!("doesntexist");
199 //^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
200 "#,
201 );
202}
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 9086e6c17..a3070f1f9 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -401,13 +401,14 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
401 401
402 match parent.kind() { 402 match parent.kind() {
403 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, 403 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
404 MACRO_STMTS => FragmentKind::Statement,
404 ITEM_LIST => FragmentKind::Items, 405 ITEM_LIST => FragmentKind::Items,
405 LET_STMT => { 406 LET_STMT => {
406 // FIXME: Handle Pattern 407 // FIXME: Handle Pattern
407 FragmentKind::Expr 408 FragmentKind::Expr
408 } 409 }
409 EXPR_STMT => FragmentKind::Statements, 410 EXPR_STMT => FragmentKind::Statements,
410 BLOCK_EXPR => FragmentKind::Expr, 411 BLOCK_EXPR => FragmentKind::Statements,
411 ARG_LIST => FragmentKind::Expr, 412 ARG_LIST => FragmentKind::Expr,
412 TRY_EXPR => FragmentKind::Expr, 413 TRY_EXPR => FragmentKind::Expr,
413 TUPLE_EXPR => FragmentKind::Expr, 414 TUPLE_EXPR => FragmentKind::Expr,
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 66f8fe8a3..7795f446f 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -300,7 +300,7 @@ impl InferenceTable {
300 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2)) 300 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2))
301 | (TyKind::Array(ty1), TyKind::Array(ty2)) 301 | (TyKind::Array(ty1), TyKind::Array(ty2))
302 | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1), 302 | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1),
303 _ => false, 303 _ => true, /* we checked equals_ctor already */
304 } 304 }
305 } else { 305 } else {
306 self.unify_inner_trivial(&ty1, &ty2, depth) 306 self.unify_inner_trivial(&ty1, &ty2, depth)
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 503910dde..850385280 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -31,6 +31,7 @@ use hir_def::{
31 GenericDefId, HasModule, LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, 31 GenericDefId, HasModule, LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId,
32}; 32};
33use itertools::Itertools; 33use itertools::Itertools;
34use smallvec::SmallVec;
34 35
35use crate::{ 36use crate::{
36 db::HirDatabase, 37 db::HirDatabase,
@@ -272,7 +273,7 @@ impl Ty {
272 273
273/// A list of substitutions for generic parameters. 274/// A list of substitutions for generic parameters.
274#[derive(Clone, PartialEq, Eq, Debug, Hash)] 275#[derive(Clone, PartialEq, Eq, Debug, Hash)]
275pub struct Substs(Arc<[Ty]>); 276pub struct Substs(SmallVec<[Ty; 2]>);
276 277
277impl TypeWalk for Substs { 278impl TypeWalk for Substs {
278 fn walk(&self, f: &mut impl FnMut(&Ty)) { 279 fn walk(&self, f: &mut impl FnMut(&Ty)) {
@@ -286,19 +287,27 @@ impl TypeWalk for Substs {
286 f: &mut impl FnMut(&mut Ty, DebruijnIndex), 287 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
287 binders: DebruijnIndex, 288 binders: DebruijnIndex,
288 ) { 289 ) {
289 for t in make_mut_slice(&mut self.0) { 290 for t in &mut self.0 {
290 t.walk_mut_binders(f, binders); 291 t.walk_mut_binders(f, binders);
291 } 292 }
292 } 293 }
293} 294}
294 295
295impl Substs { 296impl Substs {
297 pub fn interned(&self, _: &Interner) -> &[Ty] {
298 &self.0
299 }
300
296 pub fn empty() -> Substs { 301 pub fn empty() -> Substs {
297 Substs(Arc::new([])) 302 Substs(SmallVec::new())
298 } 303 }
299 304
300 pub fn single(ty: Ty) -> Substs { 305 pub fn single(ty: Ty) -> Substs {
301 Substs(Arc::new([ty])) 306 Substs({
307 let mut v = SmallVec::new();
308 v.push(ty);
309 v
310 })
302 } 311 }
303 312
304 pub fn prefix(&self, n: usize) -> Substs { 313 pub fn prefix(&self, n: usize) -> Substs {
@@ -316,6 +325,10 @@ impl Substs {
316 &self.0[0] 325 &self.0[0]
317 } 326 }
318 327
328 pub fn from_iter(_interner: &Interner, elements: impl IntoIterator<Item = Ty>) -> Self {
329 Substs(elements.into_iter().collect())
330 }
331
319 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). 332 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
320 pub(crate) fn type_params_for_generics( 333 pub(crate) fn type_params_for_generics(
321 db: &dyn HirDatabase, 334 db: &dyn HirDatabase,
@@ -600,13 +613,13 @@ impl CallableSig {
600 613
601 pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig { 614 pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
602 CallableSig { 615 CallableSig {
603 params_and_return: Arc::clone(&fn_ptr.substs.0), 616 params_and_return: fn_ptr.substs.interned(&Interner).iter().cloned().collect(),
604 is_varargs: fn_ptr.sig.variadic, 617 is_varargs: fn_ptr.sig.variadic,
605 } 618 }
606 } 619 }
607 620
608 pub fn from_substs(substs: &Substs) -> CallableSig { 621 pub fn from_substs(substs: &Substs) -> CallableSig {
609 CallableSig { params_and_return: Arc::clone(&substs.0), is_varargs: false } 622 CallableSig { params_and_return: substs.iter().cloned().collect(), is_varargs: false }
610 } 623 }
611 624
612 pub fn params(&self) -> &[Ty] { 625 pub fn params(&self) -> &[Ty] {
@@ -649,7 +662,7 @@ impl Ty {
649 TyKind::Function(FnPointer { 662 TyKind::Function(FnPointer {
650 num_args: sig.params().len(), 663 num_args: sig.params().len(),
651 sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs }, 664 sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs },
652 substs: Substs(sig.params_and_return), 665 substs: Substs::from_iter(&Interner, sig.params_and_return.iter().cloned()),
653 }) 666 })
654 .intern(&Interner) 667 .intern(&Interner)
655 } 668 }
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index b4c650fa1..6ab757bfc 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -31,7 +31,7 @@ use crate::{
31 traits::chalk::{Interner, ToChalk}, 31 traits::chalk::{Interner, ToChalk},
32 utils::{ 32 utils::{
33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, 33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
34 make_mut_slice, variant_data, 34 variant_data,
35 }, 35 },
36 AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, FnPointer, FnSig, GenericPredicate, 36 AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, FnPointer, FnSig, GenericPredicate,
37 ImplTraitId, OpaqueTy, PolyFnSig, ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, 37 ImplTraitId, OpaqueTy, PolyFnSig, ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait,
@@ -150,8 +150,9 @@ impl<'a> TyLoweringContext<'a> {
150 let ty = match type_ref { 150 let ty = match type_ref {
151 TypeRef::Never => TyKind::Never.intern(&Interner), 151 TypeRef::Never => TyKind::Never.intern(&Interner),
152 TypeRef::Tuple(inner) => { 152 TypeRef::Tuple(inner) => {
153 let inner_tys: Arc<[Ty]> = inner.iter().map(|tr| self.lower_ty(tr)).collect(); 153 let inner_tys = inner.iter().map(|tr| self.lower_ty(tr));
154 TyKind::Tuple(inner_tys.len(), Substs(inner_tys)).intern(&Interner) 154 TyKind::Tuple(inner_tys.len(), Substs::from_iter(&Interner, inner_tys))
155 .intern(&Interner)
155 } 156 }
156 TypeRef::Path(path) => { 157 TypeRef::Path(path) => {
157 let (ty, res_) = self.lower_path(path); 158 let (ty, res_) = self.lower_path(path);
@@ -638,7 +639,7 @@ impl<'a> TyLoweringContext<'a> {
638 ) -> TraitRef { 639 ) -> TraitRef {
639 let mut substs = self.trait_ref_substs_from_path(segment, resolved); 640 let mut substs = self.trait_ref_substs_from_path(segment, resolved);
640 if let Some(self_ty) = explicit_self_ty { 641 if let Some(self_ty) = explicit_self_ty {
641 make_mut_slice(&mut substs.0)[0] = self_ty; 642 substs.0[0] = self_ty;
642 } 643 }
643 TraitRef { trait_: resolved, substs } 644 TraitRef { trait_: resolved, substs }
644 } 645 }
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index fb3afaedc..af4f8bb11 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -216,6 +216,22 @@ fn expr_macro_expanded_in_various_places() {
216} 216}
217 217
218#[test] 218#[test]
219fn expr_macro_expanded_in_stmts() {
220 check_infer(
221 r#"
222 macro_rules! id { ($($es:tt)*) => { $($es)* } }
223 fn foo() {
224 id! { let a = (); }
225 }
226 "#,
227 expect![[r#"
228 !0..8 'leta=();': ()
229 57..84 '{ ...); } }': ()
230 "#]],
231 );
232}
233
234#[test]
219fn infer_type_value_macro_having_same_name() { 235fn infer_type_value_macro_having_same_name() {
220 check_infer( 236 check_infer(
221 r#" 237 r#"
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index e185b1c0a..93d3ad020 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() {
1699 1699
1700#[test] 1700#[test]
1701fn fn_trait() { 1701fn fn_trait() {
1702 check_infer( 1702 check_infer_with_mismatches(
1703 r#" 1703 r#"
1704 trait FnOnce<Args> { 1704 trait FnOnce<Args> {
1705 type Output; 1705 type Output;
@@ -1727,7 +1727,7 @@ fn fn_trait() {
1727 1727
1728#[test] 1728#[test]
1729fn fn_ptr_and_item() { 1729fn fn_ptr_and_item() {
1730 check_infer( 1730 check_infer_with_mismatches(
1731 r#" 1731 r#"
1732 #[lang="fn_once"] 1732 #[lang="fn_once"]
1733 trait FnOnce<Args> { 1733 trait FnOnce<Args> {
@@ -1743,12 +1743,12 @@ fn fn_ptr_and_item() {
1743 struct Bar<T>(T); 1743 struct Bar<T>(T);
1744 1744
1745 impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> { 1745 impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
1746 fn foo(&self) -> (A1, R) {} 1746 fn foo(&self) -> (A1, R) { loop {} }
1747 } 1747 }
1748 1748
1749 enum Opt<T> { None, Some(T) } 1749 enum Opt<T> { None, Some(T) }
1750 impl<T> Opt<T> { 1750 impl<T> Opt<T> {
1751 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> {} 1751 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> { loop {} }
1752 } 1752 }
1753 1753
1754 fn test() { 1754 fn test() {
@@ -1765,19 +1765,23 @@ fn fn_ptr_and_item() {
1765 80..84 'args': Args 1765 80..84 'args': Args
1766 139..143 'self': &Self 1766 139..143 'self': &Self
1767 243..247 'self': &Bar<F> 1767 243..247 'self': &Bar<F>
1768 260..262 '{}': () 1768 260..271 '{ loop {} }': (A1, R)
1769 346..350 'self': Opt<T> 1769 262..269 'loop {}': !
1770 352..353 'f': F 1770 267..269 '{}': ()
1771 368..370 '{}': () 1771 355..359 'self': Opt<T>
1772 384..500 '{ ...(f); }': () 1772 361..362 'f': F
1773 394..397 'bar': Bar<fn(u8) -> u32> 1773 377..388 '{ loop {} }': Opt<U>
1774 423..426 'bar': Bar<fn(u8) -> u32> 1774 379..386 'loop {}': !
1775 423..432 'bar.foo()': (u8, u32) 1775 384..386 '{}': ()
1776 443..446 'opt': Opt<u8> 1776 402..518 '{ ...(f); }': ()
1777 465..466 'f': fn(u8) -> u32 1777 412..415 'bar': Bar<fn(u8) -> u32>
1778 487..490 'opt': Opt<u8> 1778 441..444 'bar': Bar<fn(u8) -> u32>
1779 487..497 'opt.map(f)': Opt<u32> 1779 441..450 'bar.foo()': (u8, u32)
1780 495..496 'f': fn(u8) -> u32 1780 461..464 'opt': Opt<u8>
1781 483..484 'f': fn(u8) -> u32
1782 505..508 'opt': Opt<u8>
1783 505..515 'opt.map(f)': Opt<u32>
1784 513..514 'f': fn(u8) -> u32
1781 "#]], 1785 "#]],
1782 ); 1786 );
1783} 1787}
@@ -1859,7 +1863,7 @@ fn fn_trait_deref_with_ty_default() {
1859 1863
1860#[test] 1864#[test]
1861fn closure_1() { 1865fn closure_1() {
1862 check_infer( 1866 check_infer_with_mismatches(
1863 r#" 1867 r#"
1864 #[lang = "fn_once"] 1868 #[lang = "fn_once"]
1865 trait FnOnce<Args> { 1869 trait FnOnce<Args> {
@@ -1868,7 +1872,7 @@ fn closure_1() {
1868 1872
1869 enum Option<T> { Some(T), None } 1873 enum Option<T> { Some(T), None }
1870 impl<T> Option<T> { 1874 impl<T> Option<T> {
1871 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {} 1875 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} }
1872 } 1876 }
1873 1877
1874 fn test() { 1878 fn test() {
@@ -1881,37 +1885,39 @@ fn closure_1() {
1881 expect![[r#" 1885 expect![[r#"
1882 147..151 'self': Option<T> 1886 147..151 'self': Option<T>
1883 153..154 'f': F 1887 153..154 'f': F
1884 172..174 '{}': () 1888 172..183 '{ loop {} }': Option<U>
1885 188..307 '{ ... 1); }': () 1889 174..181 'loop {}': !
1886 198..199 'x': Option<u32> 1890 179..181 '{}': ()
1887 202..214 'Option::Some': Some<u32>(u32) -> Option<u32> 1891 197..316 '{ ... 1); }': ()
1888 202..220 'Option...(1u32)': Option<u32> 1892 207..208 'x': Option<u32>
1889 215..219 '1u32': u32 1893 211..223 'Option::Some': Some<u32>(u32) -> Option<u32>
1890 226..227 'x': Option<u32> 1894 211..229 'Option...(1u32)': Option<u32>
1891 226..242 'x.map(...v + 1)': Option<u32> 1895 224..228 '1u32': u32
1892 232..241 '|v| v + 1': |u32| -> u32 1896 235..236 'x': Option<u32>
1893 233..234 'v': u32 1897 235..251 'x.map(...v + 1)': Option<u32>
1894 236..237 'v': u32 1898 241..250 '|v| v + 1': |u32| -> u32
1895 236..241 'v + 1': u32 1899 242..243 'v': u32
1896 240..241 '1': u32 1900 245..246 'v': u32
1897 248..249 'x': Option<u32> 1901 245..250 'v + 1': u32
1898 248..264 'x.map(... 1u64)': Option<u64> 1902 249..250 '1': u32
1899 254..263 '|_v| 1u64': |u32| -> u64 1903 257..258 'x': Option<u32>
1900 255..257 '_v': u32 1904 257..273 'x.map(... 1u64)': Option<u64>
1901 259..263 '1u64': u64 1905 263..272 '|_v| 1u64': |u32| -> u64
1902 274..275 'y': Option<i64> 1906 264..266 '_v': u32
1903 291..292 'x': Option<u32> 1907 268..272 '1u64': u64
1904 291..304 'x.map(|_v| 1)': Option<i64> 1908 283..284 'y': Option<i64>
1905 297..303 '|_v| 1': |u32| -> i64 1909 300..301 'x': Option<u32>
1906 298..300 '_v': u32 1910 300..313 'x.map(|_v| 1)': Option<i64>
1907 302..303 '1': i64 1911 306..312 '|_v| 1': |u32| -> i64
1912 307..309 '_v': u32
1913 311..312 '1': i64
1908 "#]], 1914 "#]],
1909 ); 1915 );
1910} 1916}
1911 1917
1912#[test] 1918#[test]
1913fn closure_2() { 1919fn closure_2() {
1914 check_infer( 1920 check_infer_with_mismatches(
1915 r#" 1921 r#"
1916 trait FnOnce<Args> { 1922 trait FnOnce<Args> {
1917 type Output; 1923 type Output;
@@ -1951,22 +1957,22 @@ fn closure_2() {
1951 1957
1952#[test] 1958#[test]
1953fn closure_as_argument_inference_order() { 1959fn closure_as_argument_inference_order() {
1954 check_infer( 1960 check_infer_with_mismatches(
1955 r#" 1961 r#"
1956 #[lang = "fn_once"] 1962 #[lang = "fn_once"]
1957 trait FnOnce<Args> { 1963 trait FnOnce<Args> {
1958 type Output; 1964 type Output;
1959 } 1965 }
1960 1966
1961 fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {} 1967 fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} }
1962 fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {} 1968 fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} }
1963 1969
1964 struct S; 1970 struct S;
1965 impl S { 1971 impl S {
1966 fn method(self) -> u64; 1972 fn method(self) -> u64;
1967 1973
1968 fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {} 1974 fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U { loop {} }
1969 fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {} 1975 fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U { loop {} }
1970 } 1976 }
1971 1977
1972 fn test() { 1978 fn test() {
@@ -1979,52 +1985,60 @@ fn closure_as_argument_inference_order() {
1979 expect![[r#" 1985 expect![[r#"
1980 94..95 'x': T 1986 94..95 'x': T
1981 100..101 'f': F 1987 100..101 'f': F
1982 111..113 '{}': () 1988 111..122 '{ loop {} }': U
1983 147..148 'f': F 1989 113..120 'loop {}': !
1984 153..154 'x': T 1990 118..120 '{}': ()
1985 164..166 '{}': () 1991 156..157 'f': F
1986 201..205 'self': S 1992 162..163 'x': T
1987 253..257 'self': S 1993 173..184 '{ loop {} }': U
1988 259..260 'x': T 1994 175..182 'loop {}': !
1989 265..266 'f': F 1995 180..182 '{}': ()
1990 276..278 '{}': () 1996 219..223 'self': S
1991 316..320 'self': S 1997 271..275 'self': S
1992 322..323 'f': F 1998 277..278 'x': T
1993 328..329 'x': T 1999 283..284 'f': F
1994 339..341 '{}': () 2000 294..305 '{ loop {} }': U
1995 355..514 '{ ... S); }': () 2001 296..303 'loop {}': !
1996 365..367 'x1': u64 2002 301..303 '{}': ()
1997 370..374 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64 2003 343..347 'self': S
1998 370..393 'foo1(S...hod())': u64 2004 349..350 'f': F
1999 375..376 'S': S 2005 355..356 'x': T
2000 378..392 '|s| s.method()': |S| -> u64 2006 366..377 '{ loop {} }': U
2001 379..380 's': S 2007 368..375 'loop {}': !
2002 382..383 's': S 2008 373..375 '{}': ()
2003 382..392 's.method()': u64 2009 391..550 '{ ... S); }': ()
2004 403..405 'x2': u64 2010 401..403 'x1': u64
2005 408..412 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64 2011 406..410 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
2006 408..431 'foo2(|...(), S)': u64 2012 406..429 'foo1(S...hod())': u64
2007 413..427 '|s| s.method()': |S| -> u64 2013 411..412 'S': S
2008 414..415 's': S 2014 414..428 '|s| s.method()': |S| -> u64
2009 417..418 's': S 2015 415..416 's': S
2010 417..427 's.method()': u64 2016 418..419 's': S
2011 429..430 'S': S 2017 418..428 's.method()': u64
2012 441..443 'x3': u64 2018 439..441 'x2': u64
2013 446..447 'S': S 2019 444..448 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
2014 446..471 'S.foo1...hod())': u64 2020 444..467 'foo2(|...(), S)': u64
2015 453..454 'S': S 2021 449..463 '|s| s.method()': |S| -> u64
2016 456..470 '|s| s.method()': |S| -> u64 2022 450..451 's': S
2017 457..458 's': S 2023 453..454 's': S
2018 460..461 's': S 2024 453..463 's.method()': u64
2019 460..470 's.method()': u64 2025 465..466 'S': S
2020 481..483 'x4': u64 2026 477..479 'x3': u64
2021 486..487 'S': S 2027 482..483 'S': S
2022 486..511 'S.foo2...(), S)': u64 2028 482..507 'S.foo1...hod())': u64
2023 493..507 '|s| s.method()': |S| -> u64 2029 489..490 'S': S
2024 494..495 's': S 2030 492..506 '|s| s.method()': |S| -> u64
2025 497..498 's': S 2031 493..494 's': S
2026 497..507 's.method()': u64 2032 496..497 's': S
2027 509..510 'S': S 2033 496..506 's.method()': u64
2034 517..519 'x4': u64
2035 522..523 'S': S
2036 522..547 'S.foo2...(), S)': u64
2037 529..543 '|s| s.method()': |S| -> u64
2038 530..531 's': S
2039 533..534 's': S
2040 533..543 's.method()': u64
2041 545..546 'S': S
2028 "#]], 2042 "#]],
2029 ); 2043 );
2030} 2044}
@@ -2536,7 +2550,7 @@ fn test() {
2536 2550
2537#[test] 2551#[test]
2538fn iterator_chain() { 2552fn iterator_chain() {
2539 check_infer( 2553 check_infer_with_mismatches(
2540 r#" 2554 r#"
2541 //- /main.rs 2555 //- /main.rs
2542 #[lang = "fn_once"] 2556 #[lang = "fn_once"]
@@ -2939,7 +2953,7 @@ fn infer_closure_arg() {
2939 2953
2940#[test] 2954#[test]
2941fn infer_fn_trait_arg() { 2955fn infer_fn_trait_arg() {
2942 check_infer( 2956 check_infer_with_mismatches(
2943 r#" 2957 r#"
2944 //- /lib.rs deps:std 2958 //- /lib.rs deps:std
2945 2959
@@ -2986,7 +3000,8 @@ fn infer_fn_trait_arg() {
2986 3000
2987#[test] 3001#[test]
2988fn infer_box_fn_arg() { 3002fn infer_box_fn_arg() {
2989 check_infer( 3003 // The type mismatch is a bug
3004 check_infer_with_mismatches(
2990 r#" 3005 r#"
2991 //- /lib.rs deps:std 3006 //- /lib.rs deps:std
2992 3007
@@ -3025,7 +3040,7 @@ fn infer_box_fn_arg() {
3025 fn foo() { 3040 fn foo() {
3026 let s = Option::None; 3041 let s = Option::None;
3027 let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {}); 3042 let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
3028 f(&s) 3043 f(&s);
3029 } 3044 }
3030 "#, 3045 "#,
3031 expect![[r#" 3046 expect![[r#"
@@ -3037,7 +3052,7 @@ fn infer_box_fn_arg() {
3037 406..417 '&self.inner': &*mut T 3052 406..417 '&self.inner': &*mut T
3038 407..411 'self': &Box<T> 3053 407..411 'self': &Box<T>
3039 407..417 'self.inner': *mut T 3054 407..417 'self.inner': *mut T
3040 478..575 '{ ...(&s) }': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)> 3055 478..576 '{ ...&s); }': ()
3041 488..489 's': Option<i32> 3056 488..489 's': Option<i32>
3042 492..504 'Option::None': Option<i32> 3057 492..504 'Option::None': Option<i32>
3043 514..515 'f': Box<dyn FnOnce(&Option<i32>)> 3058 514..515 'f': Box<dyn FnOnce(&Option<i32>)>
@@ -3049,6 +3064,7 @@ fn infer_box_fn_arg() {
3049 568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)> 3064 568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)>
3050 570..572 '&s': &Option<i32> 3065 570..572 '&s': &Option<i32>
3051 571..572 's': Option<i32> 3066 571..572 's': Option<i32>
3067 549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|_| -> ()>
3052 "#]], 3068 "#]],
3053 ); 3069 );
3054} 3070}
diff --git a/crates/hir_ty/src/traits/chalk/interner.rs b/crates/hir_ty/src/traits/chalk/interner.rs
index 1dc3f497d..94e94a26d 100644
--- a/crates/hir_ty/src/traits/chalk/interner.rs
+++ b/crates/hir_ty/src/traits/chalk/interner.rs
@@ -5,6 +5,7 @@ use super::tls;
5use base_db::salsa::InternId; 5use base_db::salsa::InternId;
6use chalk_ir::{GenericArg, Goal, GoalData}; 6use chalk_ir::{GenericArg, Goal, GoalData};
7use hir_def::TypeAliasId; 7use hir_def::TypeAliasId;
8use smallvec::SmallVec;
8use std::{fmt, sync::Arc}; 9use std::{fmt, sync::Arc};
9 10
10#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] 11#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
@@ -33,7 +34,7 @@ impl chalk_ir::interner::Interner for Interner {
33 type InternedGenericArg = chalk_ir::GenericArgData<Self>; 34 type InternedGenericArg = chalk_ir::GenericArgData<Self>;
34 type InternedGoal = Arc<GoalData<Self>>; 35 type InternedGoal = Arc<GoalData<Self>>;
35 type InternedGoals = Vec<Goal<Self>>; 36 type InternedGoals = Vec<Goal<Self>>;
36 type InternedSubstitution = Vec<GenericArg<Self>>; 37 type InternedSubstitution = SmallVec<[GenericArg<Self>; 2]>;
37 type InternedProgramClause = Arc<chalk_ir::ProgramClauseData<Self>>; 38 type InternedProgramClause = Arc<chalk_ir::ProgramClauseData<Self>>;
38 type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>; 39 type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>;
39 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; 40 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
@@ -265,13 +266,13 @@ impl chalk_ir::interner::Interner for Interner {
265 fn intern_substitution<E>( 266 fn intern_substitution<E>(
266 &self, 267 &self,
267 data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>, 268 data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>,
268 ) -> Result<Vec<GenericArg<Self>>, E> { 269 ) -> Result<Self::InternedSubstitution, E> {
269 data.into_iter().collect() 270 data.into_iter().collect()
270 } 271 }
271 272
272 fn substitution_data<'a>( 273 fn substitution_data<'a>(
273 &self, 274 &self,
274 substitution: &'a Vec<GenericArg<Self>>, 275 substitution: &'a Self::InternedSubstitution,
275 ) -> &'a [GenericArg<Self>] { 276 ) -> &'a [GenericArg<Self>] {
276 substitution 277 substitution
277 } 278 }
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 aa7072f25..b8834d283 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 @@
1use hir::{known, HasSource, Name}; 1use hir::{known, HasSource, Name};
2use syntax::{ 2use syntax::{
3 ast::{self, NameOwner}, 3 ast::{self, NameOwner},
4 AstNode, TextRange, 4 AstNode,
5}; 5};
6 6
7use crate::{ 7use crate::{
@@ -51,12 +51,19 @@ pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext)
51 } 51 }
52 52
53 let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?; 53 let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?;
54 let len_fn = get_impl_method(ctx, &impl_, &known::len)?;
55 if !len_fn.ret_type(ctx.sema.db).is_usize() {
56 cov_mark::hit!(len_fn_different_return_type);
57 return None;
58 }
59
54 if get_impl_method(ctx, &impl_, &known::is_empty).is_some() { 60 if get_impl_method(ctx, &impl_, &known::is_empty).is_some() {
55 cov_mark::hit!(is_empty_already_implemented); 61 cov_mark::hit!(is_empty_already_implemented);
56 return None; 62 return None;
57 } 63 }
58 64
59 let range = get_text_range_of_len_function(ctx, &impl_)?; 65 let node = len_fn.source(ctx.sema.db)?;
66 let range = node.syntax().value.text_range();
60 67
61 acc.add( 68 acc.add(
62 AssistId("generate_is_empty_from_len", AssistKind::Generate), 69 AssistId("generate_is_empty_from_len", AssistKind::Generate),
@@ -89,13 +96,6 @@ fn get_impl_method(
89 ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func)) 96 ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func))
90} 97}
91 98
92fn get_text_range_of_len_function(ctx: &AssistContext, impl_: &ast::Impl) -> Option<TextRange> {
93 let db = ctx.sema.db;
94 let func = get_impl_method(ctx, impl_, &known::len)?;
95 let node = func.source(db)?;
96 Some(node.syntax().value.text_range())
97}
98
99#[cfg(test)] 99#[cfg(test)]
100mod tests { 100mod tests {
101 use crate::tests::{check_assist, check_assist_not_applicable}; 101 use crate::tests::{check_assist, check_assist_not_applicable};
@@ -158,6 +158,23 @@ impl MyStruct {
158 } 158 }
159 159
160 #[test] 160 #[test]
161 fn len_fn_different_return_type() {
162 cov_mark::check!(len_fn_different_return_type);
163 check_assist_not_applicable(
164 generate_is_empty_from_len,
165 r#"
166struct MyStruct { data: Vec<String> }
167
168impl MyStruct {
169 p$0ub fn len(&self) -> u32 {
170 self.data.len()
171 }
172}
173"#,
174 );
175 }
176
177 #[test]
161 fn generate_is_empty() { 178 fn generate_is_empty() {
162 check_assist( 179 check_assist(
163 generate_is_empty_from_len, 180 generate_is_empty_from_len,
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 2514dda7c..09a27de71 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -10,10 +10,8 @@ pub(crate) mod type_alias;
10 10
11mod builder_ext; 11mod builder_ext;
12 12
13use base_db::Upcast;
14use hir::{ 13use hir::{
15 db::HirDatabase, AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, 14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type,
16 ScopeDef, Type,
17}; 15};
18use ide_db::{ 16use ide_db::{
19 helpers::{item_name, SnippetCap}, 17 helpers::{item_name, SnippetCap},
@@ -22,8 +20,8 @@ use ide_db::{
22use syntax::TextRange; 20use syntax::TextRange;
23 21
24use crate::{ 22use crate::{
25 item::{CompletionRelevance, ImportEdit}, 23 item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
26 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, 24 CompletionRelevance,
27}; 25};
28 26
29use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; 27use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro};
@@ -144,7 +142,15 @@ impl<'a> Render<'a> {
144 .set_documentation(field.docs(self.ctx.db())) 142 .set_documentation(field.docs(self.ctx.db()))
145 .set_deprecated(is_deprecated); 143 .set_deprecated(is_deprecated);
146 144
147 item.set_relevance(compute_relevance(&self.ctx, &ty, &name.to_string())); 145 item.set_relevance(CompletionRelevance {
146 exact_type_match: compute_exact_type_match(self.ctx.completion, ty),
147 exact_name_match: compute_exact_name_match(self.ctx.completion, name.to_string()),
148 ..CompletionRelevance::default()
149 });
150
151 if let Some(ref_match) = compute_ref_match(self.ctx.completion, ty) {
152 item.ref_match(ref_match);
153 }
148 154
149 item.build() 155 item.build()
150 } 156 }
@@ -234,31 +240,18 @@ impl<'a> Render<'a> {
234 if !ty.is_unknown() { 240 if !ty.is_unknown() {
235 item.detail(ty.display(self.ctx.db()).to_string()); 241 item.detail(ty.display(self.ctx.db()).to_string());
236 } 242 }
237 };
238 243
239 if let ScopeDef::Local(local) = resolution { 244 item.set_relevance(CompletionRelevance {
240 let ty = local.ty(self.ctx.db()); 245 exact_type_match: compute_exact_type_match(self.ctx.completion, &ty),
246 exact_name_match: compute_exact_name_match(self.ctx.completion, local_name.clone()),
247 is_local: true,
248 ..CompletionRelevance::default()
249 });
241 250
242 let mut relevance = compute_relevance(&self.ctx, &ty, &local_name); 251 if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ty) {
243 relevance.is_local = true; 252 item.ref_match(ref_match);
244 item.set_relevance(relevance);
245
246 if let Some(expected_type) = self.ctx.completion.expected_type.as_ref() {
247 if &ty != expected_type {
248 if let Some(ty_without_ref) = expected_type.remove_ref() {
249 if relevance_type_match(self.ctx.db().upcast(), &ty, &ty_without_ref) {
250 cov_mark::hit!(suggest_ref);
251 let mutability = if expected_type.is_mutable_reference() {
252 Mutability::Mut
253 } else {
254 Mutability::Shared
255 };
256 item.ref_match(mutability);
257 }
258 }
259 }
260 } 253 }
261 } 254 };
262 255
263 // Add `<>` for generic types 256 // Add `<>` for generic types
264 if self.ctx.completion.is_path_type 257 if self.ctx.completion.is_path_type
@@ -313,17 +306,44 @@ impl<'a> Render<'a> {
313 } 306 }
314} 307}
315 308
316fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> CompletionRelevance { 309fn compute_exact_type_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> bool {
317 let mut res = CompletionRelevance::default(); 310 if let Some(expected_type) = ctx.expected_type.as_ref() {
311 // We don't ever consider unit type to be an exact type match, since
312 // nearly always this is not meaningful to the user.
313 completion_ty == expected_type && !expected_type.is_unit()
314 } else {
315 false
316 }
317}
318 318
319 res.exact_type_match = Some(ty) == ctx.completion.expected_type.as_ref(); 319fn compute_exact_name_match(ctx: &CompletionContext, completion_name: impl Into<String>) -> bool {
320 res.exact_name_match = Some(name) == ctx.completion.expected_name.as_deref(); 320 let completion_name = completion_name.into();
321 321
322 res 322 Some(&completion_name) == ctx.expected_name.as_ref()
323} 323}
324 324
325fn relevance_type_match(db: &dyn HirDatabase, ty: &Type, expected_type: &Type) -> bool { 325fn compute_ref_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> Option<Mutability> {
326 ty == expected_type || ty.autoderef(db).any(|deref_ty| &deref_ty == expected_type) 326 let mut ref_match = None;
327 if let Some(expected_type) = &ctx.expected_type {
328 if completion_ty != expected_type {
329 if let Some(expected_type_without_ref) = expected_type.remove_ref() {
330 if completion_ty == &expected_type_without_ref
331 || completion_ty
332 .autoderef(ctx.db)
333 .any(|deref_ty| deref_ty == expected_type_without_ref)
334 {
335 cov_mark::hit!(suggest_ref);
336 let mutability = if expected_type.is_mutable_reference() {
337 Mutability::Mut
338 } else {
339 Mutability::Shared
340 };
341 ref_match = Some(mutability);
342 }
343 }
344 }
345 };
346 ref_match
327} 347}
328 348
329#[cfg(test)] 349#[cfg(test)]
@@ -477,6 +497,11 @@ fn main() { let _: m::Spam = S$0 }
477 ), 497 ),
478 lookup: "Spam::Bar", 498 lookup: "Spam::Bar",
479 detail: "(i32)", 499 detail: "(i32)",
500 relevance: CompletionRelevance {
501 exact_name_match: false,
502 exact_type_match: true,
503 is_local: false,
504 },
480 trigger_call_info: true, 505 trigger_call_info: true,
481 }, 506 },
482 CompletionItem { 507 CompletionItem {
@@ -498,6 +523,11 @@ fn main() { let _: m::Spam = S$0 }
498 ), 523 ),
499 lookup: "Spam::Foo", 524 lookup: "Spam::Foo",
500 detail: "()", 525 detail: "()",
526 relevance: CompletionRelevance {
527 exact_name_match: false,
528 exact_type_match: true,
529 is_local: false,
530 },
501 }, 531 },
502 CompletionItem { 532 CompletionItem {
503 label: "main()", 533 label: "main()",
@@ -1169,4 +1199,86 @@ fn foo(bar: u32) {
1169 "#]], 1199 "#]],
1170 ); 1200 );
1171 } 1201 }
1202
1203 #[test]
1204 fn enum_owned() {
1205 check_relevance(
1206 r#"
1207enum Foo { A, B }
1208fn foo() {
1209 bar($0);
1210}
1211fn bar(t: Foo) {}
1212"#,
1213 expect![[r#"
1214 ev Foo::A [type]
1215 ev Foo::B [type]
1216 en Foo []
1217 fn bar(…) []
1218 fn foo() []
1219 "#]],
1220 );
1221 }
1222
1223 #[test]
1224 fn enum_ref() {
1225 check_relevance(
1226 r#"
1227enum Foo { A, B }
1228fn foo() {
1229 bar($0);
1230}
1231fn bar(t: &Foo) {}
1232"#,
1233 expect![[r#"
1234 ev Foo::A []
1235 ev &Foo::A [type]
1236 ev Foo::B []
1237 ev &Foo::B [type]
1238 en Foo []
1239 fn bar(…) []
1240 fn foo() []
1241 "#]],
1242 );
1243 }
1244
1245 #[test]
1246 fn suggest_deref_fn_ret() {
1247 check_relevance(
1248 r#"
1249#[lang = "deref"]
1250trait Deref {
1251 type Target;
1252 fn deref(&self) -> &Self::Target;
1253}
1254
1255struct S;
1256struct T(S);
1257
1258impl Deref for T {
1259 type Target = S;
1260
1261 fn deref(&self) -> &Self::Target {
1262 &self.0
1263 }
1264}
1265
1266fn foo(s: &S) {}
1267fn bar() -> T {}
1268
1269fn main() {
1270 foo($0);
1271}
1272 "#,
1273 expect![[r#"
1274 tt Deref []
1275 fn bar() []
1276 fn &bar() [type]
1277 fn foo(…) []
1278 st T []
1279 st S []
1280 fn main() []
1281 "#]],
1282 )
1283 }
1172} 1284}
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs
index e8cfcc0c7..374247b05 100644
--- a/crates/ide_completion/src/render/enum_variant.rs
+++ b/crates/ide_completion/src/render/enum_variant.rs
@@ -6,7 +6,8 @@ use itertools::Itertools;
6 6
7use crate::{ 7use crate::{
8 item::{CompletionItem, CompletionKind, ImportEdit}, 8 item::{CompletionItem, CompletionKind, ImportEdit},
9 render::{builder_ext::Params, RenderContext}, 9 render::{builder_ext::Params, compute_exact_type_match, compute_ref_match, RenderContext},
10 CompletionRelevance,
10}; 11};
11 12
12pub(crate) fn render_variant<'a>( 13pub(crate) fn render_variant<'a>(
@@ -74,6 +75,16 @@ impl<'a> EnumRender<'a> {
74 item.lookup_by(self.short_qualified_name); 75 item.lookup_by(self.short_qualified_name);
75 } 76 }
76 77
78 let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db);
79 item.set_relevance(CompletionRelevance {
80 exact_type_match: compute_exact_type_match(self.ctx.completion, &ty),
81 ..CompletionRelevance::default()
82 });
83
84 if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ty) {
85 item.ref_match(ref_match);
86 }
87
77 item.build() 88 item.build()
78 } 89 }
79 90
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 47e26a5d8..194ea135e 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -6,7 +6,10 @@ use syntax::ast::Fn;
6 6
7use crate::{ 7use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit}, 8 item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit},
9 render::{builder_ext::Params, RenderContext}, 9 render::{
10 builder_ext::Params, compute_exact_name_match, compute_exact_type_match, compute_ref_match,
11 RenderContext,
12 },
10}; 13};
11 14
12pub(crate) fn render_fn<'a>( 15pub(crate) fn render_fn<'a>(
@@ -52,23 +55,19 @@ impl<'a> FunctionRender<'a> {
52 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), 55 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
53 ) 56 )
54 .detail(self.detail()) 57 .detail(self.detail())
55 .add_call_parens(self.ctx.completion, self.name, params) 58 .add_call_parens(self.ctx.completion, self.name.clone(), params)
56 .add_import(import_to_add); 59 .add_import(import_to_add);
57 60
58 let mut relevance = CompletionRelevance::default(); 61 let ret_type = self.func.ret_type(self.ctx.db());
59 if let Some(expected_type) = &self.ctx.completion.expected_type { 62 item.set_relevance(CompletionRelevance {
60 let ret_ty = self.func.ret_type(self.ctx.db()); 63 exact_type_match: compute_exact_type_match(self.ctx.completion, &ret_type),
64 exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()),
65 ..CompletionRelevance::default()
66 });
61 67
62 // We don't ever consider a function which returns unit type to be an 68 if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ret_type) {
63 // exact type match, since nearly always this is not meaningful to the 69 item.ref_match(ref_match);
64 // user.
65 relevance.exact_type_match = &ret_ty == expected_type && !ret_ty.is_unit();
66 } 70 }
67 if let Some(expected_name) = &self.ctx.completion.expected_name {
68 relevance.exact_name_match =
69 expected_name == &self.func.name(self.ctx.db()).to_string();
70 }
71 item.set_relevance(relevance);
72 71
73 item.build() 72 item.build()
74 } 73 }
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 3a168bb4b..eca0bcc18 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -662,12 +662,11 @@ fn test_tt_to_stmts() {
662 [email protected] 662 [email protected]
663 [email protected] "1" 663 [email protected] "1"
664 [email protected] ";" 664 [email protected] ";"
665 [email protected] 665 [email protected]
666 [email protected] 666 [email protected]
667 [email protected] 667 [email protected]
668 [email protected] 668 [email protected]
669 [email protected] 669 [email protected] "a""#,
670 [email protected] "a""#,
671 ); 670 );
672} 671}
673 672
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 6c0e22722..cebb8f400 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -63,11 +63,11 @@ pub(crate) mod fragments {
63 } 63 }
64 64
65 pub(crate) fn stmt(p: &mut Parser) { 65 pub(crate) fn stmt(p: &mut Parser) {
66 expressions::stmt(p, expressions::StmtWithSemi::No) 66 expressions::stmt(p, expressions::StmtWithSemi::No, true)
67 } 67 }
68 68
69 pub(crate) fn stmt_optional_semi(p: &mut Parser) { 69 pub(crate) fn stmt_optional_semi(p: &mut Parser) {
70 expressions::stmt(p, expressions::StmtWithSemi::Optional) 70 expressions::stmt(p, expressions::StmtWithSemi::Optional, false)
71 } 71 }
72 72
73 pub(crate) fn opt_visibility(p: &mut Parser) { 73 pub(crate) fn opt_visibility(p: &mut Parser) {
@@ -133,7 +133,7 @@ pub(crate) mod fragments {
133 continue; 133 continue;
134 } 134 }
135 135
136 expressions::stmt(p, expressions::StmtWithSemi::Optional); 136 expressions::stmt(p, expressions::StmtWithSemi::Optional, true);
137 } 137 }
138 138
139 m.complete(p, MACRO_STMTS); 139 m.complete(p, MACRO_STMTS);
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 5f885edfd..0d9dc9348 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 {
54 !forbid 54 !forbid
55} 55}
56 56
57pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { 57pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
58 let m = p.start(); 58 let m = p.start();
59 // test attr_on_expr_stmt 59 // test attr_on_expr_stmt
60 // fn foo() { 60 // fn foo() {
@@ -90,7 +90,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
90 p.error(format!("attributes are not allowed on {:?}", kind)); 90 p.error(format!("attributes are not allowed on {:?}", kind));
91 } 91 }
92 92
93 if p.at(T!['}']) { 93 if p.at(T!['}']) || (prefer_expr && p.at(EOF)) {
94 // test attr_on_last_expr_in_block 94 // test attr_on_last_expr_in_block
95 // fn foo() { 95 // fn foo() {
96 // { #[A] bar!()? } 96 // { #[A] bar!()? }
@@ -198,7 +198,7 @@ pub(super) fn expr_block_contents(p: &mut Parser) {
198 continue; 198 continue;
199 } 199 }
200 200
201 stmt(p, StmtWithSemi::Yes) 201 stmt(p, StmtWithSemi::Yes, false)
202 } 202 }
203} 203}
204 204
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 064931aec..6097178b6 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1336,6 +1336,7 @@ pub enum Expr {
1336 Literal(Literal), 1336 Literal(Literal),
1337 LoopExpr(LoopExpr), 1337 LoopExpr(LoopExpr),
1338 MacroCall(MacroCall), 1338 MacroCall(MacroCall),
1339 MacroStmts(MacroStmts),
1339 MatchExpr(MatchExpr), 1340 MatchExpr(MatchExpr),
1340 MethodCallExpr(MethodCallExpr), 1341 MethodCallExpr(MethodCallExpr),
1341 ParenExpr(ParenExpr), 1342 ParenExpr(ParenExpr),
@@ -3034,6 +3035,9 @@ impl From<LoopExpr> for Expr {
3034impl From<MacroCall> for Expr { 3035impl From<MacroCall> for Expr {
3035 fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) } 3036 fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) }
3036} 3037}
3038impl From<MacroStmts> for Expr {
3039 fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
3040}
3037impl From<MatchExpr> for Expr { 3041impl From<MatchExpr> for Expr {
3038 fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) } 3042 fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
3039} 3043}
@@ -3078,8 +3082,8 @@ impl AstNode for Expr {
3078 match kind { 3082 match kind {
3079 ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR 3083 ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
3080 | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR 3084 | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR
3081 | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MATCH_EXPR 3085 | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS
3082 | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR 3086 | MATCH_EXPR | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
3083 | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR 3087 | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
3084 | YIELD_EXPR => true, 3088 | YIELD_EXPR => true,
3085 _ => false, 3089 _ => false,
@@ -3105,6 +3109,7 @@ impl AstNode for Expr {
3105 LITERAL => Expr::Literal(Literal { syntax }), 3109 LITERAL => Expr::Literal(Literal { syntax }),
3106 LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }), 3110 LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
3107 MACRO_CALL => Expr::MacroCall(MacroCall { syntax }), 3111 MACRO_CALL => Expr::MacroCall(MacroCall { syntax }),
3112 MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
3108 MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }), 3113 MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
3109 METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }), 3114 METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
3110 PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }), 3115 PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
@@ -3142,6 +3147,7 @@ impl AstNode for Expr {
3142 Expr::Literal(it) => &it.syntax, 3147 Expr::Literal(it) => &it.syntax,
3143 Expr::LoopExpr(it) => &it.syntax, 3148 Expr::LoopExpr(it) => &it.syntax,
3144 Expr::MacroCall(it) => &it.syntax, 3149 Expr::MacroCall(it) => &it.syntax,
3150 Expr::MacroStmts(it) => &it.syntax,
3145 Expr::MatchExpr(it) => &it.syntax, 3151 Expr::MatchExpr(it) => &it.syntax,
3146 Expr::MethodCallExpr(it) => &it.syntax, 3152 Expr::MethodCallExpr(it) => &it.syntax,
3147 Expr::ParenExpr(it) => &it.syntax, 3153 Expr::ParenExpr(it) => &it.syntax,
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index e084f0df6..ad93fbe3b 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -11,7 +11,7 @@ anyhow = "1.0.26"
11flate2 = "1.0" 11flate2 = "1.0"
12proc-macro2 = "1.0.8" 12proc-macro2 = "1.0.8"
13quote = "1.0.2" 13quote = "1.0.2"
14ungrammar = "=1.11" 14ungrammar = "=1.12"
15walkdir = "2.3.1" 15walkdir = "2.3.1"
16write-json = "0.1.0" 16write-json = "0.1.0"
17xshell = "0.1" 17xshell = "0.1"