aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/lib.rs6
-rw-r--r--crates/hir/src/semantics.rs2
-rw-r--r--crates/hir_def/src/body/lower.rs68
-rw-r--r--crates/hir_def/src/expr.rs4
-rw-r--r--crates/hir_def/src/item_tree.rs9
-rw-r--r--crates/hir_def/src/item_tree/lower.rs8
-rw-r--r--crates/hir_expand/src/db.rs59
-rw-r--r--crates/hir_expand/src/name.rs4
-rw-r--r--crates/hir_ty/src/infer.rs5
-rw-r--r--crates/hir_ty/src/infer/expr.rs1
-rw-r--r--crates/hir_ty/src/infer/unify.rs4
-rw-r--r--crates/hir_ty/src/lib.rs2
-rw-r--r--crates/hir_ty/src/tests/macros.rs40
-rw-r--r--crates/ide/src/diagnostics/fixes.rs2
-rw-r--r--crates/ide/src/inlay_hints.rs2
-rw-r--r--crates/ide/src/runnables.rs8
-rw-r--r--crates/ide/src/syntax_highlighting/format.rs2
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_enum_is_method.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_enum_projection_method.rs3
-rw-r--r--crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs5
-rw-r--r--crates/ide_assists/src/utils.rs4
-rw-r--r--crates/ide_completion/src/item.rs59
-rw-r--r--crates/ide_completion/src/render.rs81
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs4
-rw-r--r--crates/ide_completion/src/render/function.rs4
-rw-r--r--crates/ide_db/src/defs.rs2
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs2
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs2
-rw-r--r--crates/ide_ssr/src/resolving.rs2
-rw-r--r--crates/rust-analyzer/src/to_proto.rs2
-rw-r--r--crates/syntax/src/ast/make.rs4
-rw-r--r--crates/syntax/src/ast/node_ext.rs19
-rw-r--r--crates/syntax/src/lib.rs2
-rw-r--r--crates/syntax/src/token_text.rs77
35 files changed, 360 insertions, 142 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 05a60e158..4ee08ef21 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -51,7 +51,7 @@ use hir_def::{
51}; 51};
52use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; 52use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind};
53use hir_ty::{ 53use hir_ty::{
54 autoderef, 54 autoderef, could_unify,
55 method_resolution::{self, TyFingerprint}, 55 method_resolution::{self, TyFingerprint},
56 primitive::UintTy, 56 primitive::UintTy,
57 to_assoc_type_id, 57 to_assoc_type_id,
@@ -2154,6 +2154,10 @@ impl Type {
2154 2154
2155 walk_type(db, self, &mut cb); 2155 walk_type(db, self, &mut cb);
2156 } 2156 }
2157
2158 pub fn could_unify_with(&self, other: &Type) -> bool {
2159 could_unify(&self.ty, &other.ty)
2160 }
2157} 2161}
2158 2162
2159// FIXME: closures 2163// FIXME: closures
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 1198e3f0b..3ff135f41 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -445,7 +445,7 @@ impl<'db> SemanticsImpl<'db> {
445 } 445 }
446 }; 446 };
447 gpl.lifetime_params() 447 gpl.lifetime_params()
448 .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()) == Some(text)) 448 .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()).as_ref() == Some(&text))
449 })?; 449 })?;
450 let src = self.find_file(lifetime_param.syntax().clone()).with_value(lifetime_param); 450 let src = self.find_file(lifetime_param.syntax().clone()).with_value(lifetime_param);
451 ToDef::to_def(self, src) 451 ToDef::to_def(self, src)
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 19f5065d1..229e81dd4 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -74,6 +74,7 @@ pub(super) fn lower(
74 _c: Count::new(), 74 _c: Count::new(),
75 }, 75 },
76 expander, 76 expander,
77 statements_in_scope: Vec::new(),
77 } 78 }
78 .collect(params, body) 79 .collect(params, body)
79} 80}
@@ -83,6 +84,7 @@ struct ExprCollector<'a> {
83 expander: Expander, 84 expander: Expander,
84 body: Body, 85 body: Body,
85 source_map: BodySourceMap, 86 source_map: BodySourceMap,
87 statements_in_scope: Vec<Statement>,
86} 88}
87 89
88impl ExprCollector<'_> { 90impl ExprCollector<'_> {
@@ -533,15 +535,13 @@ impl ExprCollector<'_> {
533 ids[0] 535 ids[0]
534 } 536 }
535 ast::Expr::MacroStmts(e) => { 537 ast::Expr::MacroStmts(e) => {
536 // FIXME: these statements should be held by some hir containter 538 e.statements().for_each(|s| self.collect_stmt(s));
537 for stmt in e.statements() { 539 let tail = e
538 self.collect_stmt(stmt); 540 .expr()
539 } 541 .map(|e| self.collect_expr(e))
540 if let Some(expr) = e.expr() { 542 .unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone()));
541 self.collect_expr(expr) 543
542 } else { 544 self.alloc_expr(Expr::MacroStmts { tail }, syntax_ptr)
543 self.alloc_expr(Expr::Missing, syntax_ptr)
544 }
545 } 545 }
546 }) 546 })
547 } 547 }
@@ -618,58 +618,54 @@ impl ExprCollector<'_> {
618 } 618 }
619 } 619 }
620 620
621 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> { 621 fn collect_stmt(&mut self, s: ast::Stmt) {
622 let stmt = match s { 622 match s {
623 ast::Stmt::LetStmt(stmt) => { 623 ast::Stmt::LetStmt(stmt) => {
624 self.check_cfg(&stmt)?; 624 if self.check_cfg(&stmt).is_none() {
625 625 return;
626 }
626 let pat = self.collect_pat_opt(stmt.pat()); 627 let pat = self.collect_pat_opt(stmt.pat());
627 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 628 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
628 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 629 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
629 vec![Statement::Let { pat, type_ref, initializer }] 630 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
630 } 631 }
631 ast::Stmt::ExprStmt(stmt) => { 632 ast::Stmt::ExprStmt(stmt) => {
632 self.check_cfg(&stmt)?; 633 if self.check_cfg(&stmt).is_none() {
634 return;
635 }
633 636
634 // Note that macro could be expended to multiple statements 637 // Note that macro could be expended to multiple statements
635 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 638 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
636 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 639 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
637 let mut stmts = vec![];
638 640
639 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { 641 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
640 match expansion { 642 match expansion {
641 Some(expansion) => { 643 Some(expansion) => {
642 let statements: ast::MacroStmts = expansion; 644 let statements: ast::MacroStmts = expansion;
643 645
644 statements.statements().for_each(|stmt| { 646 statements.statements().for_each(|stmt| this.collect_stmt(stmt));
645 if let Some(mut r) = this.collect_stmt(stmt) {
646 stmts.append(&mut r);
647 }
648 });
649 if let Some(expr) = statements.expr() { 647 if let Some(expr) = statements.expr() {
650 stmts.push(Statement::Expr(this.collect_expr(expr))); 648 let expr = this.collect_expr(expr);
649 this.statements_in_scope.push(Statement::Expr(expr));
651 } 650 }
652 } 651 }
653 None => { 652 None => {
654 stmts.push(Statement::Expr( 653 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
655 this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 654 this.statements_in_scope.push(Statement::Expr(expr));
656 ));
657 } 655 }
658 } 656 }
659 }); 657 });
660 stmts
661 } else { 658 } else {
662 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] 659 let expr = self.collect_expr_opt(stmt.expr());
660 self.statements_in_scope.push(Statement::Expr(expr));
663 } 661 }
664 } 662 }
665 ast::Stmt::Item(item) => { 663 ast::Stmt::Item(item) => {
666 self.check_cfg(&item)?; 664 if self.check_cfg(&item).is_none() {
667 665 return;
668 return None; 666 }
669 } 667 }
670 }; 668 }
671
672 Some(stmt)
673 } 669 }
674 670
675 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { 671 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
@@ -685,10 +681,12 @@ impl ExprCollector<'_> {
685 let module = if has_def_map { def_map.root() } else { self.expander.module }; 681 let module = if has_def_map { def_map.root() } else { self.expander.module };
686 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); 682 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
687 let prev_local_module = mem::replace(&mut self.expander.module, module); 683 let prev_local_module = mem::replace(&mut self.expander.module, module);
684 let prev_statements = std::mem::take(&mut self.statements_in_scope);
685
686 block.statements().for_each(|s| self.collect_stmt(s));
688 687
689 let statements =
690 block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
691 let tail = block.tail_expr().map(|e| self.collect_expr(e)); 688 let tail = block.tail_expr().map(|e| self.collect_expr(e));
689 let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements);
692 let syntax_node_ptr = AstPtr::new(&block.into()); 690 let syntax_node_ptr = AstPtr::new(&block.into());
693 let expr_id = self.alloc_expr( 691 let expr_id = self.alloc_expr(
694 Expr::Block { id: block_id, statements, tail, label: None }, 692 Expr::Block { id: block_id, statements, tail, label: None },
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index 24be93773..6c7376fad 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -171,6 +171,9 @@ pub enum Expr {
171 Unsafe { 171 Unsafe {
172 body: ExprId, 172 body: ExprId,
173 }, 173 },
174 MacroStmts {
175 tail: ExprId,
176 },
174 Array(Array), 177 Array(Array),
175 Literal(Literal), 178 Literal(Literal),
176} 179}
@@ -357,6 +360,7 @@ impl Expr {
357 f(*repeat) 360 f(*repeat)
358 } 361 }
359 }, 362 },
363 Expr::MacroStmts { tail } => f(*tail),
360 Expr::Literal(_) => {} 364 Expr::Literal(_) => {}
361 } 365 }
362 } 366 }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index ae2475b4e..ca0048b16 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -110,15 +110,6 @@ 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 },
118 ast::Item(item) => {
119 // Macros can expand to stmt and other item, and we add it as top level item
120 ctx.lower_single_item(item)
121 },
122 _ => { 113 _ => {
123 panic!("cannot create item tree from {:?} {}", syntax, syntax); 114 panic!("cannot create item tree from {:?} {}", syntax, syntax);
124 }, 115 },
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index d3fe1ce1e..3f558edd8 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -87,14 +87,6 @@ impl Ctx {
87 self.tree 87 self.tree
88 } 88 }
89 89
90 pub(super) fn lower_single_item(mut self, item: ast::Item) -> ItemTree {
91 self.tree.top_level = self
92 .lower_mod_item(&item, false)
93 .map(|item| item.0)
94 .unwrap_or_else(|| Default::default());
95 self.tree
96 }
97
98 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { 90 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree {
99 self.collect_inner_items(within); 91 self.collect_inner_items(within);
100 self.tree 92 self.tree
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index fc73e435b..d672f6723 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -5,7 +5,13 @@ use std::sync::Arc;
5use base_db::{salsa, SourceDatabase}; 5use base_db::{salsa, SourceDatabase};
6use mbe::{ExpandError, ExpandResult, MacroRules}; 6use mbe::{ExpandError, ExpandResult, MacroRules};
7use parser::FragmentKind; 7use parser::FragmentKind;
8use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; 8use syntax::{
9 algo::diff,
10 ast::{MacroStmts, NameOwner},
11 AstNode, GreenNode, Parse,
12 SyntaxKind::*,
13 SyntaxNode,
14};
9 15
10use crate::{ 16use crate::{
11 ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, 17 ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander,
@@ -340,13 +346,19 @@ fn parse_macro_with_arg(
340 None => return ExpandResult { value: None, err: result.err }, 346 None => return ExpandResult { value: None, err: result.err },
341 }; 347 };
342 348
343 log::debug!("expanded = {}", tt.as_debug_string());
344
345 let fragment_kind = to_fragment_kind(db, macro_call_id); 349 let fragment_kind = to_fragment_kind(db, macro_call_id);
346 350
351 log::debug!("expanded = {}", tt.as_debug_string());
352 log::debug!("kind = {:?}", fragment_kind);
353
347 let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { 354 let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) {
348 Ok(it) => it, 355 Ok(it) => it,
349 Err(err) => { 356 Err(err) => {
357 log::debug!(
358 "failed to parse expanstion to {:?} = {}",
359 fragment_kind,
360 tt.as_debug_string()
361 );
350 return ExpandResult::only_err(err); 362 return ExpandResult::only_err(err);
351 } 363 }
352 }; 364 };
@@ -362,15 +374,34 @@ fn parse_macro_with_arg(
362 return ExpandResult::only_err(err); 374 return ExpandResult::only_err(err);
363 } 375 }
364 }; 376 };
365 377 if is_self_replicating(&node, &call_node.value) {
366 if !diff(&node, &call_node.value).is_empty() {
367 ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) }
368 } else {
369 return ExpandResult::only_err(err); 378 return ExpandResult::only_err(err);
379 } else {
380 ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) }
381 }
382 }
383 None => {
384 log::debug!("parse = {:?}", parse.syntax_node().kind());
385 ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None }
386 }
387 }
388}
389
390fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool {
391 if diff(from, to).is_empty() {
392 return true;
393 }
394 if let Some(stmts) = MacroStmts::cast(from.clone()) {
395 if stmts.statements().any(|stmt| diff(stmt.syntax(), to).is_empty()) {
396 return true;
397 }
398 if let Some(expr) = stmts.expr() {
399 if diff(expr.syntax(), to).is_empty() {
400 return true;
370 } 401 }
371 } 402 }
372 None => ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None },
373 } 403 }
404 false
374} 405}
375 406
376fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { 407fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> {
@@ -390,21 +421,15 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
390 421
391 let parent = match syn.parent() { 422 let parent = match syn.parent() {
392 Some(it) => it, 423 Some(it) => it,
393 None => { 424 None => return FragmentKind::Statements,
394 // FIXME:
395 // If it is root, which means the parent HirFile
396 // MacroKindFile must be non-items
397 // return expr now.
398 return FragmentKind::Expr;
399 }
400 }; 425 };
401 426
402 match parent.kind() { 427 match parent.kind() {
403 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, 428 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
404 MACRO_STMTS => FragmentKind::Statement, 429 MACRO_STMTS => FragmentKind::Statements,
405 ITEM_LIST => FragmentKind::Items, 430 ITEM_LIST => FragmentKind::Items,
406 LET_STMT => { 431 LET_STMT => {
407 // FIXME: Handle Pattern 432 // FIXME: Handle LHS Pattern
408 FragmentKind::Expr 433 FragmentKind::Expr
409 } 434 }
410 EXPR_STMT => FragmentKind::Statements, 435 EXPR_STMT => FragmentKind::Statements,
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 0aeea48d5..cd691b1d2 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -75,14 +75,14 @@ impl AsName for ast::NameRef {
75 fn as_name(&self) -> Name { 75 fn as_name(&self) -> Name {
76 match self.as_tuple_field() { 76 match self.as_tuple_field() {
77 Some(idx) => Name::new_tuple_field(idx), 77 Some(idx) => Name::new_tuple_field(idx),
78 None => Name::resolve(self.text()), 78 None => Name::resolve(&self.text()),
79 } 79 }
80 } 80 }
81} 81}
82 82
83impl AsName for ast::Name { 83impl AsName for ast::Name {
84 fn as_name(&self) -> Name { 84 fn as_name(&self) -> Name {
85 Name::resolve(self.text()) 85 Name::resolve(&self.text())
86 } 86 }
87} 87}
88 88
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 8f9cf7480..e4407ff50 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -45,6 +45,11 @@ use crate::{
45 to_assoc_type_id, to_chalk_trait_id, AliasEq, AliasTy, Interner, TyKind, 45 to_assoc_type_id, to_chalk_trait_id, AliasEq, AliasTy, Interner, TyKind,
46}; 46};
47 47
48// This lint has a false positive here. See the link below for details.
49//
50// https://github.com/rust-lang/rust/issues/57411
51#[allow(unreachable_pub)]
52pub use unify::could_unify;
48pub(crate) use unify::unify; 53pub(crate) use unify::unify;
49 54
50mod unify; 55mod unify;
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 3f3187ea2..e6ede05ca 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -767,6 +767,7 @@ impl<'a> InferenceContext<'a> {
767 None => self.table.new_float_var(), 767 None => self.table.new_float_var(),
768 }, 768 },
769 }, 769 },
770 Expr::MacroStmts { tail } => self.infer_expr(*tail, expected),
770 }; 771 };
771 // use a new type variable if we got unknown here 772 // use a new type variable if we got unknown here
772 let ty = self.insert_type_vars_shallow(ty); 773 let ty = self.insert_type_vars_shallow(ty);
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 75250a369..6e7b0f5a6 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -157,6 +157,10 @@ impl<T> Canonicalized<T> {
157 } 157 }
158} 158}
159 159
160pub fn could_unify(t1: &Ty, t2: &Ty) -> bool {
161 InferenceTable::new().unify(t1, t2)
162}
163
160pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> { 164pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> {
161 let mut table = InferenceTable::new(); 165 let mut table = InferenceTable::new();
162 let vars = Substitution( 166 let vars = Substitution(
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 69265286f..6f9c698e6 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -41,7 +41,7 @@ use crate::{
41}; 41};
42 42
43pub use autoderef::autoderef; 43pub use autoderef::autoderef;
44pub use infer::{InferenceResult, InferenceVar}; 44pub use infer::{could_unify, InferenceResult, InferenceVar};
45pub use lower::{ 45pub use lower::{
46 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, 46 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
47 TyDefId, TyLoweringContext, ValueTyDefId, 47 TyDefId, TyLoweringContext, ValueTyDefId,
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index 7eda51866..01935ec99 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -226,12 +226,49 @@ fn expr_macro_expanded_in_stmts() {
226 "#, 226 "#,
227 expect![[r#" 227 expect![[r#"
228 !0..8 'leta=();': () 228 !0..8 'leta=();': ()
229 !0..8 'leta=();': ()
230 !3..4 'a': ()
231 !5..7 '()': ()
229 57..84 '{ ...); } }': () 232 57..84 '{ ...); } }': ()
230 "#]], 233 "#]],
231 ); 234 );
232} 235}
233 236
234#[test] 237#[test]
238fn recurisve_macro_expanded_in_stmts() {
239 check_infer(
240 r#"
241 macro_rules! ng {
242 ([$($tts:tt)*]) => {
243 $($tts)*;
244 };
245 ([$($tts:tt)*] $head:tt $($rest:tt)*) => {
246 ng! {
247 [$($tts)* $head] $($rest)*
248 }
249 };
250 }
251 fn foo() {
252 ng!([] let a = 3);
253 let b = a;
254 }
255 "#,
256 expect![[r#"
257 !0..7 'leta=3;': {unknown}
258 !0..7 'leta=3;': {unknown}
259 !0..13 'ng!{[leta=3]}': {unknown}
260 !0..13 'ng!{[leta=]3}': {unknown}
261 !0..13 'ng!{[leta]=3}': {unknown}
262 !3..4 'a': i32
263 !5..6 '3': i32
264 196..237 '{ ...= a; }': ()
265 229..230 'b': i32
266 233..234 'a': i32
267 "#]],
268 );
269}
270
271#[test]
235fn recursive_inner_item_macro_rules() { 272fn recursive_inner_item_macro_rules() {
236 check_infer( 273 check_infer(
237 r#" 274 r#"
@@ -246,7 +283,8 @@ fn recursive_inner_item_macro_rules() {
246 "#, 283 "#,
247 expect![[r#" 284 expect![[r#"
248 !0..1 '1': i32 285 !0..1 '1': i32
249 !0..7 'mac!($)': {unknown} 286 !0..26 'macro_...>{1};}': {unknown}
287 !0..26 'macro_...>{1};}': {unknown}
250 107..143 '{ ...!(); }': () 288 107..143 '{ ...!(); }': ()
251 129..130 'a': i32 289 129..130 'a': i32
252 "#]], 290 "#]],
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index 2f840909c..5fb3e2d91 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -210,7 +210,7 @@ fn missing_record_expr_field_fix(
210 } 210 }
211 let new_field = make::record_field( 211 let new_field = make::record_field(
212 None, 212 None,
213 make::name(record_expr_field.field_name()?.text()), 213 make::name(&record_expr_field.field_name()?.text()),
214 make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), 214 make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
215 ); 215 );
216 216
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 16c04eeee..25f96222c 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -416,7 +416,7 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> {
416 match expr { 416 match expr {
417 ast::Expr::MethodCallExpr(method_call_expr) => { 417 ast::Expr::MethodCallExpr(method_call_expr) => {
418 let name_ref = method_call_expr.name_ref()?; 418 let name_ref = method_call_expr.name_ref()?;
419 match name_ref.text() { 419 match name_ref.text().as_str() {
420 "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), 420 "clone" => method_call_expr.receiver().map(|rec| rec.to_string()),
421 name_ref => Some(name_ref.to_owned()), 421 name_ref => Some(name_ref.to_owned()),
422 } 422 }
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 5b488e2c5..7e4c5a078 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -226,7 +226,9 @@ pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) ->
226 let func = def.source(sema.db)?; 226 let func = def.source(sema.db)?;
227 let name_string = def.name(sema.db).to_string(); 227 let name_string = def.name(sema.db).to_string();
228 228
229 let kind = if name_string == "main" { 229 let root = def.krate(sema.db)?.root_module(sema.db);
230
231 let kind = if name_string == "main" && def.module(sema.db) == root {
230 RunnableKind::Bin 232 RunnableKind::Bin
231 } else { 233 } else {
232 let canonical_path = { 234 let canonical_path = {
@@ -444,6 +446,10 @@ fn test_foo() {}
444 446
445#[bench] 447#[bench]
446fn bench() {} 448fn bench() {}
449
450mod not_a_root {
451 fn main() {}
452}
447"#, 453"#,
448 &[&BIN, &TEST, &TEST, &BENCH], 454 &[&BIN, &TEST, &TEST, &BENCH],
449 expect![[r#" 455 expect![[r#"
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs
index e503abc93..5bbadb0f4 100644
--- a/crates/ide/src/syntax_highlighting/format.rs
+++ b/crates/ide/src/syntax_highlighting/format.rs
@@ -31,7 +31,7 @@ fn is_format_string(string: &ast::String) -> Option<()> {
31 let parent = string.syntax().parent()?; 31 let parent = string.syntax().parent()?;
32 32
33 let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; 33 let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?;
34 if !matches!(name.text(), "format_args" | "format_args_nl") { 34 if !matches!(name.text().as_str(), "format_args" | "format_args_nl") {
35 return None; 35 return None;
36 } 36 }
37 37
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index 596c536a7..a8d6355bd 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -195,7 +195,7 @@ fn extract_struct_def(
195 195
196fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Option<()> { 196fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Option<()> {
197 let name = variant.name()?; 197 let name = variant.name()?;
198 let tuple_field = make::tuple_field(None, make::ty(name.text())); 198 let tuple_field = make::tuple_field(None, make::ty(&name.text()));
199 let replacement = make::variant( 199 let replacement = make::variant(
200 name, 200 name,
201 Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))), 201 Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))),
diff --git a/crates/ide_assists/src/handlers/generate_enum_is_method.rs b/crates/ide_assists/src/handlers/generate_enum_is_method.rs
index 7e181a480..a9f71a703 100644
--- a/crates/ide_assists/src/handlers/generate_enum_is_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_is_method.rs
@@ -44,7 +44,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) ->
44 }; 44 };
45 45
46 let enum_lowercase_name = to_lower_snake_case(&parent_enum.name()?.to_string()); 46 let enum_lowercase_name = to_lower_snake_case(&parent_enum.name()?.to_string());
47 let fn_name = format!("is_{}", &to_lower_snake_case(variant_name.text())); 47 let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text()));
48 48
49 // Return early if we've found an existing new fn 49 // Return early if we've found an existing new fn
50 let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?; 50 let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?;
diff --git a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
index 871bcab50..e2f572ba3 100644
--- a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
@@ -132,7 +132,8 @@ fn generate_enum_projection_method(
132 ast::StructKind::Unit => return None, 132 ast::StructKind::Unit => return None,
133 }; 133 };
134 134
135 let fn_name = format!("{}_{}", props.fn_name_prefix, &to_lower_snake_case(variant_name.text())); 135 let fn_name =
136 format!("{}_{}", props.fn_name_prefix, &to_lower_snake_case(&variant_name.text()));
136 137
137 // Return early if we've found an existing new fn 138 // Return early if we've found an existing new fn
138 let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?; 139 let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?;
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
index 4f0ef52ca..f872d20c8 100644
--- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -165,7 +165,7 @@ fn impl_def_from_trait(
165 } 165 }
166 let impl_def = make::impl_trait( 166 let impl_def = make::impl_trait(
167 trait_path.clone(), 167 trait_path.clone(),
168 make::path_unqualified(make::path_segment(make::name_ref(annotated_name.text()))), 168 make::path_unqualified(make::path_segment(make::name_ref(&annotated_name.text()))),
169 ); 169 );
170 let (impl_def, first_assoc_item) = 170 let (impl_def, first_assoc_item) =
171 add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope); 171 add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
@@ -178,12 +178,13 @@ fn update_attribute(
178 trait_name: &ast::NameRef, 178 trait_name: &ast::NameRef,
179 attr: &ast::Attr, 179 attr: &ast::Attr,
180) { 180) {
181 let trait_name = trait_name.text();
181 let new_attr_input = input 182 let new_attr_input = input
182 .syntax() 183 .syntax()
183 .descendants_with_tokens() 184 .descendants_with_tokens()
184 .filter(|t| t.kind() == IDENT) 185 .filter(|t| t.kind() == IDENT)
185 .filter_map(|t| t.into_token().map(|t| t.text().to_string())) 186 .filter_map(|t| t.into_token().map(|t| t.text().to_string()))
186 .filter(|t| t != trait_name.text()) 187 .filter(|t| t != &trait_name)
187 .collect::<Vec<_>>(); 188 .collect::<Vec<_>>();
188 let has_more_derives = !new_attr_input.is_empty(); 189 let has_more_derives = !new_attr_input.is_empty();
189 190
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs
index 728d174db..5f630ec75 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -246,7 +246,7 @@ fn invert_special_case(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Opti
246 let method = mce.name_ref()?; 246 let method = mce.name_ref()?;
247 let arg_list = mce.arg_list()?; 247 let arg_list = mce.arg_list()?;
248 248
249 let method = match method.text() { 249 let method = match method.text().as_str() {
250 "is_some" => "is_none", 250 "is_some" => "is_none",
251 "is_none" => "is_some", 251 "is_none" => "is_some",
252 "is_ok" => "is_err", 252 "is_ok" => "is_err",
@@ -443,7 +443,7 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
443 buf.push_str(trait_text); 443 buf.push_str(trait_text);
444 buf.push_str(" for "); 444 buf.push_str(" for ");
445 } 445 }
446 buf.push_str(adt.name().unwrap().text()); 446 buf.push_str(&adt.name().unwrap().text());
447 if let Some(generic_params) = generic_params { 447 if let Some(generic_params) = generic_params {
448 let lifetime_params = generic_params 448 let lifetime_params = generic_params
449 .lifetime_params() 449 .lifetime_params()
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 9a4b5217a..cc4ac9ea2 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -122,7 +122,7 @@ impl fmt::Debug for CompletionItem {
122 } 122 }
123} 123}
124 124
125#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Default)] 125#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
126pub struct CompletionRelevance { 126pub struct CompletionRelevance {
127 /// This is set in cases like these: 127 /// This is set in cases like these:
128 /// 128 ///
@@ -134,31 +134,41 @@ pub struct CompletionRelevance {
134 /// } 134 /// }
135 /// ``` 135 /// ```
136 pub exact_name_match: bool, 136 pub exact_name_match: bool,
137 /// See CompletionRelevanceTypeMatch doc comments for cases where this is set.
138 pub type_match: Option<CompletionRelevanceTypeMatch>,
137 /// This is set in cases like these: 139 /// This is set in cases like these:
138 /// 140 ///
139 /// ``` 141 /// ```
140 /// fn f(spam: String) {} 142 /// fn foo(a: u32) {
141 /// fn main { 143 /// let b = 0;
142 /// let foo = String::new(); 144 /// $0 // `a` and `b` are local
143 /// f($0) // type of local matches the type of param
144 /// } 145 /// }
145 /// ``` 146 /// ```
146 pub exact_type_match: bool, 147 pub is_local: bool,
148}
149
150#[derive(Debug, Clone, Copy, Eq, PartialEq)]
151pub enum CompletionRelevanceTypeMatch {
147 /// This is set in cases like these: 152 /// This is set in cases like these:
148 /// 153 ///
149 /// ``` 154 /// ```
150 /// fn foo(bar: u32) { 155 /// enum Option<T> { Some(T), None }
151 /// $0 // `bar` is local 156 /// fn f(a: Option<u32>) {}
157 /// fn main {
158 /// f(Option::N$0) // type `Option<T>` could unify with `Option<u32>`
152 /// } 159 /// }
153 /// ``` 160 /// ```
161 CouldUnify,
162 /// This is set in cases like these:
154 /// 163 ///
155 /// ``` 164 /// ```
156 /// fn foo() { 165 /// fn f(spam: String) {}
157 /// let bar = 0; 166 /// fn main {
158 /// $0 // `bar` is local 167 /// let foo = String::new();
168 /// f($0) // type of local matches the type of param
159 /// } 169 /// }
160 /// ``` 170 /// ```
161 pub is_local: bool, 171 Exact,
162} 172}
163 173
164impl CompletionRelevance { 174impl CompletionRelevance {
@@ -177,9 +187,11 @@ impl CompletionRelevance {
177 if self.exact_name_match { 187 if self.exact_name_match {
178 score += 1; 188 score += 1;
179 } 189 }
180 if self.exact_type_match { 190 score += match self.type_match {
181 score += 3; 191 Some(CompletionRelevanceTypeMatch::Exact) => 4,
182 } 192 Some(CompletionRelevanceTypeMatch::CouldUnify) => 3,
193 None => 0,
194 };
183 if self.is_local { 195 if self.is_local {
184 score += 1; 196 score += 1;
185 } 197 }
@@ -342,7 +354,7 @@ impl CompletionItem {
342 // match, but with exact type match set because self.ref_match 354 // match, but with exact type match set because self.ref_match
343 // is only set if there is an exact type match. 355 // is only set if there is an exact type match.
344 let mut relevance = self.relevance; 356 let mut relevance = self.relevance;
345 relevance.exact_type_match = true; 357 relevance.type_match = Some(CompletionRelevanceTypeMatch::Exact);
346 358
347 self.ref_match.map(|mutability| (mutability, relevance)) 359 self.ref_match.map(|mutability| (mutability, relevance))
348 } 360 }
@@ -523,7 +535,7 @@ mod tests {
523 use itertools::Itertools; 535 use itertools::Itertools;
524 use test_utils::assert_eq_text; 536 use test_utils::assert_eq_text;
525 537
526 use super::CompletionRelevance; 538 use super::{CompletionRelevance, CompletionRelevanceTypeMatch};
527 539
528 /// Check that these are CompletionRelevance are sorted in ascending order 540 /// Check that these are CompletionRelevance are sorted in ascending order
529 /// by their relevance score. 541 /// by their relevance score.
@@ -576,15 +588,22 @@ mod tests {
576 is_local: true, 588 is_local: true,
577 ..CompletionRelevance::default() 589 ..CompletionRelevance::default()
578 }], 590 }],
579 vec![CompletionRelevance { exact_type_match: true, ..CompletionRelevance::default() }], 591 vec![CompletionRelevance {
592 type_match: Some(CompletionRelevanceTypeMatch::CouldUnify),
593 ..CompletionRelevance::default()
594 }],
595 vec![CompletionRelevance {
596 type_match: Some(CompletionRelevanceTypeMatch::Exact),
597 ..CompletionRelevance::default()
598 }],
580 vec![CompletionRelevance { 599 vec![CompletionRelevance {
581 exact_name_match: true, 600 exact_name_match: true,
582 exact_type_match: true, 601 type_match: Some(CompletionRelevanceTypeMatch::Exact),
583 ..CompletionRelevance::default() 602 ..CompletionRelevance::default()
584 }], 603 }],
585 vec![CompletionRelevance { 604 vec![CompletionRelevance {
586 exact_name_match: true, 605 exact_name_match: true,
587 exact_type_match: true, 606 type_match: Some(CompletionRelevanceTypeMatch::Exact),
588 is_local: true, 607 is_local: true,
589 }], 608 }],
590 ]; 609 ];
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 9ce49074f..1a762d3dc 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -20,8 +20,8 @@ use ide_db::{
20use syntax::TextRange; 20use syntax::TextRange;
21 21
22use crate::{ 22use crate::{
23 item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, 23 item::{CompletionRelevanceTypeMatch, ImportEdit},
24 CompletionRelevance, 24 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
25}; 25};
26 26
27use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; 27use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro};
@@ -143,7 +143,7 @@ impl<'a> Render<'a> {
143 .set_deprecated(is_deprecated); 143 .set_deprecated(is_deprecated);
144 144
145 item.set_relevance(CompletionRelevance { 145 item.set_relevance(CompletionRelevance {
146 exact_type_match: compute_exact_type_match(self.ctx.completion, ty), 146 type_match: compute_type_match(self.ctx.completion, ty),
147 exact_name_match: compute_exact_name_match(self.ctx.completion, name.to_string()), 147 exact_name_match: compute_exact_name_match(self.ctx.completion, name.to_string()),
148 ..CompletionRelevance::default() 148 ..CompletionRelevance::default()
149 }); 149 });
@@ -245,7 +245,7 @@ impl<'a> Render<'a> {
245 } 245 }
246 246
247 item.set_relevance(CompletionRelevance { 247 item.set_relevance(CompletionRelevance {
248 exact_type_match: compute_exact_type_match(self.ctx.completion, &ty), 248 type_match: compute_type_match(self.ctx.completion, &ty),
249 exact_name_match: compute_exact_name_match(self.ctx.completion, &local_name), 249 exact_name_match: compute_exact_name_match(self.ctx.completion, &local_name),
250 is_local: true, 250 is_local: true,
251 ..CompletionRelevance::default() 251 ..CompletionRelevance::default()
@@ -309,14 +309,24 @@ impl<'a> Render<'a> {
309 } 309 }
310} 310}
311 311
312fn compute_exact_type_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> bool { 312fn compute_type_match(
313 match ctx.expected_type.as_ref() { 313 ctx: &CompletionContext,
314 Some(expected_type) => { 314 completion_ty: &hir::Type,
315 // We don't ever consider unit type to be an exact type match, since 315) -> Option<CompletionRelevanceTypeMatch> {
316 // nearly always this is not meaningful to the user. 316 let expected_type = ctx.expected_type.as_ref()?;
317 completion_ty == expected_type && !expected_type.is_unit() 317
318 } 318 // We don't ever consider unit type to be an exact type match, since
319 None => false, 319 // nearly always this is not meaningful to the user.
320 if expected_type.is_unit() {
321 return None;
322 }
323
324 if completion_ty == expected_type {
325 Some(CompletionRelevanceTypeMatch::Exact)
326 } else if expected_type.could_unify_with(completion_ty) {
327 Some(CompletionRelevanceTypeMatch::CouldUnify)
328 } else {
329 None
320 } 330 }
321} 331}
322 332
@@ -348,6 +358,7 @@ mod tests {
348 use itertools::Itertools; 358 use itertools::Itertools;
349 359
350 use crate::{ 360 use crate::{
361 item::CompletionRelevanceTypeMatch,
351 test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, 362 test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG},
352 CompletionKind, CompletionRelevance, 363 CompletionKind, CompletionRelevance,
353 }; 364 };
@@ -360,7 +371,11 @@ mod tests {
360 fn check_relevance(ra_fixture: &str, expect: Expect) { 371 fn check_relevance(ra_fixture: &str, expect: Expect) {
361 fn display_relevance(relevance: CompletionRelevance) -> String { 372 fn display_relevance(relevance: CompletionRelevance) -> String {
362 let relevance_factors = vec![ 373 let relevance_factors = vec![
363 (relevance.exact_type_match, "type"), 374 (relevance.type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"),
375 (
376 relevance.type_match == Some(CompletionRelevanceTypeMatch::CouldUnify),
377 "type_could_unify",
378 ),
364 (relevance.exact_name_match, "name"), 379 (relevance.exact_name_match, "name"),
365 (relevance.is_local, "local"), 380 (relevance.is_local, "local"),
366 ] 381 ]
@@ -533,7 +548,9 @@ fn main() { let _: m::Spam = S$0 }
533 detail: "(i32)", 548 detail: "(i32)",
534 relevance: CompletionRelevance { 549 relevance: CompletionRelevance {
535 exact_name_match: false, 550 exact_name_match: false,
536 exact_type_match: true, 551 type_match: Some(
552 Exact,
553 ),
537 is_local: false, 554 is_local: false,
538 }, 555 },
539 trigger_call_info: true, 556 trigger_call_info: true,
@@ -559,7 +576,9 @@ fn main() { let _: m::Spam = S$0 }
559 detail: "()", 576 detail: "()",
560 relevance: CompletionRelevance { 577 relevance: CompletionRelevance {
561 exact_name_match: false, 578 exact_name_match: false,
562 exact_type_match: true, 579 type_match: Some(
580 Exact,
581 ),
563 is_local: false, 582 is_local: false,
564 }, 583 },
565 }, 584 },
@@ -1108,7 +1127,7 @@ fn main() {
1108 detail: "S", 1127 detail: "S",
1109 relevance: CompletionRelevance { 1128 relevance: CompletionRelevance {
1110 exact_name_match: true, 1129 exact_name_match: true,
1111 exact_type_match: false, 1130 type_match: None,
1112 is_local: true, 1131 is_local: true,
1113 }, 1132 },
1114 ref_match: "&mut ", 1133 ref_match: "&mut ",
@@ -1353,4 +1372,34 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
1353 "#]], 1372 "#]],
1354 ); 1373 );
1355 } 1374 }
1375
1376 #[test]
1377 fn generic_enum() {
1378 check_relevance(
1379 r#"
1380enum Foo<T> { A(T), B }
1381// bar() should not be an exact type match
1382// because the generic parameters are different
1383fn bar() -> Foo<u8> { Foo::B }
1384// FIXME baz() should be an exact type match
1385// because the types could unify, but it currently
1386// is not. This is due to the T here being
1387// TyKind::Placeholder rather than TyKind::Missing.
1388fn baz<T>() -> Foo<T> { Foo::B }
1389fn foo() {
1390 let foo: Foo<u32> = Foo::B;
1391 let _: Foo<u32> = f$0;
1392}
1393"#,
1394 expect![[r#"
1395 ev Foo::A(…) [type_could_unify]
1396 ev Foo::B [type_could_unify]
1397 lc foo [type+local]
1398 en Foo []
1399 fn baz() []
1400 fn bar() []
1401 fn foo() []
1402 "#]],
1403 );
1404 }
1356} 1405}
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs
index 374247b05..832f5ced1 100644
--- a/crates/ide_completion/src/render/enum_variant.rs
+++ b/crates/ide_completion/src/render/enum_variant.rs
@@ -6,7 +6,7 @@ use itertools::Itertools;
6 6
7use crate::{ 7use crate::{
8 item::{CompletionItem, CompletionKind, ImportEdit}, 8 item::{CompletionItem, CompletionKind, ImportEdit},
9 render::{builder_ext::Params, compute_exact_type_match, compute_ref_match, RenderContext}, 9 render::{builder_ext::Params, compute_ref_match, compute_type_match, RenderContext},
10 CompletionRelevance, 10 CompletionRelevance,
11}; 11};
12 12
@@ -77,7 +77,7 @@ impl<'a> EnumRender<'a> {
77 77
78 let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db); 78 let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db);
79 item.set_relevance(CompletionRelevance { 79 item.set_relevance(CompletionRelevance {
80 exact_type_match: compute_exact_type_match(self.ctx.completion, &ty), 80 type_match: compute_type_match(self.ctx.completion, &ty),
81 ..CompletionRelevance::default() 81 ..CompletionRelevance::default()
82 }); 82 });
83 83
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index b1eba20e8..d681e2c91 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -8,7 +8,7 @@ use syntax::ast::Fn;
8use crate::{ 8use crate::{
9 item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit}, 9 item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit},
10 render::{ 10 render::{
11 builder_ext::Params, compute_exact_name_match, compute_exact_type_match, compute_ref_match, 11 builder_ext::Params, compute_exact_name_match, compute_ref_match, compute_type_match,
12 RenderContext, 12 RenderContext,
13 }, 13 },
14}; 14};
@@ -73,7 +73,7 @@ impl<'a> FunctionRender<'a> {
73 73
74 let ret_type = self.func.ret_type(self.ctx.db()); 74 let ret_type = self.func.ret_type(self.ctx.db());
75 item.set_relevance(CompletionRelevance { 75 item.set_relevance(CompletionRelevance {
76 exact_type_match: compute_exact_type_match(self.ctx.completion, &ret_type), 76 type_match: compute_type_match(self.ctx.completion, &ret_type),
77 exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()), 77 exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()),
78 ..CompletionRelevance::default() 78 ..CompletionRelevance::default()
79 }); 79 });
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index 75167ff39..ab23dd7ac 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -343,7 +343,7 @@ impl NameRefClass {
343 hir::AssocItem::TypeAlias(it) => Some(*it), 343 hir::AssocItem::TypeAlias(it) => Some(*it),
344 _ => None, 344 _ => None,
345 }) 345 })
346 .find(|alias| &alias.name(sema.db).to_string() == name_ref.text()) 346 .find(|alias| &alias.name(sema.db).to_string() == &name_ref.text())
347 { 347 {
348 return Some(NameRefClass::Definition(Definition::ModuleDef( 348 return Some(NameRefClass::Definition(Definition::ModuleDef(
349 ModuleDef::TypeAlias(ty), 349 ModuleDef::TypeAlias(ty),
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 1881c746f..3deb0d159 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -288,7 +288,7 @@ fn path_applicable_imports(
288 import_for_item( 288 import_for_item(
289 sema.db, 289 sema.db,
290 mod_path, 290 mod_path,
291 unresolved_first_segment, 291 &unresolved_first_segment,
292 &unresolved_qualifier, 292 &unresolved_qualifier,
293 item, 293 item,
294 ) 294 )
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index 20c195f82..e681ced80 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -509,7 +509,7 @@ impl ImportGroup {
509 PathSegmentKind::SelfKw => ImportGroup::ThisModule, 509 PathSegmentKind::SelfKw => ImportGroup::ThisModule,
510 PathSegmentKind::SuperKw => ImportGroup::SuperModule, 510 PathSegmentKind::SuperKw => ImportGroup::SuperModule,
511 PathSegmentKind::CrateKw => ImportGroup::ThisCrate, 511 PathSegmentKind::CrateKw => ImportGroup::ThisCrate,
512 PathSegmentKind::Name(name) => match name.text() { 512 PathSegmentKind::Name(name) => match name.text().as_str() {
513 "std" => ImportGroup::Std, 513 "std" => ImportGroup::Std,
514 "core" => ImportGroup::Std, 514 "core" => ImportGroup::Std,
515 _ => ImportGroup::ExternCrate, 515 _ => ImportGroup::ExternCrate,
diff --git a/crates/ide_ssr/src/resolving.rs b/crates/ide_ssr/src/resolving.rs
index dc7835473..541da4122 100644
--- a/crates/ide_ssr/src/resolving.rs
+++ b/crates/ide_ssr/src/resolving.rs
@@ -150,7 +150,7 @@ impl Resolver<'_, '_> {
150 fn path_contains_placeholder(&self, path: &ast::Path) -> bool { 150 fn path_contains_placeholder(&self, path: &ast::Path) -> bool {
151 if let Some(segment) = path.segment() { 151 if let Some(segment) = path.segment() {
152 if let Some(name_ref) = segment.name_ref() { 152 if let Some(name_ref) = segment.name_ref() {
153 if self.placeholders_by_stand_in.contains_key(name_ref.text()) { 153 if self.placeholders_by_stand_in.contains_key(name_ref.text().as_str()) {
154 return true; 154 return true;
155 } 155 }
156 } 156 }
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 25169005f..530c8a5a4 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -1138,7 +1138,7 @@ mod tests {
1138 ( 1138 (
1139 "&arg", 1139 "&arg",
1140 Some( 1140 Some(
1141 "fffffffa", 1141 "fffffff9",
1142 ), 1142 ),
1143 ), 1143 ),
1144 ( 1144 (
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index c08f2c14f..c6a7b99b7 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -268,14 +268,14 @@ pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
268} 268}
269 269
270pub fn ident_pat(name: ast::Name) -> ast::IdentPat { 270pub fn ident_pat(name: ast::Name) -> ast::IdentPat {
271 return from_text(name.text()); 271 return from_text(&name.text());
272 272
273 fn from_text(text: &str) -> ast::IdentPat { 273 fn from_text(text: &str) -> ast::IdentPat {
274 ast_from_text(&format!("fn f({}: ())", text)) 274 ast_from_text(&format!("fn f({}: ())", text))
275 } 275 }
276} 276}
277pub fn ident_mut_pat(name: ast::Name) -> ast::IdentPat { 277pub fn ident_mut_pat(name: ast::Name) -> ast::IdentPat {
278 return from_text(name.text()); 278 return from_text(&name.text());
279 279
280 fn from_text(text: &str) -> ast::IdentPat { 280 fn from_text(text: &str) -> ast::IdentPat {
281 ast_from_text(&format!("fn f(mut {}: ())", text)) 281 ast_from_text(&format!("fn f(mut {}: ())", text))
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index bdf907a21..2772d7364 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -8,23 +8,23 @@ use parser::SyntaxKind;
8 8
9use crate::{ 9use crate::{
10 ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, 10 ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode},
11 SmolStr, SyntaxElement, SyntaxToken, T, 11 SmolStr, SyntaxElement, SyntaxToken, TokenText, T,
12}; 12};
13 13
14impl ast::Lifetime { 14impl ast::Lifetime {
15 pub fn text(&self) -> &str { 15 pub fn text(&self) -> TokenText {
16 text_of_first_token(self.syntax()) 16 text_of_first_token(self.syntax())
17 } 17 }
18} 18}
19 19
20impl ast::Name { 20impl ast::Name {
21 pub fn text(&self) -> &str { 21 pub fn text(&self) -> TokenText {
22 text_of_first_token(self.syntax()) 22 text_of_first_token(self.syntax())
23 } 23 }
24} 24}
25 25
26impl ast::NameRef { 26impl ast::NameRef {
27 pub fn text(&self) -> &str { 27 pub fn text(&self) -> TokenText {
28 text_of_first_token(self.syntax()) 28 text_of_first_token(self.syntax())
29 } 29 }
30 30
@@ -33,10 +33,11 @@ impl ast::NameRef {
33 } 33 }
34} 34}
35 35
36fn text_of_first_token(node: &SyntaxNode) -> &str { 36fn text_of_first_token(node: &SyntaxNode) -> TokenText {
37 let t = 37 let first_token =
38 node.green().children().next().and_then(|it| it.into_token()).unwrap().text().to_string(); 38 node.green().children().next().and_then(|it| it.into_token()).unwrap().to_owned();
39 Box::leak(Box::new(t)) 39
40 TokenText(first_token)
40} 41}
41 42
42pub enum Macro { 43pub enum Macro {
@@ -378,7 +379,7 @@ impl fmt::Display for NameOrNameRef {
378} 379}
379 380
380impl NameOrNameRef { 381impl NameOrNameRef {
381 pub fn text(&self) -> &str { 382 pub fn text(&self) -> TokenText {
382 match self { 383 match self {
383 NameOrNameRef::Name(name) => name.text(), 384 NameOrNameRef::Name(name) => name.text(),
384 NameOrNameRef::NameRef(name_ref) => name_ref.text(), 385 NameOrNameRef::NameRef(name_ref) => name_ref.text(),
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index 2a5c61171..90de6bef6 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -29,6 +29,7 @@ mod syntax_error;
29mod parsing; 29mod parsing;
30mod validation; 30mod validation;
31mod ptr; 31mod ptr;
32mod token_text;
32#[cfg(test)] 33#[cfg(test)]
33mod tests; 34mod tests;
34 35
@@ -55,6 +56,7 @@ pub use crate::{
55 SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, SyntaxToken, 56 SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, SyntaxToken,
56 SyntaxTreeBuilder, 57 SyntaxTreeBuilder,
57 }, 58 },
59 token_text::TokenText,
58}; 60};
59pub use parser::{SyntaxKind, T}; 61pub use parser::{SyntaxKind, T};
60pub use rowan::{ 62pub use rowan::{
diff --git a/crates/syntax/src/token_text.rs b/crates/syntax/src/token_text.rs
new file mode 100644
index 000000000..d2ed0a12a
--- /dev/null
+++ b/crates/syntax/src/token_text.rs
@@ -0,0 +1,77 @@
1//! Yet another version of owned string, backed by a syntax tree token.
2
3use std::{cmp::Ordering, fmt, ops};
4
5pub struct TokenText(pub(crate) rowan::GreenToken);
6
7impl TokenText {
8 pub fn as_str(&self) -> &str {
9 self.0.text()
10 }
11}
12
13impl ops::Deref for TokenText {
14 type Target = str;
15
16 fn deref(&self) -> &str {
17 self.as_str()
18 }
19}
20impl AsRef<str> for TokenText {
21 fn as_ref(&self) -> &str {
22 self.as_str()
23 }
24}
25
26impl From<TokenText> for String {
27 fn from(token_text: TokenText) -> Self {
28 token_text.as_str().into()
29 }
30}
31
32impl PartialEq<&'_ str> for TokenText {
33 fn eq(&self, other: &&str) -> bool {
34 self.as_str() == *other
35 }
36}
37impl PartialEq<TokenText> for &'_ str {
38 fn eq(&self, other: &TokenText) -> bool {
39 other == self
40 }
41}
42impl PartialEq<String> for TokenText {
43 fn eq(&self, other: &String) -> bool {
44 self.as_str() == other.as_str()
45 }
46}
47impl PartialEq<TokenText> for String {
48 fn eq(&self, other: &TokenText) -> bool {
49 other == self
50 }
51}
52impl PartialEq for TokenText {
53 fn eq(&self, other: &TokenText) -> bool {
54 self.as_str() == other.as_str()
55 }
56}
57impl Eq for TokenText {}
58impl Ord for TokenText {
59 fn cmp(&self, other: &Self) -> Ordering {
60 self.as_str().cmp(other.as_str())
61 }
62}
63impl PartialOrd for TokenText {
64 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
65 Some(self.cmp(other))
66 }
67}
68impl fmt::Display for TokenText {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 fmt::Display::fmt(self.as_str(), f)
71 }
72}
73impl fmt::Debug for TokenText {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 fmt::Debug::fmt(self.as_str(), f)
76 }
77}