diff options
Diffstat (limited to 'crates')
35 files changed, 1155 insertions, 475 deletions
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index d4ea7327e..55e9c3f0c 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml | |||
@@ -15,6 +15,7 @@ rustc-hash = "1.1.0" | |||
15 | either = "1.5.3" | 15 | either = "1.5.3" |
16 | arrayvec = "0.5.1" | 16 | arrayvec = "0.5.1" |
17 | itertools = "0.10.0" | 17 | itertools = "0.10.0" |
18 | smallvec = "1.4.0" | ||
18 | 19 | ||
19 | stdx = { path = "../stdx", version = "0.0.0" } | 20 | stdx = { path = "../stdx", version = "0.0.0" } |
20 | syntax = { path = "../syntax", version = "0.0.0" } | 21 | syntax = { path = "../syntax", version = "0.0.0" } |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 98135602a..f0bc2c7b9 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -53,6 +53,7 @@ use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; | |||
53 | use hir_ty::{ | 53 | use hir_ty::{ |
54 | autoderef, | 54 | autoderef, |
55 | method_resolution::{self, TyFingerprint}, | 55 | method_resolution::{self, TyFingerprint}, |
56 | primitive::UintTy, | ||
56 | to_assoc_type_id, | 57 | to_assoc_type_id, |
57 | traits::{FnTrait, Solution, SolutionVariables}, | 58 | traits::{FnTrait, Solution, SolutionVariables}, |
58 | AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, | 59 | AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, |
@@ -953,6 +954,14 @@ impl SelfParam { | |||
953 | }) | 954 | }) |
954 | .unwrap_or(Access::Owned) | 955 | .unwrap_or(Access::Owned) |
955 | } | 956 | } |
957 | |||
958 | pub fn display(self, db: &dyn HirDatabase) -> &'static str { | ||
959 | match self.access(db) { | ||
960 | Access::Shared => "&self", | ||
961 | Access::Exclusive => "&mut self", | ||
962 | Access::Owned => "self", | ||
963 | } | ||
964 | } | ||
956 | } | 965 | } |
957 | 966 | ||
958 | impl HasVisibility for Function { | 967 | impl HasVisibility for Function { |
@@ -1666,6 +1675,10 @@ impl Type { | |||
1666 | matches!(self.ty.value.interned(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..)) | 1675 | matches!(self.ty.value.interned(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..)) |
1667 | } | 1676 | } |
1668 | 1677 | ||
1678 | pub fn is_usize(&self) -> bool { | ||
1679 | matches!(self.ty.value.interned(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize))) | ||
1680 | } | ||
1681 | |||
1669 | pub fn remove_ref(&self) -> Option<Type> { | 1682 | pub fn remove_ref(&self) -> Option<Type> { |
1670 | match &self.ty.value.interned(&Interner) { | 1683 | match &self.ty.value.interned(&Interner) { |
1671 | TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), | 1684 | TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 945638cc5..519339c0c 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -259,6 +259,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
259 | } | 259 | } |
260 | 260 | ||
261 | pub fn to_module_def(&self, file: FileId) -> Option<Module> { | 261 | pub fn to_module_def(&self, file: FileId) -> Option<Module> { |
262 | self.imp.to_module_def(file).next() | ||
263 | } | ||
264 | |||
265 | pub fn to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> { | ||
262 | self.imp.to_module_def(file) | 266 | self.imp.to_module_def(file) |
263 | } | 267 | } |
264 | 268 | ||
@@ -537,8 +541,8 @@ impl<'db> SemanticsImpl<'db> { | |||
537 | f(&mut ctx) | 541 | f(&mut ctx) |
538 | } | 542 | } |
539 | 543 | ||
540 | fn to_module_def(&self, file: FileId) -> Option<Module> { | 544 | fn to_module_def(&self, file: FileId) -> impl Iterator<Item = Module> { |
541 | self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from) | 545 | self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from) |
542 | } | 546 | } |
543 | 547 | ||
544 | fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { | 548 | fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 6c612ee86..e9d820140 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -12,6 +12,7 @@ use hir_def::{ | |||
12 | }; | 12 | }; |
13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; | 13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; |
14 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
15 | use smallvec::SmallVec; | ||
15 | use stdx::impl_from; | 16 | use stdx::impl_from; |
16 | use syntax::{ | 17 | use syntax::{ |
17 | ast::{self, NameOwner}, | 18 | ast::{self, NameOwner}, |
@@ -28,14 +29,19 @@ pub(super) struct SourceToDefCtx<'a, 'b> { | |||
28 | } | 29 | } |
29 | 30 | ||
30 | impl SourceToDefCtx<'_, '_> { | 31 | impl SourceToDefCtx<'_, '_> { |
31 | pub(super) fn file_to_def(&mut self, file: FileId) -> Option<ModuleId> { | 32 | pub(super) fn file_to_def(&mut self, file: FileId) -> SmallVec<[ModuleId; 1]> { |
32 | let _p = profile::span("SourceBinder::to_module_def"); | 33 | let _p = profile::span("SourceBinder::to_module_def"); |
33 | self.db.relevant_crates(file).iter().find_map(|&crate_id| { | 34 | let mut mods = SmallVec::new(); |
35 | for &crate_id in self.db.relevant_crates(file).iter() { | ||
34 | // FIXME: inner items | 36 | // FIXME: inner items |
35 | let crate_def_map = self.db.crate_def_map(crate_id); | 37 | let crate_def_map = self.db.crate_def_map(crate_id); |
36 | let local_id = crate_def_map.modules_for_file(file).next()?; | 38 | mods.extend( |
37 | Some(crate_def_map.module_id(local_id)) | 39 | crate_def_map |
38 | }) | 40 | .modules_for_file(file) |
41 | .map(|local_id| crate_def_map.module_id(local_id)), | ||
42 | ) | ||
43 | } | ||
44 | mods | ||
39 | } | 45 | } |
40 | 46 | ||
41 | pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> { | 47 | pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> { |
@@ -55,7 +61,7 @@ impl SourceToDefCtx<'_, '_> { | |||
55 | Some(parent_declaration) => self.module_to_def(parent_declaration), | 61 | Some(parent_declaration) => self.module_to_def(parent_declaration), |
56 | None => { | 62 | None => { |
57 | let file_id = src.file_id.original_file(self.db.upcast()); | 63 | let file_id = src.file_id.original_file(self.db.upcast()); |
58 | self.file_to_def(file_id) | 64 | self.file_to_def(file_id).get(0).copied() |
59 | } | 65 | } |
60 | }?; | 66 | }?; |
61 | 67 | ||
@@ -185,7 +191,7 @@ impl SourceToDefCtx<'_, '_> { | |||
185 | ) -> Option<MacroDefId> { | 191 | ) -> Option<MacroDefId> { |
186 | let kind = MacroDefKind::Declarative; | 192 | let kind = MacroDefKind::Declarative; |
187 | let file_id = src.file_id.original_file(self.db.upcast()); | 193 | let file_id = src.file_id.original_file(self.db.upcast()); |
188 | let krate = self.file_to_def(file_id)?.krate(); | 194 | let krate = self.file_to_def(file_id).get(0).copied()?.krate(); |
189 | let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); | 195 | let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); |
190 | let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast())); | 196 | let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast())); |
191 | Some(MacroDefId { krate, ast_id, kind, local_inner: false }) | 197 | Some(MacroDefId { krate, ast_id, kind, local_inner: false }) |
@@ -245,7 +251,7 @@ impl SourceToDefCtx<'_, '_> { | |||
245 | return Some(res); | 251 | return Some(res); |
246 | } | 252 | } |
247 | 253 | ||
248 | let def = self.file_to_def(src.file_id.original_file(self.db.upcast()))?; | 254 | let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?; |
249 | Some(def.into()) | 255 | Some(def.into()) |
250 | } | 256 | } |
251 | 257 | ||
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)] |
103 | pub struct UnresolvedMacroCall { | 103 | pub struct UnresolvedMacroCall { |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index d63ac3df3..7bb22c4c4 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 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use 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] | ||
160 | fn 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] | ||
174 | fn 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] | ||
191 | fn 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_expand/src/name.rs b/crates/hir_expand/src/name.rs index e833e032c..43de9edd6 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -191,6 +191,8 @@ pub mod known { | |||
191 | filter_map, | 191 | filter_map, |
192 | next, | 192 | next, |
193 | iter_mut, | 193 | iter_mut, |
194 | len, | ||
195 | is_empty, | ||
194 | // Builtin macros | 196 | // Builtin macros |
195 | file, | 197 | file, |
196 | column, | 198 | column, |
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 | }; |
33 | use itertools::Itertools; | 33 | use itertools::Itertools; |
34 | use smallvec::SmallVec; | ||
34 | 35 | ||
35 | use crate::{ | 36 | use 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)] |
275 | pub struct Substs(Arc<[Ty]>); | 276 | pub struct Substs(SmallVec<[Ty; 2]>); |
276 | 277 | ||
277 | impl TypeWalk for Substs { | 278 | impl 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 | ||
295 | impl Substs { | 296 | impl 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] |
219 | fn 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] | ||
219 | fn infer_type_value_macro_having_same_name() { | 235 | fn 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] |
1701 | fn fn_trait() { | 1701 | fn 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] |
1729 | fn fn_ptr_and_item() { | 1729 | fn 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] |
1861 | fn closure_1() { | 1865 | fn 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] |
1913 | fn closure_2() { | 1919 | fn 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] |
1953 | fn closure_as_argument_inference_order() { | 1959 | fn 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] |
2538 | fn iterator_chain() { | 2552 | fn 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] |
2941 | fn infer_fn_trait_arg() { | 2955 | fn 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] |
2988 | fn infer_box_fn_arg() { | 3002 | fn 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; | |||
5 | use base_db::salsa::InternId; | 5 | use base_db::salsa::InternId; |
6 | use chalk_ir::{GenericArg, Goal, GoalData}; | 6 | use chalk_ir::{GenericArg, Goal, GoalData}; |
7 | use hir_def::TypeAliasId; | 7 | use hir_def::TypeAliasId; |
8 | use smallvec::SmallVec; | ||
8 | use std::{fmt, sync::Arc}; | 9 | use 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/src/parent_module.rs b/crates/ide/src/parent_module.rs index 03d71b380..22b0d6ecb 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | use hir::Semantics; | 1 | use hir::Semantics; |
2 | use ide_db::base_db::{CrateId, FileId, FilePosition}; | 2 | use ide_db::base_db::{CrateId, FileId, FilePosition}; |
3 | use ide_db::RootDatabase; | 3 | use ide_db::RootDatabase; |
4 | use itertools::Itertools; | ||
4 | use syntax::{ | 5 | use syntax::{ |
5 | algo::find_node_at_offset, | 6 | algo::find_node_at_offset, |
6 | ast::{self, AstNode}, | 7 | ast::{self, AstNode}, |
@@ -18,8 +19,7 @@ use crate::NavigationTarget; | |||
18 | // | VS Code | **Rust Analyzer: Locate parent module** | 19 | // | VS Code | **Rust Analyzer: Locate parent module** |
19 | // |=== | 20 | // |=== |
20 | 21 | ||
21 | /// This returns `Vec` because a module may be included from several places. We | 22 | /// This returns `Vec` because a module may be included from several places. |
22 | /// don't handle this case yet though, so the Vec has length at most one. | ||
23 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { | 23 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { |
24 | let sema = Semantics::new(db); | 24 | let sema = Semantics::new(db); |
25 | let source_file = sema.parse(position.file_id); | 25 | let source_file = sema.parse(position.file_id); |
@@ -37,27 +37,23 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na | |||
37 | } | 37 | } |
38 | } | 38 | } |
39 | 39 | ||
40 | let module = match module { | 40 | match module { |
41 | Some(module) => sema.to_def(&module), | 41 | Some(module) => sema |
42 | None => sema.to_module_def(position.file_id), | 42 | .to_def(&module) |
43 | }; | 43 | .into_iter() |
44 | let module = match module { | 44 | .map(|module| NavigationTarget::from_module_to_decl(db, module)) |
45 | None => return Vec::new(), | 45 | .collect(), |
46 | Some(it) => it, | 46 | None => sema |
47 | }; | 47 | .to_module_defs(position.file_id) |
48 | let nav = NavigationTarget::from_module_to_decl(db, module); | 48 | .map(|module| NavigationTarget::from_module_to_decl(db, module)) |
49 | vec![nav] | 49 | .collect(), |
50 | } | ||
50 | } | 51 | } |
51 | 52 | ||
52 | /// Returns `Vec` for the same reason as `parent_module` | 53 | /// Returns `Vec` for the same reason as `parent_module` |
53 | pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> { | 54 | pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> { |
54 | let sema = Semantics::new(db); | 55 | let sema = Semantics::new(db); |
55 | let module = match sema.to_module_def(file_id) { | 56 | sema.to_module_defs(file_id).map(|module| module.krate().into()).unique().collect() |
56 | Some(it) => it, | ||
57 | None => return Vec::new(), | ||
58 | }; | ||
59 | let krate = module.krate(); | ||
60 | vec![krate.into()] | ||
61 | } | 57 | } |
62 | 58 | ||
63 | #[cfg(test)] | 59 | #[cfg(test)] |
@@ -67,11 +63,13 @@ mod tests { | |||
67 | use crate::fixture; | 63 | use crate::fixture; |
68 | 64 | ||
69 | fn check(ra_fixture: &str) { | 65 | fn check(ra_fixture: &str) { |
70 | let (analysis, position, expected) = fixture::nav_target_annotation(ra_fixture); | 66 | let (analysis, position, expected) = fixture::annotations(ra_fixture); |
71 | let mut navs = analysis.parent_module(position).unwrap(); | 67 | let navs = analysis.parent_module(position).unwrap(); |
72 | assert_eq!(navs.len(), 1); | 68 | let navs = navs |
73 | let nav = navs.pop().unwrap(); | 69 | .iter() |
74 | assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }); | 70 | .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) |
71 | .collect::<Vec<_>>(); | ||
72 | assert_eq!(expected.into_iter().map(|(fr, _)| fr).collect::<Vec<_>>(), navs); | ||
75 | } | 73 | } |
76 | 74 | ||
77 | #[test] | 75 | #[test] |
@@ -120,15 +118,46 @@ mod foo { | |||
120 | } | 118 | } |
121 | 119 | ||
122 | #[test] | 120 | #[test] |
123 | fn test_resolve_crate_root() { | 121 | fn test_resolve_multi_parent_module() { |
124 | let (analysis, file_id) = fixture::file( | 122 | check( |
125 | r#" | 123 | r#" |
126 | //- /main.rs | 124 | //- /main.rs |
127 | mod foo; | 125 | mod foo; |
126 | //^^^ | ||
127 | #[path = "foo.rs"] | ||
128 | mod bar; | ||
129 | //^^^ | ||
130 | //- /foo.rs | ||
131 | $0 | ||
132 | "#, | ||
133 | ); | ||
134 | } | ||
135 | |||
136 | #[test] | ||
137 | fn test_resolve_crate_root() { | ||
138 | let (analysis, file_id) = fixture::file( | ||
139 | r#" | ||
128 | //- /foo.rs | 140 | //- /foo.rs |
129 | $0 | 141 | $0 |
142 | //- /main.rs | ||
143 | mod foo; | ||
130 | "#, | 144 | "#, |
131 | ); | 145 | ); |
132 | assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1); | 146 | assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1); |
133 | } | 147 | } |
148 | |||
149 | #[test] | ||
150 | fn test_resolve_multi_parent_crate() { | ||
151 | let (analysis, file_id) = fixture::file( | ||
152 | r#" | ||
153 | //- /baz.rs | ||
154 | $0 | ||
155 | //- /foo.rs crate:foo | ||
156 | mod baz; | ||
157 | //- /bar.rs crate:bar | ||
158 | mod baz; | ||
159 | "#, | ||
160 | ); | ||
161 | assert_eq!(analysis.crate_for(file_id).unwrap().len(), 2); | ||
162 | } | ||
134 | } | 163 | } |
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 new file mode 100644 index 000000000..b8834d283 --- /dev/null +++ b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs | |||
@@ -0,0 +1,272 @@ | |||
1 | use hir::{known, HasSource, Name}; | ||
2 | use syntax::{ | ||
3 | ast::{self, NameOwner}, | ||
4 | AstNode, | ||
5 | }; | ||
6 | |||
7 | use crate::{ | ||
8 | assist_context::{AssistContext, Assists}, | ||
9 | AssistId, AssistKind, | ||
10 | }; | ||
11 | |||
12 | // Assist: generate_is_empty_from_len | ||
13 | // | ||
14 | // Generates is_empty implementation from the len method. | ||
15 | // | ||
16 | // ``` | ||
17 | // struct MyStruct { data: Vec<String> } | ||
18 | // | ||
19 | // impl MyStruct { | ||
20 | // p$0ub fn len(&self) -> usize { | ||
21 | // self.data.len() | ||
22 | // } | ||
23 | // } | ||
24 | // ``` | ||
25 | // -> | ||
26 | // ``` | ||
27 | // struct MyStruct { data: Vec<String> } | ||
28 | // | ||
29 | // impl MyStruct { | ||
30 | // pub fn len(&self) -> usize { | ||
31 | // self.data.len() | ||
32 | // } | ||
33 | // | ||
34 | // pub fn is_empty(&self) -> bool { | ||
35 | // self.len() == 0 | ||
36 | // } | ||
37 | // } | ||
38 | // ``` | ||
39 | pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
40 | let fn_node = ctx.find_node_at_offset::<ast::Fn>()?; | ||
41 | let fn_name = fn_node.name()?; | ||
42 | |||
43 | if fn_name.text() != "len" { | ||
44 | cov_mark::hit!(len_function_not_present); | ||
45 | return None; | ||
46 | } | ||
47 | |||
48 | if fn_node.param_list()?.params().next().is_some() { | ||
49 | cov_mark::hit!(len_function_with_parameters); | ||
50 | return None; | ||
51 | } | ||
52 | |||
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 | |||
60 | if get_impl_method(ctx, &impl_, &known::is_empty).is_some() { | ||
61 | cov_mark::hit!(is_empty_already_implemented); | ||
62 | return None; | ||
63 | } | ||
64 | |||
65 | let node = len_fn.source(ctx.sema.db)?; | ||
66 | let range = node.syntax().value.text_range(); | ||
67 | |||
68 | acc.add( | ||
69 | AssistId("generate_is_empty_from_len", AssistKind::Generate), | ||
70 | "Generate a is_empty impl from a len function", | ||
71 | range, | ||
72 | |builder| { | ||
73 | let code = r#" | ||
74 | |||
75 | pub fn is_empty(&self) -> bool { | ||
76 | self.len() == 0 | ||
77 | }"# | ||
78 | .to_string(); | ||
79 | builder.insert(range.end(), code) | ||
80 | }, | ||
81 | ) | ||
82 | } | ||
83 | |||
84 | fn get_impl_method( | ||
85 | ctx: &AssistContext, | ||
86 | impl_: &ast::Impl, | ||
87 | fn_name: &Name, | ||
88 | ) -> Option<hir::Function> { | ||
89 | let db = ctx.sema.db; | ||
90 | let impl_def: hir::Impl = ctx.sema.to_def(impl_)?; | ||
91 | |||
92 | let scope = ctx.sema.scope(impl_.syntax()); | ||
93 | let krate = impl_def.module(db).krate(); | ||
94 | let ty = impl_def.target_ty(db); | ||
95 | let traits_in_scope = scope.traits_in_scope(); | ||
96 | ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func)) | ||
97 | } | ||
98 | |||
99 | #[cfg(test)] | ||
100 | mod tests { | ||
101 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
102 | |||
103 | use super::*; | ||
104 | |||
105 | #[test] | ||
106 | fn len_function_not_present() { | ||
107 | cov_mark::check!(len_function_not_present); | ||
108 | check_assist_not_applicable( | ||
109 | generate_is_empty_from_len, | ||
110 | r#" | ||
111 | struct MyStruct { data: Vec<String> } | ||
112 | |||
113 | impl MyStruct { | ||
114 | p$0ub fn test(&self) -> usize { | ||
115 | self.data.len() | ||
116 | } | ||
117 | } | ||
118 | "#, | ||
119 | ); | ||
120 | } | ||
121 | |||
122 | #[test] | ||
123 | fn len_function_with_parameters() { | ||
124 | cov_mark::check!(len_function_with_parameters); | ||
125 | check_assist_not_applicable( | ||
126 | generate_is_empty_from_len, | ||
127 | r#" | ||
128 | struct MyStruct { data: Vec<String> } | ||
129 | |||
130 | impl MyStruct { | ||
131 | p$0ub fn len(&self, _i: bool) -> usize { | ||
132 | self.data.len() | ||
133 | } | ||
134 | } | ||
135 | "#, | ||
136 | ); | ||
137 | } | ||
138 | |||
139 | #[test] | ||
140 | fn is_empty_already_implemented() { | ||
141 | cov_mark::check!(is_empty_already_implemented); | ||
142 | check_assist_not_applicable( | ||
143 | generate_is_empty_from_len, | ||
144 | r#" | ||
145 | struct MyStruct { data: Vec<String> } | ||
146 | |||
147 | impl MyStruct { | ||
148 | p$0ub fn len(&self) -> usize { | ||
149 | self.data.len() | ||
150 | } | ||
151 | |||
152 | pub fn is_empty(&self) -> bool { | ||
153 | self.len() == 0 | ||
154 | } | ||
155 | } | ||
156 | "#, | ||
157 | ); | ||
158 | } | ||
159 | |||
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#" | ||
166 | struct MyStruct { data: Vec<String> } | ||
167 | |||
168 | impl MyStruct { | ||
169 | p$0ub fn len(&self) -> u32 { | ||
170 | self.data.len() | ||
171 | } | ||
172 | } | ||
173 | "#, | ||
174 | ); | ||
175 | } | ||
176 | |||
177 | #[test] | ||
178 | fn generate_is_empty() { | ||
179 | check_assist( | ||
180 | generate_is_empty_from_len, | ||
181 | r#" | ||
182 | struct MyStruct { data: Vec<String> } | ||
183 | |||
184 | impl MyStruct { | ||
185 | p$0ub fn len(&self) -> usize { | ||
186 | self.data.len() | ||
187 | } | ||
188 | } | ||
189 | "#, | ||
190 | r#" | ||
191 | struct MyStruct { data: Vec<String> } | ||
192 | |||
193 | impl MyStruct { | ||
194 | pub fn len(&self) -> usize { | ||
195 | self.data.len() | ||
196 | } | ||
197 | |||
198 | pub fn is_empty(&self) -> bool { | ||
199 | self.len() == 0 | ||
200 | } | ||
201 | } | ||
202 | "#, | ||
203 | ); | ||
204 | } | ||
205 | |||
206 | #[test] | ||
207 | fn multiple_functions_in_impl() { | ||
208 | check_assist( | ||
209 | generate_is_empty_from_len, | ||
210 | r#" | ||
211 | struct MyStruct { data: Vec<String> } | ||
212 | |||
213 | impl MyStruct { | ||
214 | pub fn new() -> Self { | ||
215 | Self { data: 0 } | ||
216 | } | ||
217 | |||
218 | p$0ub fn len(&self) -> usize { | ||
219 | self.data.len() | ||
220 | } | ||
221 | |||
222 | pub fn work(&self) -> Option<usize> { | ||
223 | |||
224 | } | ||
225 | } | ||
226 | "#, | ||
227 | r#" | ||
228 | struct MyStruct { data: Vec<String> } | ||
229 | |||
230 | impl MyStruct { | ||
231 | pub fn new() -> Self { | ||
232 | Self { data: 0 } | ||
233 | } | ||
234 | |||
235 | pub fn len(&self) -> usize { | ||
236 | self.data.len() | ||
237 | } | ||
238 | |||
239 | pub fn is_empty(&self) -> bool { | ||
240 | self.len() == 0 | ||
241 | } | ||
242 | |||
243 | pub fn work(&self) -> Option<usize> { | ||
244 | |||
245 | } | ||
246 | } | ||
247 | "#, | ||
248 | ); | ||
249 | } | ||
250 | |||
251 | #[test] | ||
252 | fn multiple_impls() { | ||
253 | check_assist_not_applicable( | ||
254 | generate_is_empty_from_len, | ||
255 | r#" | ||
256 | struct MyStruct { data: Vec<String> } | ||
257 | |||
258 | impl MyStruct { | ||
259 | p$0ub fn len(&self) -> usize { | ||
260 | self.data.len() | ||
261 | } | ||
262 | } | ||
263 | |||
264 | impl MyStruct { | ||
265 | pub fn is_empty(&self) -> bool { | ||
266 | self.len() == 0 | ||
267 | } | ||
268 | } | ||
269 | "#, | ||
270 | ); | ||
271 | } | ||
272 | } | ||
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index f1aab74d4..8c068a6c0 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs | |||
@@ -129,6 +129,7 @@ mod handlers { | |||
129 | mod flip_trait_bound; | 129 | mod flip_trait_bound; |
130 | mod generate_default_from_enum_variant; | 130 | mod generate_default_from_enum_variant; |
131 | mod generate_default_from_new; | 131 | mod generate_default_from_new; |
132 | mod generate_is_empty_from_len; | ||
132 | mod generate_derive; | 133 | mod generate_derive; |
133 | mod generate_enum_is_method; | 134 | mod generate_enum_is_method; |
134 | mod generate_enum_projection_method; | 135 | mod generate_enum_projection_method; |
@@ -193,6 +194,7 @@ mod handlers { | |||
193 | flip_trait_bound::flip_trait_bound, | 194 | flip_trait_bound::flip_trait_bound, |
194 | generate_default_from_enum_variant::generate_default_from_enum_variant, | 195 | generate_default_from_enum_variant::generate_default_from_enum_variant, |
195 | generate_default_from_new::generate_default_from_new, | 196 | generate_default_from_new::generate_default_from_new, |
197 | generate_is_empty_from_len::generate_is_empty_from_len, | ||
196 | generate_derive::generate_derive, | 198 | generate_derive::generate_derive, |
197 | generate_enum_is_method::generate_enum_is_method, | 199 | generate_enum_is_method::generate_enum_is_method, |
198 | generate_enum_projection_method::generate_enum_as_method, | 200 | generate_enum_projection_method::generate_enum_as_method, |
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index 3f77edd8d..736027ff0 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs | |||
@@ -722,6 +722,35 @@ impl<T: Clone> Ctx<T> { | |||
722 | } | 722 | } |
723 | 723 | ||
724 | #[test] | 724 | #[test] |
725 | fn doctest_generate_is_empty_from_len() { | ||
726 | check_doc_test( | ||
727 | "generate_is_empty_from_len", | ||
728 | r#####" | ||
729 | struct MyStruct { data: Vec<String> } | ||
730 | |||
731 | impl MyStruct { | ||
732 | p$0ub fn len(&self) -> usize { | ||
733 | self.data.len() | ||
734 | } | ||
735 | } | ||
736 | "#####, | ||
737 | r#####" | ||
738 | struct MyStruct { data: Vec<String> } | ||
739 | |||
740 | impl MyStruct { | ||
741 | pub fn len(&self) -> usize { | ||
742 | self.data.len() | ||
743 | } | ||
744 | |||
745 | pub fn is_empty(&self) -> bool { | ||
746 | self.len() == 0 | ||
747 | } | ||
748 | } | ||
749 | "#####, | ||
750 | ) | ||
751 | } | ||
752 | |||
753 | #[test] | ||
725 | fn doctest_generate_new() { | 754 | fn doctest_generate_new() { |
726 | check_doc_test( | 755 | check_doc_test( |
727 | "generate_new", | 756 | "generate_new", |
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index 5ee9a9f07..cec2d0c3a 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -81,7 +81,7 @@ fn foo(s: S) { s.$0 } | |||
81 | "#, | 81 | "#, |
82 | expect![[r#" | 82 | expect![[r#" |
83 | fd foo u32 | 83 | fd foo u32 |
84 | me bar() -> () | 84 | me bar() fn(&self) |
85 | "#]], | 85 | "#]], |
86 | ); | 86 | ); |
87 | } | 87 | } |
@@ -97,7 +97,7 @@ impl S { | |||
97 | "#, | 97 | "#, |
98 | expect![[r#" | 98 | expect![[r#" |
99 | fd the_field (u32,) | 99 | fd the_field (u32,) |
100 | me foo() -> () | 100 | me foo() fn(self) |
101 | "#]], | 101 | "#]], |
102 | ) | 102 | ) |
103 | } | 103 | } |
@@ -113,7 +113,7 @@ impl A { | |||
113 | "#, | 113 | "#, |
114 | expect![[r#" | 114 | expect![[r#" |
115 | fd the_field (u32, i32) | 115 | fd the_field (u32, i32) |
116 | me foo() -> () | 116 | me foo() fn(&self) |
117 | "#]], | 117 | "#]], |
118 | ) | 118 | ) |
119 | } | 119 | } |
@@ -163,7 +163,7 @@ mod m { | |||
163 | fn foo(a: A) { a.$0 } | 163 | fn foo(a: A) { a.$0 } |
164 | "#, | 164 | "#, |
165 | expect![[r#" | 165 | expect![[r#" |
166 | me the_method() -> () | 166 | me the_method() fn(&self) |
167 | "#]], | 167 | "#]], |
168 | ); | 168 | ); |
169 | } | 169 | } |
@@ -196,7 +196,7 @@ impl A<i32> { | |||
196 | fn foo(a: A<u32>) { a.$0 } | 196 | fn foo(a: A<u32>) { a.$0 } |
197 | "#, | 197 | "#, |
198 | expect![[r#" | 198 | expect![[r#" |
199 | me the_method() -> () | 199 | me the_method() fn(&self) |
200 | "#]], | 200 | "#]], |
201 | ) | 201 | ) |
202 | } | 202 | } |
@@ -211,7 +211,7 @@ impl Trait for A {} | |||
211 | fn foo(a: A) { a.$0 } | 211 | fn foo(a: A) { a.$0 } |
212 | "#, | 212 | "#, |
213 | expect![[r#" | 213 | expect![[r#" |
214 | me the_method() -> () | 214 | me the_method() fn(&self) |
215 | "#]], | 215 | "#]], |
216 | ); | 216 | ); |
217 | } | 217 | } |
@@ -226,7 +226,7 @@ impl<T> Trait for T {} | |||
226 | fn foo(a: &A) { a.$0 } | 226 | fn foo(a: &A) { a.$0 } |
227 | ", | 227 | ", |
228 | expect![[r#" | 228 | expect![[r#" |
229 | me the_method() -> () | 229 | me the_method() fn(&self) |
230 | "#]], | 230 | "#]], |
231 | ); | 231 | ); |
232 | } | 232 | } |
@@ -244,7 +244,7 @@ impl Trait for A {} | |||
244 | fn foo(a: A) { a.$0 } | 244 | fn foo(a: A) { a.$0 } |
245 | ", | 245 | ", |
246 | expect![[r#" | 246 | expect![[r#" |
247 | me the_method() -> () | 247 | me the_method() fn(&self) |
248 | "#]], | 248 | "#]], |
249 | ); | 249 | ); |
250 | } | 250 | } |
@@ -298,7 +298,7 @@ impl T { | |||
298 | } | 298 | } |
299 | "#, | 299 | "#, |
300 | expect![[r#" | 300 | expect![[r#" |
301 | me blah() -> () | 301 | me blah() fn(&self) |
302 | "#]], | 302 | "#]], |
303 | ); | 303 | ); |
304 | } | 304 | } |
@@ -407,7 +407,7 @@ fn foo() { | |||
407 | } | 407 | } |
408 | "#, | 408 | "#, |
409 | expect![[r#" | 409 | expect![[r#" |
410 | me the_method() -> () | 410 | me the_method() fn(&self) |
411 | "#]], | 411 | "#]], |
412 | ); | 412 | ); |
413 | } | 413 | } |
@@ -422,7 +422,7 @@ macro_rules! make_s { () => { S }; } | |||
422 | fn main() { make_s!().f$0; } | 422 | fn main() { make_s!().f$0; } |
423 | "#, | 423 | "#, |
424 | expect![[r#" | 424 | expect![[r#" |
425 | me foo() -> () | 425 | me foo() fn(&self) |
426 | "#]], | 426 | "#]], |
427 | ) | 427 | ) |
428 | } | 428 | } |
@@ -450,7 +450,7 @@ mod foo { | |||
450 | } | 450 | } |
451 | "#, | 451 | "#, |
452 | expect![[r#" | 452 | expect![[r#" |
453 | me private() -> () | 453 | me private() fn(&self) |
454 | "#]], | 454 | "#]], |
455 | ); | 455 | ); |
456 | } | 456 | } |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 391a11c91..08df2df3f 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -402,7 +402,7 @@ fn main() { | |||
402 | check( | 402 | check( |
403 | fixture, | 403 | fixture, |
404 | expect![[r#" | 404 | expect![[r#" |
405 | fn weird_function() (dep::test_mod::TestTrait) -> () | 405 | fn weird_function() (dep::test_mod::TestTrait) fn() |
406 | "#]], | 406 | "#]], |
407 | ); | 407 | ); |
408 | 408 | ||
@@ -495,7 +495,7 @@ fn main() { | |||
495 | check( | 495 | check( |
496 | fixture, | 496 | fixture, |
497 | expect![[r#" | 497 | expect![[r#" |
498 | me random_method() (dep::test_mod::TestTrait) -> () | 498 | me random_method() (dep::test_mod::TestTrait) fn(&self) |
499 | "#]], | 499 | "#]], |
500 | ); | 500 | ); |
501 | 501 | ||
@@ -665,7 +665,7 @@ fn main() { | |||
665 | } | 665 | } |
666 | "#, | 666 | "#, |
667 | expect![[r#" | 667 | expect![[r#" |
668 | me random_method() (dep::test_mod::TestTrait) -> () DEPRECATED | 668 | me random_method() (dep::test_mod::TestTrait) fn(&self) DEPRECATED |
669 | "#]], | 669 | "#]], |
670 | ); | 670 | ); |
671 | 671 | ||
@@ -696,7 +696,7 @@ fn main() { | |||
696 | "#, | 696 | "#, |
697 | expect![[r#" | 697 | expect![[r#" |
698 | ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED | 698 | ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED |
699 | fn weird_function() (dep::test_mod::TestTrait) -> () DEPRECATED | 699 | fn weird_function() (dep::test_mod::TestTrait) fn() DEPRECATED |
700 | "#]], | 700 | "#]], |
701 | ); | 701 | ); |
702 | } | 702 | } |
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 9282c3827..46cef58f0 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -11,10 +11,13 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
11 | return; | 11 | return; |
12 | } | 12 | } |
13 | 13 | ||
14 | if let Some(ty) = &ctx.expected_type { | 14 | if !ctx.is_irrefutable_pat_binding { |
15 | super::complete_enum_variants(acc, ctx, ty, |acc, ctx, variant, path| { | 15 | if let Some(ty) = ctx.expected_type.as_ref() { |
16 | acc.add_qualified_variant_pat(ctx, variant, path) | 16 | super::complete_enum_variants(acc, ctx, ty, |acc, ctx, variant, path| { |
17 | }); | 17 | acc.add_qualified_variant_pat(ctx, variant, path.clone()); |
18 | acc.add_qualified_enum_variant(ctx, variant, path); | ||
19 | }); | ||
20 | } | ||
18 | } | 21 | } |
19 | 22 | ||
20 | // FIXME: ideally, we should look at the type we are matching against and | 23 | // FIXME: ideally, we should look at the type we are matching against and |
@@ -85,7 +88,7 @@ static FOO: E = E::X; | |||
85 | struct Bar { f: u32 } | 88 | struct Bar { f: u32 } |
86 | 89 | ||
87 | fn foo() { | 90 | fn foo() { |
88 | match E::X { $0 } | 91 | match E::X { a$0 } |
89 | } | 92 | } |
90 | "#, | 93 | "#, |
91 | expect![[r#" | 94 | expect![[r#" |
@@ -106,10 +109,11 @@ macro_rules! m { ($e:expr) => { $e } } | |||
106 | enum E { X } | 109 | enum E { X } |
107 | 110 | ||
108 | fn foo() { | 111 | fn foo() { |
109 | m!(match E::X { $0 }) | 112 | m!(match E::X { a$0 }) |
110 | } | 113 | } |
111 | "#, | 114 | "#, |
112 | expect![[r#" | 115 | expect![[r#" |
116 | ev E::X () | ||
113 | en E | 117 | en E |
114 | ma m!(…) macro_rules! m | 118 | ma m!(…) macro_rules! m |
115 | "#]], | 119 | "#]], |
@@ -129,7 +133,7 @@ static FOO: E = E::X; | |||
129 | struct Bar { f: u32 } | 133 | struct Bar { f: u32 } |
130 | 134 | ||
131 | fn foo() { | 135 | fn foo() { |
132 | let $0 | 136 | let a$0 |
133 | } | 137 | } |
134 | "#, | 138 | "#, |
135 | expect![[r#" | 139 | expect![[r#" |
@@ -147,7 +151,7 @@ enum E { X } | |||
147 | static FOO: E = E::X; | 151 | static FOO: E = E::X; |
148 | struct Bar { f: u32 } | 152 | struct Bar { f: u32 } |
149 | 153 | ||
150 | fn foo($0) { | 154 | fn foo(a$0) { |
151 | } | 155 | } |
152 | "#, | 156 | "#, |
153 | expect![[r#" | 157 | expect![[r#" |
@@ -163,7 +167,7 @@ fn foo($0) { | |||
163 | struct Bar { f: u32 } | 167 | struct Bar { f: u32 } |
164 | 168 | ||
165 | fn foo() { | 169 | fn foo() { |
166 | let $0 | 170 | let a$0 |
167 | } | 171 | } |
168 | "#, | 172 | "#, |
169 | expect![[r#" | 173 | expect![[r#" |
@@ -179,7 +183,7 @@ fn foo() { | |||
179 | struct Foo { bar: String, baz: String } | 183 | struct Foo { bar: String, baz: String } |
180 | struct Bar(String, String); | 184 | struct Bar(String, String); |
181 | struct Baz; | 185 | struct Baz; |
182 | fn outer($0) {} | 186 | fn outer(a$0) {} |
183 | "#, | 187 | "#, |
184 | expect![[r#" | 188 | expect![[r#" |
185 | bn Foo Foo { bar$1, baz$2 }: Foo$0 | 189 | bn Foo Foo { bar$1, baz$2 }: Foo$0 |
@@ -196,7 +200,7 @@ struct Foo { bar: String, baz: String } | |||
196 | struct Bar(String, String); | 200 | struct Bar(String, String); |
197 | struct Baz; | 201 | struct Baz; |
198 | fn outer() { | 202 | fn outer() { |
199 | let $0 | 203 | let a$0 |
200 | } | 204 | } |
201 | "#, | 205 | "#, |
202 | expect![[r#" | 206 | expect![[r#" |
@@ -215,7 +219,7 @@ struct Bar(String, String); | |||
215 | struct Baz; | 219 | struct Baz; |
216 | fn outer() { | 220 | fn outer() { |
217 | match () { | 221 | match () { |
218 | $0 | 222 | a$0 |
219 | } | 223 | } |
220 | } | 224 | } |
221 | "#, | 225 | "#, |
@@ -239,7 +243,7 @@ use foo::*; | |||
239 | 243 | ||
240 | fn outer() { | 244 | fn outer() { |
241 | match () { | 245 | match () { |
242 | $0 | 246 | a$0 |
243 | } | 247 | } |
244 | } | 248 | } |
245 | "#, | 249 | "#, |
@@ -258,7 +262,7 @@ fn outer() { | |||
258 | struct Foo(i32); | 262 | struct Foo(i32); |
259 | fn main() { | 263 | fn main() { |
260 | match Foo(92) { | 264 | match Foo(92) { |
261 | $0(92) => (), | 265 | a$0(92) => (), |
262 | } | 266 | } |
263 | } | 267 | } |
264 | "#, | 268 | "#, |
@@ -281,7 +285,7 @@ struct Foo(i32); | |||
281 | impl Foo { | 285 | impl Foo { |
282 | fn foo() { | 286 | fn foo() { |
283 | match () { | 287 | match () { |
284 | $0 | 288 | a$0 |
285 | } | 289 | } |
286 | } | 290 | } |
287 | } | 291 | } |
@@ -314,4 +318,86 @@ impl Foo { | |||
314 | "#]], | 318 | "#]], |
315 | ) | 319 | ) |
316 | } | 320 | } |
321 | |||
322 | #[test] | ||
323 | fn completes_enum_variant_matcharm() { | ||
324 | check( | ||
325 | r#" | ||
326 | enum Foo { Bar, Baz, Quux } | ||
327 | |||
328 | fn main() { | ||
329 | let foo = Foo::Quux; | ||
330 | match foo { Qu$0 } | ||
331 | } | ||
332 | "#, | ||
333 | expect![[r#" | ||
334 | ev Foo::Bar () | ||
335 | ev Foo::Baz () | ||
336 | ev Foo::Quux () | ||
337 | en Foo | ||
338 | "#]], | ||
339 | ) | ||
340 | } | ||
341 | |||
342 | #[test] | ||
343 | fn completes_enum_variant_matcharm_ref() { | ||
344 | check( | ||
345 | r#" | ||
346 | enum Foo { Bar, Baz, Quux } | ||
347 | |||
348 | fn main() { | ||
349 | let foo = Foo::Quux; | ||
350 | match &foo { Qu$0 } | ||
351 | } | ||
352 | "#, | ||
353 | expect![[r#" | ||
354 | ev Foo::Bar () | ||
355 | ev Foo::Baz () | ||
356 | ev Foo::Quux () | ||
357 | en Foo | ||
358 | "#]], | ||
359 | ) | ||
360 | } | ||
361 | |||
362 | #[test] | ||
363 | fn completes_enum_variant_iflet() { | ||
364 | check( | ||
365 | r#" | ||
366 | enum Foo { Bar, Baz, Quux } | ||
367 | |||
368 | fn main() { | ||
369 | let foo = Foo::Quux; | ||
370 | if let Qu$0 = foo { } | ||
371 | } | ||
372 | "#, | ||
373 | expect![[r#" | ||
374 | ev Foo::Bar () | ||
375 | ev Foo::Baz () | ||
376 | ev Foo::Quux () | ||
377 | en Foo | ||
378 | "#]], | ||
379 | ) | ||
380 | } | ||
381 | |||
382 | #[test] | ||
383 | fn completes_enum_variant_impl() { | ||
384 | check( | ||
385 | r#" | ||
386 | enum Foo { Bar, Baz, Quux } | ||
387 | impl Foo { | ||
388 | fn foo() { match Foo::Bar { Q$0 } } | ||
389 | } | ||
390 | "#, | ||
391 | expect![[r#" | ||
392 | ev Self::Bar () | ||
393 | ev Self::Baz () | ||
394 | ev Self::Quux () | ||
395 | ev Foo::Bar () | ||
396 | ev Foo::Baz () | ||
397 | ev Foo::Quux () | ||
398 | sp Self | ||
399 | en Foo | ||
400 | "#]], | ||
401 | ) | ||
402 | } | ||
317 | } | 403 | } |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index df74b739e..105ff6013 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -359,8 +359,8 @@ impl S { | |||
359 | fn foo() { let _ = S::$0 } | 359 | fn foo() { let _ = S::$0 } |
360 | "#, | 360 | "#, |
361 | expect![[r#" | 361 | expect![[r#" |
362 | fn a() -> () | 362 | fn a() fn() |
363 | me b(…) -> () | 363 | me b(…) fn(&self) |
364 | ct C const C: i32 = 42; | 364 | ct C const C: i32 = 42; |
365 | ta T type T = i32; | 365 | ta T type T = i32; |
366 | "#]], | 366 | "#]], |
@@ -387,7 +387,7 @@ mod m { | |||
387 | fn foo() { let _ = S::$0 } | 387 | fn foo() { let _ = S::$0 } |
388 | "#, | 388 | "#, |
389 | expect![[r#" | 389 | expect![[r#" |
390 | fn public_method() -> () | 390 | fn public_method() fn() |
391 | ct PUBLIC_CONST pub(crate) const PUBLIC_CONST: u32 = 1; | 391 | ct PUBLIC_CONST pub(crate) const PUBLIC_CONST: u32 = 1; |
392 | ta PublicType pub(crate) type PublicType = u32; | 392 | ta PublicType pub(crate) type PublicType = u32; |
393 | "#]], | 393 | "#]], |
@@ -404,7 +404,7 @@ impl E { fn m() { } } | |||
404 | fn foo() { let _ = E::$0 } | 404 | fn foo() { let _ = E::$0 } |
405 | "#, | 405 | "#, |
406 | expect![[r#" | 406 | expect![[r#" |
407 | fn m() -> () | 407 | fn m() fn() |
408 | "#]], | 408 | "#]], |
409 | ); | 409 | ); |
410 | } | 410 | } |
@@ -419,7 +419,7 @@ impl U { fn m() { } } | |||
419 | fn foo() { let _ = U::$0 } | 419 | fn foo() { let _ = U::$0 } |
420 | "#, | 420 | "#, |
421 | expect![[r#" | 421 | expect![[r#" |
422 | fn m() -> () | 422 | fn m() fn() |
423 | "#]], | 423 | "#]], |
424 | ); | 424 | ); |
425 | } | 425 | } |
@@ -449,7 +449,7 @@ trait Trait { fn m(); } | |||
449 | fn foo() { let _ = Trait::$0 } | 449 | fn foo() { let _ = Trait::$0 } |
450 | "#, | 450 | "#, |
451 | expect![[r#" | 451 | expect![[r#" |
452 | fn m() -> () | 452 | fn m() fn() |
453 | "#]], | 453 | "#]], |
454 | ); | 454 | ); |
455 | } | 455 | } |
@@ -466,7 +466,7 @@ impl Trait for S {} | |||
466 | fn foo() { let _ = S::$0 } | 466 | fn foo() { let _ = S::$0 } |
467 | "#, | 467 | "#, |
468 | expect![[r#" | 468 | expect![[r#" |
469 | fn m() -> () | 469 | fn m() fn() |
470 | "#]], | 470 | "#]], |
471 | ); | 471 | ); |
472 | } | 472 | } |
@@ -483,7 +483,7 @@ impl Trait for S {} | |||
483 | fn foo() { let _ = <S as Trait>::$0 } | 483 | fn foo() { let _ = <S as Trait>::$0 } |
484 | "#, | 484 | "#, |
485 | expect![[r#" | 485 | expect![[r#" |
486 | fn m() -> () | 486 | fn m() fn() |
487 | "#]], | 487 | "#]], |
488 | ); | 488 | ); |
489 | } | 489 | } |
@@ -512,11 +512,11 @@ fn foo<T: Sub>() { T::$0 } | |||
512 | ta SubTy type SubTy; | 512 | ta SubTy type SubTy; |
513 | ta Ty type Ty; | 513 | ta Ty type Ty; |
514 | ct C2 const C2: (); | 514 | ct C2 const C2: (); |
515 | fn subfunc() -> () | 515 | fn subfunc() fn() |
516 | me submethod(…) -> () | 516 | me submethod(…) fn(&self) |
517 | ct CONST const CONST: u8; | 517 | ct CONST const CONST: u8; |
518 | fn func() -> () | 518 | fn func() fn() |
519 | me method(…) -> () | 519 | me method(…) fn(&self) |
520 | "#]], | 520 | "#]], |
521 | ); | 521 | ); |
522 | } | 522 | } |
@@ -552,11 +552,11 @@ impl<T> Sub for Wrap<T> { | |||
552 | ta SubTy type SubTy; | 552 | ta SubTy type SubTy; |
553 | ta Ty type Ty; | 553 | ta Ty type Ty; |
554 | ct CONST const CONST: u8 = 0; | 554 | ct CONST const CONST: u8 = 0; |
555 | fn func() -> () | 555 | fn func() fn() |
556 | me method(…) -> () | 556 | me method(…) fn(&self) |
557 | ct C2 const C2: () = (); | 557 | ct C2 const C2: () = (); |
558 | fn subfunc() -> () | 558 | fn subfunc() fn() |
559 | me submethod(…) -> () | 559 | me submethod(…) fn(&self) |
560 | "#]], | 560 | "#]], |
561 | ); | 561 | ); |
562 | } | 562 | } |
@@ -573,8 +573,8 @@ impl T { fn bar() {} } | |||
573 | fn main() { T::$0; } | 573 | fn main() { T::$0; } |
574 | "#, | 574 | "#, |
575 | expect![[r#" | 575 | expect![[r#" |
576 | fn foo() -> () | 576 | fn foo() fn() |
577 | fn bar() -> () | 577 | fn bar() fn() |
578 | "#]], | 578 | "#]], |
579 | ); | 579 | ); |
580 | } | 580 | } |
@@ -589,7 +589,7 @@ macro_rules! foo { () => {} } | |||
589 | fn main() { let _ = crate::$0 } | 589 | fn main() { let _ = crate::$0 } |
590 | "#, | 590 | "#, |
591 | expect![[r##" | 591 | expect![[r##" |
592 | fn main() -> () | 592 | fn main() fn() |
593 | ma foo!(…) #[macro_export] macro_rules! foo | 593 | ma foo!(…) #[macro_export] macro_rules! foo |
594 | "##]], | 594 | "##]], |
595 | ); | 595 | ); |
@@ -633,7 +633,7 @@ mod p { | |||
633 | "#, | 633 | "#, |
634 | expect![[r#" | 634 | expect![[r#" |
635 | ct RIGHT_CONST | 635 | ct RIGHT_CONST |
636 | fn right_fn() -> () | 636 | fn right_fn() fn() |
637 | st RightType | 637 | st RightType |
638 | "#]], | 638 | "#]], |
639 | ); | 639 | ); |
@@ -680,8 +680,8 @@ fn main() { m!(self::f$0); } | |||
680 | fn foo() {} | 680 | fn foo() {} |
681 | "#, | 681 | "#, |
682 | expect![[r#" | 682 | expect![[r#" |
683 | fn main() -> () | 683 | fn main() fn() |
684 | fn foo() -> () | 684 | fn foo() fn() |
685 | "#]], | 685 | "#]], |
686 | ); | 686 | ); |
687 | } | 687 | } |
@@ -699,7 +699,7 @@ mod m { | |||
699 | "#, | 699 | "#, |
700 | expect![[r#" | 700 | expect![[r#" |
701 | md z | 701 | md z |
702 | fn z() -> () | 702 | fn z() fn() |
703 | "#]], | 703 | "#]], |
704 | ); | 704 | ); |
705 | } | 705 | } |
@@ -719,7 +719,7 @@ fn foo() { | |||
719 | } | 719 | } |
720 | "#, | 720 | "#, |
721 | expect![[r#" | 721 | expect![[r#" |
722 | fn new() -> HashMap<K, V, RandomState> | 722 | fn new() fn() -> HashMap<K, V, RandomState> |
723 | "#]], | 723 | "#]], |
724 | ); | 724 | ); |
725 | } | 725 | } |
@@ -752,8 +752,8 @@ fn main() { | |||
752 | } | 752 | } |
753 | "#, | 753 | "#, |
754 | expect![[r#" | 754 | expect![[r#" |
755 | fn main() -> () | 755 | fn main() fn() |
756 | fn foo(…) -> () | 756 | fn foo(…) fn(i32, i32) |
757 | "#]], | 757 | "#]], |
758 | ); | 758 | ); |
759 | } | 759 | } |
@@ -776,7 +776,7 @@ impl Foo { | |||
776 | expect![[r#" | 776 | expect![[r#" |
777 | ev Bar () | 777 | ev Bar () |
778 | ev Baz () | 778 | ev Baz () |
779 | me foo(…) -> () | 779 | me foo(…) fn(self) |
780 | "#]], | 780 | "#]], |
781 | ); | 781 | ); |
782 | } | 782 | } |
@@ -800,7 +800,7 @@ impl u8 { | |||
800 | "#, | 800 | "#, |
801 | expect![[r#" | 801 | expect![[r#" |
802 | ct MAX pub const MAX: Self = 255; | 802 | ct MAX pub const MAX: Self = 255; |
803 | me func(…) -> () | 803 | me func(…) fn(self) |
804 | "#]], | 804 | "#]], |
805 | ); | 805 | ); |
806 | } | 806 | } |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 044dfd160..1b8b063e7 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -6,7 +6,7 @@ use syntax::AstNode; | |||
6 | use crate::{CompletionContext, Completions}; | 6 | use crate::{CompletionContext, Completions}; |
7 | 7 | ||
8 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 8 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
9 | if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { | 9 | if !ctx.is_trivial_path { |
10 | return; | 10 | return; |
11 | } | 11 | } |
12 | if ctx.record_lit_syntax.is_some() | 12 | if ctx.record_lit_syntax.is_some() |
@@ -23,10 +23,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
23 | }); | 23 | }); |
24 | } | 24 | } |
25 | 25 | ||
26 | if ctx.is_pat_binding_or_const { | ||
27 | return; | ||
28 | } | ||
29 | |||
30 | ctx.scope.process_all_names(&mut |name, res| { | 26 | ctx.scope.process_all_names(&mut |name, res| { |
31 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { | 27 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { |
32 | cov_mark::hit!(skip_lifetime_completion); | 28 | cov_mark::hit!(skip_lifetime_completion); |
@@ -139,7 +135,7 @@ fn quux(x: i32) { | |||
139 | expect![[r#" | 135 | expect![[r#" |
140 | lc y i32 | 136 | lc y i32 |
141 | lc x i32 | 137 | lc x i32 |
142 | fn quux(…) -> () | 138 | fn quux(…) fn(i32) |
143 | "#]], | 139 | "#]], |
144 | ); | 140 | ); |
145 | } | 141 | } |
@@ -161,7 +157,7 @@ fn quux() { | |||
161 | expect![[r#" | 157 | expect![[r#" |
162 | lc b i32 | 158 | lc b i32 |
163 | lc a | 159 | lc a |
164 | fn quux() -> () | 160 | fn quux() fn() |
165 | "#]], | 161 | "#]], |
166 | ); | 162 | ); |
167 | } | 163 | } |
@@ -176,7 +172,7 @@ fn quux() { | |||
176 | "#, | 172 | "#, |
177 | expect![[r#" | 173 | expect![[r#" |
178 | lc x | 174 | lc x |
179 | fn quux() -> () | 175 | fn quux() fn() |
180 | "#]], | 176 | "#]], |
181 | ); | 177 | ); |
182 | } | 178 | } |
@@ -207,14 +203,14 @@ fn main() { | |||
207 | r#"fn quux<T>() { $0 }"#, | 203 | r#"fn quux<T>() { $0 }"#, |
208 | expect![[r#" | 204 | expect![[r#" |
209 | tp T | 205 | tp T |
210 | fn quux() -> () | 206 | fn quux() fn() |
211 | "#]], | 207 | "#]], |
212 | ); | 208 | ); |
213 | check( | 209 | check( |
214 | r#"fn quux<const C: usize>() { $0 }"#, | 210 | r#"fn quux<const C: usize>() { $0 }"#, |
215 | expect![[r#" | 211 | expect![[r#" |
216 | cp C | 212 | cp C |
217 | fn quux() -> () | 213 | fn quux() fn() |
218 | "#]], | 214 | "#]], |
219 | ); | 215 | ); |
220 | } | 216 | } |
@@ -225,7 +221,7 @@ fn main() { | |||
225 | check( | 221 | check( |
226 | r#"fn quux<'a>() { $0 }"#, | 222 | r#"fn quux<'a>() { $0 }"#, |
227 | expect![[r#" | 223 | expect![[r#" |
228 | fn quux() -> () | 224 | fn quux() fn() |
229 | "#]], | 225 | "#]], |
230 | ); | 226 | ); |
231 | } | 227 | } |
@@ -263,7 +259,7 @@ fn quux() { $0 } | |||
263 | "#, | 259 | "#, |
264 | expect![[r#" | 260 | expect![[r#" |
265 | st S | 261 | st S |
266 | fn quux() -> () | 262 | fn quux() fn() |
267 | en E | 263 | en E |
268 | "#]], | 264 | "#]], |
269 | ); | 265 | ); |
@@ -316,7 +312,7 @@ mod m { | |||
316 | } | 312 | } |
317 | "#, | 313 | "#, |
318 | expect![[r#" | 314 | expect![[r#" |
319 | fn quux() -> () | 315 | fn quux() fn() |
320 | st Bar | 316 | st Bar |
321 | "#]], | 317 | "#]], |
322 | ); | 318 | ); |
@@ -331,7 +327,7 @@ fn x() -> $0 | |||
331 | "#, | 327 | "#, |
332 | expect![[r#" | 328 | expect![[r#" |
333 | st Foo | 329 | st Foo |
334 | fn x() -> () | 330 | fn x() fn() |
335 | "#]], | 331 | "#]], |
336 | ); | 332 | ); |
337 | } | 333 | } |
@@ -352,7 +348,7 @@ fn foo() { | |||
352 | expect![[r#" | 348 | expect![[r#" |
353 | lc bar i32 | 349 | lc bar i32 |
354 | lc bar i32 | 350 | lc bar i32 |
355 | fn foo() -> () | 351 | fn foo() fn() |
356 | "#]], | 352 | "#]], |
357 | ); | 353 | ); |
358 | } | 354 | } |
@@ -382,7 +378,7 @@ use prelude::*; | |||
382 | mod prelude { struct Option; } | 378 | mod prelude { struct Option; } |
383 | "#, | 379 | "#, |
384 | expect![[r#" | 380 | expect![[r#" |
385 | fn foo() -> () | 381 | fn foo() fn() |
386 | md std | 382 | md std |
387 | st Option | 383 | st Option |
388 | "#]], | 384 | "#]], |
@@ -412,7 +408,7 @@ mod macros { | |||
412 | } | 408 | } |
413 | "#, | 409 | "#, |
414 | expect![[r##" | 410 | expect![[r##" |
415 | fn f() -> () | 411 | fn f() fn() |
416 | ma concat!(…) #[macro_export] macro_rules! concat | 412 | ma concat!(…) #[macro_export] macro_rules! concat |
417 | md std | 413 | md std |
418 | "##]], | 414 | "##]], |
@@ -439,7 +435,7 @@ use prelude::*; | |||
439 | mod prelude { struct String; } | 435 | mod prelude { struct String; } |
440 | "#, | 436 | "#, |
441 | expect![[r#" | 437 | expect![[r#" |
442 | fn foo() -> () | 438 | fn foo() fn() |
443 | md std | 439 | md std |
444 | md core | 440 | md core |
445 | st String | 441 | st String |
@@ -470,7 +466,7 @@ fn main() { let v = $0 } | |||
470 | expect![[r##" | 466 | expect![[r##" |
471 | md m1 | 467 | md m1 |
472 | ma baz!(…) #[macro_export] macro_rules! baz | 468 | ma baz!(…) #[macro_export] macro_rules! baz |
473 | fn main() -> () | 469 | fn main() fn() |
474 | md m2 | 470 | md m2 |
475 | ma bar!(…) macro_rules! bar | 471 | ma bar!(…) macro_rules! bar |
476 | ma foo!(…) macro_rules! foo | 472 | ma foo!(…) macro_rules! foo |
@@ -486,7 +482,7 @@ macro_rules! foo { () => {} } | |||
486 | fn foo() { $0 } | 482 | fn foo() { $0 } |
487 | "#, | 483 | "#, |
488 | expect![[r#" | 484 | expect![[r#" |
489 | fn foo() -> () | 485 | fn foo() fn() |
490 | ma foo!(…) macro_rules! foo | 486 | ma foo!(…) macro_rules! foo |
491 | "#]], | 487 | "#]], |
492 | ); | 488 | ); |
@@ -500,7 +496,7 @@ macro_rules! foo { () => {} } | |||
500 | fn main() { let x: $0 } | 496 | fn main() { let x: $0 } |
501 | "#, | 497 | "#, |
502 | expect![[r#" | 498 | expect![[r#" |
503 | fn main() -> () | 499 | fn main() fn() |
504 | ma foo!(…) macro_rules! foo | 500 | ma foo!(…) macro_rules! foo |
505 | "#]], | 501 | "#]], |
506 | ); | 502 | ); |
@@ -514,7 +510,7 @@ macro_rules! foo { () => {} } | |||
514 | fn main() { $0 } | 510 | fn main() { $0 } |
515 | "#, | 511 | "#, |
516 | expect![[r#" | 512 | expect![[r#" |
517 | fn main() -> () | 513 | fn main() fn() |
518 | ma foo!(…) macro_rules! foo | 514 | ma foo!(…) macro_rules! foo |
519 | "#]], | 515 | "#]], |
520 | ); | 516 | ); |
@@ -530,8 +526,8 @@ fn main() { | |||
530 | } | 526 | } |
531 | "#, | 527 | "#, |
532 | expect![[r#" | 528 | expect![[r#" |
533 | fn frobnicate() -> () | 529 | fn frobnicate() fn() |
534 | fn main() -> () | 530 | fn main() fn() |
535 | "#]], | 531 | "#]], |
536 | ); | 532 | ); |
537 | } | 533 | } |
@@ -549,7 +545,7 @@ fn quux(x: i32) { | |||
549 | expect![[r#" | 545 | expect![[r#" |
550 | lc y i32 | 546 | lc y i32 |
551 | lc x i32 | 547 | lc x i32 |
552 | fn quux(…) -> () | 548 | fn quux(…) fn(i32) |
553 | ma m!(…) macro_rules! m | 549 | ma m!(…) macro_rules! m |
554 | "#]], | 550 | "#]], |
555 | ); | 551 | ); |
@@ -568,7 +564,7 @@ fn quux(x: i32) { | |||
568 | expect![[r#" | 564 | expect![[r#" |
569 | lc y i32 | 565 | lc y i32 |
570 | lc x i32 | 566 | lc x i32 |
571 | fn quux(…) -> () | 567 | fn quux(…) fn(i32) |
572 | ma m!(…) macro_rules! m | 568 | ma m!(…) macro_rules! m |
573 | "#]], | 569 | "#]], |
574 | ); | 570 | ); |
@@ -587,7 +583,7 @@ fn quux(x: i32) { | |||
587 | expect![[r#" | 583 | expect![[r#" |
588 | lc y i32 | 584 | lc y i32 |
589 | lc x i32 | 585 | lc x i32 |
590 | fn quux(…) -> () | 586 | fn quux(…) fn(i32) |
591 | ma m!(…) macro_rules! m | 587 | ma m!(…) macro_rules! m |
592 | "#]], | 588 | "#]], |
593 | ); | 589 | ); |
@@ -602,73 +598,13 @@ use spam::Quux; | |||
602 | fn main() { $0 } | 598 | fn main() { $0 } |
603 | "#, | 599 | "#, |
604 | expect![[r#" | 600 | expect![[r#" |
605 | fn main() -> () | 601 | fn main() fn() |
606 | ?? Quux | 602 | ?? Quux |
607 | "#]], | 603 | "#]], |
608 | ); | 604 | ); |
609 | } | 605 | } |
610 | 606 | ||
611 | #[test] | 607 | #[test] |
612 | fn completes_enum_variant_matcharm() { | ||
613 | check( | ||
614 | r#" | ||
615 | enum Foo { Bar, Baz, Quux } | ||
616 | |||
617 | fn main() { | ||
618 | let foo = Foo::Quux; | ||
619 | match foo { Qu$0 } | ||
620 | } | ||
621 | "#, | ||
622 | expect![[r#" | ||
623 | ev Foo::Bar () | ||
624 | ev Foo::Baz () | ||
625 | ev Foo::Quux () | ||
626 | en Foo | ||
627 | "#]], | ||
628 | ) | ||
629 | } | ||
630 | |||
631 | #[test] | ||
632 | fn completes_enum_variant_matcharm_ref() { | ||
633 | check( | ||
634 | r#" | ||
635 | enum Foo { Bar, Baz, Quux } | ||
636 | |||
637 | fn main() { | ||
638 | let foo = Foo::Quux; | ||
639 | match &foo { Qu$0 } | ||
640 | } | ||
641 | "#, | ||
642 | expect![[r#" | ||
643 | ev Foo::Bar () | ||
644 | ev Foo::Baz () | ||
645 | ev Foo::Quux () | ||
646 | en Foo | ||
647 | "#]], | ||
648 | ) | ||
649 | } | ||
650 | |||
651 | #[test] | ||
652 | fn completes_enum_variant_iflet() { | ||
653 | check( | ||
654 | r#" | ||
655 | enum Foo { Bar, Baz, Quux } | ||
656 | |||
657 | fn main() { | ||
658 | let foo = Foo::Quux; | ||
659 | if let Qu$0 = foo { } | ||
660 | } | ||
661 | "#, | ||
662 | expect![[r#" | ||
663 | ev Foo::Bar () | ||
664 | ev Foo::Baz () | ||
665 | ev Foo::Quux () | ||
666 | en Foo | ||
667 | "#]], | ||
668 | ) | ||
669 | } | ||
670 | |||
671 | #[test] | ||
672 | fn completes_enum_variant_basic_expr() { | 608 | fn completes_enum_variant_basic_expr() { |
673 | check( | 609 | check( |
674 | r#" | 610 | r#" |
@@ -680,7 +616,7 @@ fn main() { let foo: Foo = Q$0 } | |||
680 | ev Foo::Baz () | 616 | ev Foo::Baz () |
681 | ev Foo::Quux () | 617 | ev Foo::Quux () |
682 | en Foo | 618 | en Foo |
683 | fn main() -> () | 619 | fn main() fn() |
684 | "#]], | 620 | "#]], |
685 | ) | 621 | ) |
686 | } | 622 | } |
@@ -695,29 +631,7 @@ fn f() -> m::E { V$0 } | |||
695 | expect![[r#" | 631 | expect![[r#" |
696 | ev m::E::V () | 632 | ev m::E::V () |
697 | md m | 633 | md m |
698 | fn f() -> E | 634 | fn f() fn() -> E |
699 | "#]], | ||
700 | ) | ||
701 | } | ||
702 | |||
703 | #[test] | ||
704 | fn completes_enum_variant_impl() { | ||
705 | check( | ||
706 | r#" | ||
707 | enum Foo { Bar, Baz, Quux } | ||
708 | impl Foo { | ||
709 | fn foo() { match Foo::Bar { Q$0 } } | ||
710 | } | ||
711 | "#, | ||
712 | expect![[r#" | ||
713 | ev Self::Bar () | ||
714 | ev Self::Baz () | ||
715 | ev Self::Quux () | ||
716 | ev Foo::Bar () | ||
717 | ev Foo::Baz () | ||
718 | ev Foo::Quux () | ||
719 | sp Self | ||
720 | en Foo | ||
721 | "#]], | 635 | "#]], |
722 | ) | 636 | ) |
723 | } | 637 | } |
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index 263554ecf..5b7ad38d5 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs | |||
@@ -230,7 +230,7 @@ fn foo() { | |||
230 | bar.fo$0; | 230 | bar.fo$0; |
231 | } | 231 | } |
232 | "#, | 232 | "#, |
233 | DetailAndDocumentation { detail: "-> ()", documentation: "Do the foo" }, | 233 | DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" }, |
234 | ); | 234 | ); |
235 | } | 235 | } |
236 | 236 | ||
@@ -255,7 +255,7 @@ fn foo() { | |||
255 | bar.fo$0; | 255 | bar.fo$0; |
256 | } | 256 | } |
257 | "#, | 257 | "#, |
258 | DetailAndDocumentation { detail: "-> ()", documentation: " Do the foo" }, | 258 | DetailAndDocumentation { detail: "fn(&self)", documentation: " Do the foo" }, |
259 | ); | 259 | ); |
260 | } | 260 | } |
261 | 261 | ||
@@ -273,7 +273,7 @@ fn bar() { | |||
273 | for c in fo$0 | 273 | for c in fo$0 |
274 | } | 274 | } |
275 | "#, | 275 | "#, |
276 | DetailAndDocumentation { detail: "-> &str", documentation: "Do the foo" }, | 276 | DetailAndDocumentation { detail: "fn() -> &str", documentation: "Do the foo" }, |
277 | ); | 277 | ); |
278 | } | 278 | } |
279 | } | 279 | } |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 2514dda7c..36655667c 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 | ||
11 | mod builder_ext; | 11 | mod builder_ext; |
12 | 12 | ||
13 | use base_db::Upcast; | ||
14 | use hir::{ | 13 | use hir::{ |
15 | db::HirDatabase, AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, | 14 | AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, |
16 | ScopeDef, Type, | ||
17 | }; | 15 | }; |
18 | use ide_db::{ | 16 | use ide_db::{ |
19 | helpers::{item_name, SnippetCap}, | 17 | helpers::{item_name, SnippetCap}, |
@@ -22,8 +20,8 @@ use ide_db::{ | |||
22 | use syntax::TextRange; | 20 | use syntax::TextRange; |
23 | 21 | ||
24 | use crate::{ | 22 | use crate::{ |
25 | item::{CompletionRelevance, ImportEdit}, | 23 | item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, |
26 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, | 24 | CompletionRelevance, |
27 | }; | 25 | }; |
28 | 26 | ||
29 | use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; | 27 | use 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 | ||
316 | fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> CompletionRelevance { | 309 | fn 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(); | 319 | fn 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 | ||
325 | fn relevance_type_match(db: &dyn HirDatabase, ty: &Type, expected_type: &Type) -> bool { | 325 | fn 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)] |
@@ -432,6 +452,44 @@ fn main() { Foo::Fo$0 } | |||
432 | } | 452 | } |
433 | 453 | ||
434 | #[test] | 454 | #[test] |
455 | fn fn_detail_includes_args_and_return_type() { | ||
456 | check( | ||
457 | r#" | ||
458 | fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) } | ||
459 | |||
460 | fn main() { fo$0 } | ||
461 | "#, | ||
462 | expect![[r#" | ||
463 | [ | ||
464 | CompletionItem { | ||
465 | label: "foo(…)", | ||
466 | source_range: 68..70, | ||
467 | delete: 68..70, | ||
468 | insert: "foo(${1:a}, ${2:b}, ${3:t})$0", | ||
469 | kind: SymbolKind( | ||
470 | Function, | ||
471 | ), | ||
472 | lookup: "foo", | ||
473 | detail: "fn(u32, u32, T) -> (u32, T)", | ||
474 | trigger_call_info: true, | ||
475 | }, | ||
476 | CompletionItem { | ||
477 | label: "main()", | ||
478 | source_range: 68..70, | ||
479 | delete: 68..70, | ||
480 | insert: "main()$0", | ||
481 | kind: SymbolKind( | ||
482 | Function, | ||
483 | ), | ||
484 | lookup: "main", | ||
485 | detail: "fn()", | ||
486 | }, | ||
487 | ] | ||
488 | "#]], | ||
489 | ); | ||
490 | } | ||
491 | |||
492 | #[test] | ||
435 | fn enum_detail_just_parentheses_for_unit() { | 493 | fn enum_detail_just_parentheses_for_unit() { |
436 | check( | 494 | check( |
437 | r#" | 495 | r#" |
@@ -477,6 +535,11 @@ fn main() { let _: m::Spam = S$0 } | |||
477 | ), | 535 | ), |
478 | lookup: "Spam::Bar", | 536 | lookup: "Spam::Bar", |
479 | detail: "(i32)", | 537 | detail: "(i32)", |
538 | relevance: CompletionRelevance { | ||
539 | exact_name_match: false, | ||
540 | exact_type_match: true, | ||
541 | is_local: false, | ||
542 | }, | ||
480 | trigger_call_info: true, | 543 | trigger_call_info: true, |
481 | }, | 544 | }, |
482 | CompletionItem { | 545 | CompletionItem { |
@@ -498,6 +561,11 @@ fn main() { let _: m::Spam = S$0 } | |||
498 | ), | 561 | ), |
499 | lookup: "Spam::Foo", | 562 | lookup: "Spam::Foo", |
500 | detail: "()", | 563 | detail: "()", |
564 | relevance: CompletionRelevance { | ||
565 | exact_name_match: false, | ||
566 | exact_type_match: true, | ||
567 | is_local: false, | ||
568 | }, | ||
501 | }, | 569 | }, |
502 | CompletionItem { | 570 | CompletionItem { |
503 | label: "main()", | 571 | label: "main()", |
@@ -508,7 +576,7 @@ fn main() { let _: m::Spam = S$0 } | |||
508 | Function, | 576 | Function, |
509 | ), | 577 | ), |
510 | lookup: "main", | 578 | lookup: "main", |
511 | detail: "-> ()", | 579 | detail: "fn()", |
512 | }, | 580 | }, |
513 | ] | 581 | ] |
514 | "#]], | 582 | "#]], |
@@ -537,7 +605,7 @@ fn main() { som$0 } | |||
537 | Function, | 605 | Function, |
538 | ), | 606 | ), |
539 | lookup: "main", | 607 | lookup: "main", |
540 | detail: "-> ()", | 608 | detail: "fn()", |
541 | }, | 609 | }, |
542 | CompletionItem { | 610 | CompletionItem { |
543 | label: "something_deprecated()", | 611 | label: "something_deprecated()", |
@@ -548,7 +616,7 @@ fn main() { som$0 } | |||
548 | Function, | 616 | Function, |
549 | ), | 617 | ), |
550 | lookup: "something_deprecated", | 618 | lookup: "something_deprecated", |
551 | detail: "-> ()", | 619 | detail: "fn()", |
552 | deprecated: true, | 620 | deprecated: true, |
553 | }, | 621 | }, |
554 | CompletionItem { | 622 | CompletionItem { |
@@ -560,7 +628,7 @@ fn main() { som$0 } | |||
560 | Function, | 628 | Function, |
561 | ), | 629 | ), |
562 | lookup: "something_else_deprecated", | 630 | lookup: "something_else_deprecated", |
563 | detail: "-> ()", | 631 | detail: "fn()", |
564 | deprecated: true, | 632 | deprecated: true, |
565 | }, | 633 | }, |
566 | ] | 634 | ] |
@@ -611,7 +679,7 @@ impl S { | |||
611 | insert: "bar()$0", | 679 | insert: "bar()$0", |
612 | kind: Method, | 680 | kind: Method, |
613 | lookup: "bar", | 681 | lookup: "bar", |
614 | detail: "-> ()", | 682 | detail: "fn(self)", |
615 | documentation: Documentation( | 683 | documentation: Documentation( |
616 | "Method docs", | 684 | "Method docs", |
617 | ), | 685 | ), |
@@ -711,7 +779,7 @@ fn foo(s: S) { s.$0 } | |||
711 | insert: "the_method()$0", | 779 | insert: "the_method()$0", |
712 | kind: Method, | 780 | kind: Method, |
713 | lookup: "the_method", | 781 | lookup: "the_method", |
714 | detail: "-> ()", | 782 | detail: "fn(&self)", |
715 | }, | 783 | }, |
716 | ] | 784 | ] |
717 | "#]], | 785 | "#]], |
@@ -1019,7 +1087,7 @@ fn main() { | |||
1019 | Function, | 1087 | Function, |
1020 | ), | 1088 | ), |
1021 | lookup: "foo", | 1089 | lookup: "foo", |
1022 | detail: "-> ()", | 1090 | detail: "fn(&mut S)", |
1023 | trigger_call_info: true, | 1091 | trigger_call_info: true, |
1024 | }, | 1092 | }, |
1025 | CompletionItem { | 1093 | CompletionItem { |
@@ -1031,7 +1099,7 @@ fn main() { | |||
1031 | Function, | 1099 | Function, |
1032 | ), | 1100 | ), |
1033 | lookup: "main", | 1101 | lookup: "main", |
1034 | detail: "-> ()", | 1102 | detail: "fn()", |
1035 | }, | 1103 | }, |
1036 | CompletionItem { | 1104 | CompletionItem { |
1037 | label: "s", | 1105 | label: "s", |
@@ -1169,4 +1237,86 @@ fn foo(bar: u32) { | |||
1169 | "#]], | 1237 | "#]], |
1170 | ); | 1238 | ); |
1171 | } | 1239 | } |
1240 | |||
1241 | #[test] | ||
1242 | fn enum_owned() { | ||
1243 | check_relevance( | ||
1244 | r#" | ||
1245 | enum Foo { A, B } | ||
1246 | fn foo() { | ||
1247 | bar($0); | ||
1248 | } | ||
1249 | fn bar(t: Foo) {} | ||
1250 | "#, | ||
1251 | expect![[r#" | ||
1252 | ev Foo::A [type] | ||
1253 | ev Foo::B [type] | ||
1254 | en Foo [] | ||
1255 | fn bar(…) [] | ||
1256 | fn foo() [] | ||
1257 | "#]], | ||
1258 | ); | ||
1259 | } | ||
1260 | |||
1261 | #[test] | ||
1262 | fn enum_ref() { | ||
1263 | check_relevance( | ||
1264 | r#" | ||
1265 | enum Foo { A, B } | ||
1266 | fn foo() { | ||
1267 | bar($0); | ||
1268 | } | ||
1269 | fn bar(t: &Foo) {} | ||
1270 | "#, | ||
1271 | expect![[r#" | ||
1272 | ev Foo::A [] | ||
1273 | ev &Foo::A [type] | ||
1274 | ev Foo::B [] | ||
1275 | ev &Foo::B [type] | ||
1276 | en Foo [] | ||
1277 | fn bar(…) [] | ||
1278 | fn foo() [] | ||
1279 | "#]], | ||
1280 | ); | ||
1281 | } | ||
1282 | |||
1283 | #[test] | ||
1284 | fn suggest_deref_fn_ret() { | ||
1285 | check_relevance( | ||
1286 | r#" | ||
1287 | #[lang = "deref"] | ||
1288 | trait Deref { | ||
1289 | type Target; | ||
1290 | fn deref(&self) -> &Self::Target; | ||
1291 | } | ||
1292 | |||
1293 | struct S; | ||
1294 | struct T(S); | ||
1295 | |||
1296 | impl Deref for T { | ||
1297 | type Target = S; | ||
1298 | |||
1299 | fn deref(&self) -> &Self::Target { | ||
1300 | &self.0 | ||
1301 | } | ||
1302 | } | ||
1303 | |||
1304 | fn foo(s: &S) {} | ||
1305 | fn bar() -> T {} | ||
1306 | |||
1307 | fn main() { | ||
1308 | foo($0); | ||
1309 | } | ||
1310 | "#, | ||
1311 | expect![[r#" | ||
1312 | tt Deref [] | ||
1313 | fn bar() [] | ||
1314 | fn &bar() [type] | ||
1315 | fn foo(…) [] | ||
1316 | st T [] | ||
1317 | st S [] | ||
1318 | fn main() [] | ||
1319 | "#]], | ||
1320 | ) | ||
1321 | } | ||
1172 | } | 1322 | } |
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 | ||
7 | use crate::{ | 7 | use 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 | ||
12 | pub(crate) fn render_variant<'a>( | 13 | pub(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..010303182 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs | |||
@@ -2,11 +2,15 @@ | |||
2 | 2 | ||
3 | use hir::{HasSource, HirDisplay, Type}; | 3 | use hir::{HasSource, HirDisplay, Type}; |
4 | use ide_db::SymbolKind; | 4 | use ide_db::SymbolKind; |
5 | use itertools::Itertools; | ||
5 | use syntax::ast::Fn; | 6 | use syntax::ast::Fn; |
6 | 7 | ||
7 | use crate::{ | 8 | use crate::{ |
8 | item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit}, | 9 | item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit}, |
9 | render::{builder_ext::Params, RenderContext}, | 10 | render::{ |
11 | builder_ext::Params, compute_exact_name_match, compute_exact_type_match, compute_ref_match, | ||
12 | RenderContext, | ||
13 | }, | ||
10 | }; | 14 | }; |
11 | 15 | ||
12 | pub(crate) fn render_fn<'a>( | 16 | pub(crate) fn render_fn<'a>( |
@@ -52,30 +56,60 @@ impl<'a> FunctionRender<'a> { | |||
52 | self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), | 56 | self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), |
53 | ) | 57 | ) |
54 | .detail(self.detail()) | 58 | .detail(self.detail()) |
55 | .add_call_parens(self.ctx.completion, self.name, params) | 59 | .add_call_parens(self.ctx.completion, self.name.clone(), params) |
56 | .add_import(import_to_add); | 60 | .add_import(import_to_add); |
57 | 61 | ||
58 | let mut relevance = CompletionRelevance::default(); | 62 | let ret_type = self.func.ret_type(self.ctx.db()); |
59 | if let Some(expected_type) = &self.ctx.completion.expected_type { | 63 | item.set_relevance(CompletionRelevance { |
60 | let ret_ty = self.func.ret_type(self.ctx.db()); | 64 | exact_type_match: compute_exact_type_match(self.ctx.completion, &ret_type), |
65 | exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()), | ||
66 | ..CompletionRelevance::default() | ||
67 | }); | ||
61 | 68 | ||
62 | // We don't ever consider a function which returns unit type to be an | 69 | 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 | 70 | item.ref_match(ref_match); |
64 | // user. | ||
65 | relevance.exact_type_match = &ret_ty == expected_type && !ret_ty.is_unit(); | ||
66 | } | 71 | } |
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 | 72 | ||
73 | item.build() | 73 | item.build() |
74 | } | 74 | } |
75 | 75 | ||
76 | fn detail(&self) -> String { | 76 | fn detail(&self) -> String { |
77 | let ty = self.func.ret_type(self.ctx.db()); | 77 | let ret_ty = self.func.ret_type(self.ctx.db()); |
78 | format!("-> {}", ty.display(self.ctx.db())) | 78 | let ret = if ret_ty.is_unit() { |
79 | // Omit the return type if it is the unit type | ||
80 | String::new() | ||
81 | } else { | ||
82 | format!(" {}", self.ty_display()) | ||
83 | }; | ||
84 | |||
85 | format!("fn({}){}", self.params_display(), ret) | ||
86 | } | ||
87 | |||
88 | fn params_display(&self) -> String { | ||
89 | if let Some(self_param) = self.func.self_param(self.ctx.db()) { | ||
90 | let params = self | ||
91 | .func | ||
92 | .assoc_fn_params(self.ctx.db()) | ||
93 | .into_iter() | ||
94 | .skip(1) // skip the self param because we are manually handling that | ||
95 | .map(|p| p.ty().display(self.ctx.db()).to_string()); | ||
96 | |||
97 | std::iter::once(self_param.display(self.ctx.db()).to_owned()).chain(params).join(", ") | ||
98 | } else { | ||
99 | let params = self | ||
100 | .func | ||
101 | .assoc_fn_params(self.ctx.db()) | ||
102 | .into_iter() | ||
103 | .map(|p| p.ty().display(self.ctx.db()).to_string()) | ||
104 | .join(", "); | ||
105 | params | ||
106 | } | ||
107 | } | ||
108 | |||
109 | fn ty_display(&self) -> String { | ||
110 | let ret_ty = self.func.ret_type(self.ctx.db()); | ||
111 | |||
112 | format!("-> {}", ret_ty.display(self.ctx.db())) | ||
79 | } | 113 | } |
80 | 114 | ||
81 | fn add_arg(&self, arg: &str, ty: &Type) -> String { | 115 | fn add_arg(&self, arg: &str, ty: &Type) -> String { |
diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs index ca2926125..b4e80f424 100644 --- a/crates/ide_completion/src/render/pattern.rs +++ b/crates/ide_completion/src/render/pattern.rs | |||
@@ -6,24 +6,6 @@ use itertools::Itertools; | |||
6 | 6 | ||
7 | use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind}; | 7 | use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind}; |
8 | 8 | ||
9 | fn visible_fields( | ||
10 | ctx: &RenderContext<'_>, | ||
11 | fields: &[hir::Field], | ||
12 | item: impl HasAttrs, | ||
13 | ) -> Option<(Vec<hir::Field>, bool)> { | ||
14 | let module = ctx.completion.scope.module()?; | ||
15 | let n_fields = fields.len(); | ||
16 | let fields = fields | ||
17 | .into_iter() | ||
18 | .filter(|field| field.is_visible_from(ctx.db(), module)) | ||
19 | .copied() | ||
20 | .collect::<Vec<_>>(); | ||
21 | |||
22 | let fields_omitted = | ||
23 | n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists(); | ||
24 | Some((fields, fields_omitted)) | ||
25 | } | ||
26 | |||
27 | pub(crate) fn render_struct_pat( | 9 | pub(crate) fn render_struct_pat( |
28 | ctx: RenderContext<'_>, | 10 | ctx: RenderContext<'_>, |
29 | strukt: hir::Struct, | 11 | strukt: hir::Struct, |
@@ -148,3 +130,21 @@ fn render_tuple_as_pat(fields: &[hir::Field], name: &str, fields_omitted: bool) | |||
148 | name = name | 130 | name = name |
149 | ) | 131 | ) |
150 | } | 132 | } |
133 | |||
134 | fn visible_fields( | ||
135 | ctx: &RenderContext<'_>, | ||
136 | fields: &[hir::Field], | ||
137 | item: impl HasAttrs, | ||
138 | ) -> Option<(Vec<hir::Field>, bool)> { | ||
139 | let module = ctx.completion.scope.module()?; | ||
140 | let n_fields = fields.len(); | ||
141 | let fields = fields | ||
142 | .into_iter() | ||
143 | .filter(|field| field.is_visible_from(ctx.db(), module)) | ||
144 | .copied() | ||
145 | .collect::<Vec<_>>(); | ||
146 | |||
147 | let fields_omitted = | ||
148 | n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists(); | ||
149 | Some((fields, fields_omitted)) | ||
150 | } | ||
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 | ||
57 | pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { | 57 | pub(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 { | |||
3034 | impl From<MacroCall> for Expr { | 3035 | impl From<MacroCall> for Expr { |
3035 | fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) } | 3036 | fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) } |
3036 | } | 3037 | } |
3038 | impl From<MacroStmts> for Expr { | ||
3039 | fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) } | ||
3040 | } | ||
3037 | impl From<MatchExpr> for Expr { | 3041 | impl 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, |