aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/base_db/src/fixture.rs3
-rw-r--r--crates/base_db/src/input.rs13
-rw-r--r--crates/cfg/src/lib.rs37
-rw-r--r--crates/hir/src/lib.rs46
-rw-r--r--crates/hir_def/src/body/lower.rs7
-rw-r--r--crates/hir_def/src/body/tests.rs9
-rw-r--r--crates/hir_def/src/generics.rs5
-rw-r--r--crates/hir_def/src/item_scope.rs6
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs6
-rw-r--r--crates/hir_def/src/nameres.rs5
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs2
-rw-r--r--crates/hir_def/src/path.rs2
-rw-r--r--crates/hir_def/src/resolver.rs12
-rw-r--r--crates/hir_expand/src/builtin_macro.rs7
-rw-r--r--crates/hir_expand/src/eager.rs6
-rw-r--r--crates/hir_ty/src/chalk_db.rs5
-rw-r--r--crates/hir_ty/src/test_db.rs10
-rw-r--r--crates/hir_ty/src/tests.rs235
-rw-r--r--crates/hir_ty/src/tests/coercion.rs673
-rw-r--r--crates/hir_ty/src/tests/display_source_code.rs10
-rw-r--r--crates/hir_ty/src/tests/macros.rs29
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs264
-rw-r--r--crates/hir_ty/src/tests/patterns.rs4
-rw-r--r--crates/hir_ty/src/tests/regression.rs11
-rw-r--r--crates/hir_ty/src/tests/simple.rs18
-rw-r--r--crates/hir_ty/src/tests/traits.rs244
-rw-r--r--crates/ide/src/hover.rs276
-rw-r--r--crates/ide/src/lib.rs8
-rw-r--r--crates/ide/src/rename.rs46
-rw-r--r--crates/ide/src/typing.rs36
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs26
-rw-r--r--crates/ide_completion/src/completions/attribute.rs15
-rw-r--r--crates/ide_completion/src/completions/attribute/cfg.rs112
-rw-r--r--crates/ide_completion/src/completions/keyword.rs28
-rw-r--r--crates/ide_completion/src/completions/pattern.rs395
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs76
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs147
-rw-r--r--crates/ide_completion/src/context.rs72
-rw-r--r--crates/ide_completion/src/patterns.rs9
-rw-r--r--crates/ide_completion/src/render.rs75
-rw-r--r--crates/ide_completion/src/tests.rs15
-rw-r--r--crates/ide_completion/src/tests/items.rs32
-rw-r--r--crates/ide_completion/src/tests/pattern.rs348
-rw-r--r--crates/ide_completion/src/tests/type_pos.rs177
-rw-r--r--crates/mbe/src/expander/matcher.rs8
-rw-r--r--crates/mbe/src/expander/transcriber.rs2
-rw-r--r--crates/mbe/src/lib.rs10
-rw-r--r--crates/mbe/src/subtree_source.rs2
-rw-r--r--crates/mbe/src/syntax_bridge.rs2
-rw-r--r--crates/mbe/src/tt_iter.rs9
-rw-r--r--crates/proc_macro_srv/src/rustc_server.rs4
-rw-r--r--crates/proc_macro_test/build.rs14
-rw-r--r--crates/project_model/src/cargo_workspace.rs17
-rw-r--r--crates/project_model/src/lib.rs2
-rw-r--r--crates/project_model/src/sysroot.rs11
-rw-r--r--crates/project_model/src/workspace.rs135
-rw-r--r--crates/rust-analyzer/src/config.rs102
-rw-r--r--crates/rust-analyzer/src/handlers.rs26
-rw-r--r--crates/syntax/src/ptr.rs2
-rw-r--r--crates/test_utils/src/lib.rs50
60 files changed, 1874 insertions, 2084 deletions
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 6ce377710..7d5d12e63 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -128,6 +128,7 @@ impl ChangeFixture {
128 file_id, 128 file_id,
129 meta.edition, 129 meta.edition,
130 Some(crate_name.clone().into()), 130 Some(crate_name.clone().into()),
131 meta.cfg.clone(),
131 meta.cfg, 132 meta.cfg,
132 meta.env, 133 meta.env,
133 Default::default(), 134 Default::default(),
@@ -157,6 +158,7 @@ impl ChangeFixture {
157 crate_root, 158 crate_root,
158 Edition::Edition2018, 159 Edition::Edition2018,
159 Some(CrateName::new("test").unwrap().into()), 160 Some(CrateName::new("test").unwrap().into()),
161 default_cfg.clone(),
160 default_cfg, 162 default_cfg,
161 Env::default(), 163 Env::default(),
162 Default::default(), 164 Default::default(),
@@ -186,6 +188,7 @@ impl ChangeFixture {
186 Edition::Edition2021, 188 Edition::Edition2021,
187 Some(CrateDisplayName::from_canonical_name("core".to_string())), 189 Some(CrateDisplayName::from_canonical_name("core".to_string())),
188 CfgOptions::default(), 190 CfgOptions::default(),
191 CfgOptions::default(),
189 Env::default(), 192 Env::default(),
190 Vec::new(), 193 Vec::new(),
191 ); 194 );
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 23cb0c839..0c51a59a0 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -189,6 +189,7 @@ pub struct CrateData {
189 /// `Dependency` matters), this name should only be used for UI. 189 /// `Dependency` matters), this name should only be used for UI.
190 pub display_name: Option<CrateDisplayName>, 190 pub display_name: Option<CrateDisplayName>,
191 pub cfg_options: CfgOptions, 191 pub cfg_options: CfgOptions,
192 pub potential_cfg_options: CfgOptions,
192 pub env: Env, 193 pub env: Env,
193 pub dependencies: Vec<Dependency>, 194 pub dependencies: Vec<Dependency>,
194 pub proc_macro: Vec<ProcMacro>, 195 pub proc_macro: Vec<ProcMacro>,
@@ -219,6 +220,7 @@ impl CrateGraph {
219 edition: Edition, 220 edition: Edition,
220 display_name: Option<CrateDisplayName>, 221 display_name: Option<CrateDisplayName>,
221 cfg_options: CfgOptions, 222 cfg_options: CfgOptions,
223 potential_cfg_options: CfgOptions,
222 env: Env, 224 env: Env,
223 proc_macro: Vec<ProcMacro>, 225 proc_macro: Vec<ProcMacro>,
224 ) -> CrateId { 226 ) -> CrateId {
@@ -227,6 +229,7 @@ impl CrateGraph {
227 edition, 229 edition,
228 display_name, 230 display_name,
229 cfg_options, 231 cfg_options,
232 potential_cfg_options,
230 env, 233 env,
231 proc_macro, 234 proc_macro,
232 dependencies: Vec::new(), 235 dependencies: Vec::new(),
@@ -504,6 +507,7 @@ mod tests {
504 Edition2018, 507 Edition2018,
505 None, 508 None,
506 CfgOptions::default(), 509 CfgOptions::default(),
510 CfgOptions::default(),
507 Env::default(), 511 Env::default(),
508 Default::default(), 512 Default::default(),
509 ); 513 );
@@ -512,6 +516,7 @@ mod tests {
512 Edition2018, 516 Edition2018,
513 None, 517 None,
514 CfgOptions::default(), 518 CfgOptions::default(),
519 CfgOptions::default(),
515 Env::default(), 520 Env::default(),
516 Default::default(), 521 Default::default(),
517 ); 522 );
@@ -520,6 +525,7 @@ mod tests {
520 Edition2018, 525 Edition2018,
521 None, 526 None,
522 CfgOptions::default(), 527 CfgOptions::default(),
528 CfgOptions::default(),
523 Env::default(), 529 Env::default(),
524 Default::default(), 530 Default::default(),
525 ); 531 );
@@ -536,6 +542,7 @@ mod tests {
536 Edition2018, 542 Edition2018,
537 None, 543 None,
538 CfgOptions::default(), 544 CfgOptions::default(),
545 CfgOptions::default(),
539 Env::default(), 546 Env::default(),
540 Default::default(), 547 Default::default(),
541 ); 548 );
@@ -544,6 +551,7 @@ mod tests {
544 Edition2018, 551 Edition2018,
545 None, 552 None,
546 CfgOptions::default(), 553 CfgOptions::default(),
554 CfgOptions::default(),
547 Env::default(), 555 Env::default(),
548 Default::default(), 556 Default::default(),
549 ); 557 );
@@ -559,6 +567,7 @@ mod tests {
559 Edition2018, 567 Edition2018,
560 None, 568 None,
561 CfgOptions::default(), 569 CfgOptions::default(),
570 CfgOptions::default(),
562 Env::default(), 571 Env::default(),
563 Default::default(), 572 Default::default(),
564 ); 573 );
@@ -567,6 +576,7 @@ mod tests {
567 Edition2018, 576 Edition2018,
568 None, 577 None,
569 CfgOptions::default(), 578 CfgOptions::default(),
579 CfgOptions::default(),
570 Env::default(), 580 Env::default(),
571 Default::default(), 581 Default::default(),
572 ); 582 );
@@ -575,6 +585,7 @@ mod tests {
575 Edition2018, 585 Edition2018,
576 None, 586 None,
577 CfgOptions::default(), 587 CfgOptions::default(),
588 CfgOptions::default(),
578 Env::default(), 589 Env::default(),
579 Default::default(), 590 Default::default(),
580 ); 591 );
@@ -590,6 +601,7 @@ mod tests {
590 Edition2018, 601 Edition2018,
591 None, 602 None,
592 CfgOptions::default(), 603 CfgOptions::default(),
604 CfgOptions::default(),
593 Env::default(), 605 Env::default(),
594 Default::default(), 606 Default::default(),
595 ); 607 );
@@ -598,6 +610,7 @@ mod tests {
598 Edition2018, 610 Edition2018,
599 None, 611 None,
600 CfgOptions::default(), 612 CfgOptions::default(),
613 CfgOptions::default(),
601 Env::default(), 614 Env::default(),
602 Default::default(), 615 Default::default(),
603 ); 616 );
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index 03b8dd767..9a4baa636 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -1,4 +1,4 @@
1//! cfg defines conditional compiling options, `cfg` attibute parser and evaluator 1//! cfg defines conditional compiling options, `cfg` attribute parser and evaluator
2 2
3mod cfg_expr; 3mod cfg_expr;
4mod dnf; 4mod dnf;
@@ -50,8 +50,29 @@ impl CfgOptions {
50 self.enabled.remove(&atom); 50 self.enabled.remove(&atom);
51 } 51 }
52 } 52 }
53
54 pub fn get_cfg_keys(&self) -> Vec<&SmolStr> {
55 self.enabled
56 .iter()
57 .map(|x| match x {
58 CfgAtom::Flag(key) => key,
59 CfgAtom::KeyValue { key, .. } => key,
60 })
61 .collect()
62 }
63
64 pub fn get_cfg_values(&self, cfg_key: &str) -> Vec<&SmolStr> {
65 self.enabled
66 .iter()
67 .filter_map(|x| match x {
68 CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value),
69 _ => None,
70 })
71 .collect()
72 }
53} 73}
54 74
75#[derive(Clone, Debug, PartialEq, Eq)]
55pub struct CfgDiff { 76pub struct CfgDiff {
56 // Invariants: No duplicates, no atom that's both in `enable` and `disable`. 77 // Invariants: No duplicates, no atom that's both in `enable` and `disable`.
57 enable: Vec<CfgAtom>, 78 enable: Vec<CfgAtom>,
@@ -59,6 +80,20 @@ pub struct CfgDiff {
59} 80}
60 81
61impl CfgDiff { 82impl CfgDiff {
83 /// Create a new CfgDiff. Will return None if the same item appears more than once in the set
84 /// of both.
85 pub fn new(enable: Vec<CfgAtom>, disable: Vec<CfgAtom>) -> Option<CfgDiff> {
86 let mut occupied = FxHashSet::default();
87 for item in enable.iter().chain(disable.iter()) {
88 if !occupied.insert(item) {
89 // was present
90 return None;
91 }
92 }
93
94 Some(CfgDiff { enable, disable })
95 }
96
62 /// Returns the total number of atoms changed by this diff. 97 /// Returns the total number of atoms changed by this diff.
63 pub fn len(&self) -> usize { 98 pub fn len(&self) -> usize {
64 self.enable.len() + self.disable.len() 99 self.enable.len() + self.disable.len()
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b7eabaabb..30cc34403 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -219,8 +219,7 @@ impl Crate {
219 let doc_url = doc_attr_q.tt_values().map(|tt| { 219 let doc_url = doc_attr_q.tt_values().map(|tt| {
220 let name = tt.token_trees.iter() 220 let name = tt.token_trees.iter()
221 .skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url")) 221 .skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url"))
222 .skip(2) 222 .nth(2);
223 .next();
224 223
225 match name { 224 match name {
226 Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text), 225 Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text),
@@ -234,6 +233,10 @@ impl Crate {
234 pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions { 233 pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
235 db.crate_graph()[self.id].cfg_options.clone() 234 db.crate_graph()[self.id].cfg_options.clone()
236 } 235 }
236
237 pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
238 db.crate_graph()[self.id].potential_cfg_options.clone()
239 }
237} 240}
238 241
239#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 242#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -1846,7 +1849,7 @@ impl TypeParam {
1846 1849
1847 pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { 1850 pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
1848 db.generic_predicates_for_param(self.id) 1851 db.generic_predicates_for_param(self.id)
1849 .into_iter() 1852 .iter()
1850 .filter_map(|pred| match &pred.skip_binders().skip_binders() { 1853 .filter_map(|pred| match &pred.skip_binders().skip_binders() {
1851 hir_ty::WhereClause::Implemented(trait_ref) => { 1854 hir_ty::WhereClause::Implemented(trait_ref) => {
1852 Some(Trait::from(trait_ref.hir_trait_id())) 1855 Some(Trait::from(trait_ref.hir_trait_id()))
@@ -1951,7 +1954,7 @@ impl Impl {
1951 all.extend( 1954 all.extend(
1952 db.inherent_impls_in_crate(id) 1955 db.inherent_impls_in_crate(id)
1953 .for_self_ty(&ty) 1956 .for_self_ty(&ty)
1954 .into_iter() 1957 .iter()
1955 .cloned() 1958 .cloned()
1956 .map(Self::from) 1959 .map(Self::from)
1957 .filter(filter), 1960 .filter(filter),
@@ -2232,8 +2235,8 @@ impl Type {
2232 } 2235 }
2233 2236
2234 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { 2237 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
2235 let adt_id = match self.ty.kind(&Interner) { 2238 let adt_id = match *self.ty.kind(&Interner) {
2236 &TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id, 2239 TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
2237 _ => return false, 2240 _ => return false,
2238 }; 2241 };
2239 2242
@@ -2287,9 +2290,9 @@ impl Type {
2287 } 2290 }
2288 2291
2289 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { 2292 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
2290 let (variant_id, substs) = match self.ty.kind(&Interner) { 2293 let (variant_id, substs) = match *self.ty.kind(&Interner) {
2291 &TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs), 2294 TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs),
2292 &TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs), 2295 TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs),
2293 _ => return Vec::new(), 2296 _ => return Vec::new(),
2294 }; 2297 };
2295 2298
@@ -2488,20 +2491,17 @@ impl Type {
2488 cb: &mut impl FnMut(Type), 2491 cb: &mut impl FnMut(Type),
2489 ) { 2492 ) {
2490 for pred in bounds { 2493 for pred in bounds {
2491 match pred.skip_binders() { 2494 if let WhereClause::Implemented(trait_ref) = pred.skip_binders() {
2492 WhereClause::Implemented(trait_ref) => { 2495 cb(type_.clone());
2493 cb(type_.clone()); 2496 // skip the self type. it's likely the type we just got the bounds from
2494 // skip the self type. it's likely the type we just got the bounds from 2497 for ty in trait_ref
2495 for ty in trait_ref 2498 .substitution
2496 .substitution 2499 .iter(&Interner)
2497 .iter(&Interner) 2500 .skip(1)
2498 .skip(1) 2501 .filter_map(|a| a.ty(&Interner))
2499 .filter_map(|a| a.ty(&Interner)) 2502 {
2500 { 2503 walk_type(db, &type_.derived(ty.clone()), cb);
2501 walk_type(db, &type_.derived(ty.clone()), cb);
2502 }
2503 } 2504 }
2504 _ => (),
2505 } 2505 }
2506 } 2506 }
2507 } 2507 }
@@ -2514,7 +2514,7 @@ impl Type {
2514 walk_substs(db, type_, substs, cb); 2514 walk_substs(db, type_, substs, cb);
2515 } 2515 }
2516 TyKind::AssociatedType(_, substs) => { 2516 TyKind::AssociatedType(_, substs) => {
2517 if let Some(_) = ty.associated_type_parent_trait(db) { 2517 if ty.associated_type_parent_trait(db).is_some() {
2518 cb(type_.derived(ty.clone())); 2518 cb(type_.derived(ty.clone()));
2519 } 2519 }
2520 walk_substs(db, type_, substs, cb); 2520 walk_substs(db, type_, substs, cb);
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index bed4c4994..f6e6cdbe2 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -690,9 +690,7 @@ impl ExprCollector<'_> {
690 } 690 }
691 } 691 }
692 ast::Stmt::Item(item) => { 692 ast::Stmt::Item(item) => {
693 if self.check_cfg(&item).is_none() { 693 self.check_cfg(&item);
694 return;
695 }
696 } 694 }
697 } 695 }
698 } 696 }
@@ -717,7 +715,8 @@ impl ExprCollector<'_> {
717 block.statements().for_each(|s| self.collect_stmt(s)); 715 block.statements().for_each(|s| self.collect_stmt(s));
718 block.tail_expr().and_then(|e| { 716 block.tail_expr().and_then(|e| {
719 let expr = self.maybe_collect_expr(e)?; 717 let expr = self.maybe_collect_expr(e)?;
720 Some(self.statements_in_scope.push(Statement::Expr { expr, has_semi: false })) 718 self.statements_in_scope.push(Statement::Expr { expr, has_semi: false });
719 Some(())
721 }); 720 });
722 721
723 let mut tail = None; 722 let mut tail = None;
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index 27d837d47..673a75386 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -15,12 +15,9 @@ fn lower(ra_fixture: &str) -> Arc<Body> {
15 let mut fn_def = None; 15 let mut fn_def = None;
16 'outer: for (_, module) in def_map.modules() { 16 'outer: for (_, module) in def_map.modules() {
17 for decl in module.scope.declarations() { 17 for decl in module.scope.declarations() {
18 match decl { 18 if let ModuleDefId::FunctionId(it) = decl {
19 ModuleDefId::FunctionId(it) => { 19 fn_def = Some(it);
20 fn_def = Some(it); 20 break 'outer;
21 break 'outer;
22 }
23 _ => {}
24 } 21 }
25 } 22 }
26 } 23 }
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 0f04b2bae..096ac7968 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -104,7 +104,7 @@ impl GenericParams {
104 ) -> Interned<GenericParams> { 104 ) -> Interned<GenericParams> {
105 let _p = profile::span("generic_params_query"); 105 let _p = profile::span("generic_params_query");
106 106
107 let generics = match def { 107 match def {
108 GenericDefId::FunctionId(id) => { 108 GenericDefId::FunctionId(id) => {
109 let id = id.lookup(db).id; 109 let id = id.lookup(db).id;
110 let tree = id.item_tree(db); 110 let tree = id.item_tree(db);
@@ -150,8 +150,7 @@ impl GenericParams {
150 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => { 150 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
151 Interned::new(GenericParams::default()) 151 Interned::new(GenericParams::default())
152 } 152 }
153 }; 153 }
154 generics
155 } 154 }
156 155
157 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { 156 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index 08407ebfa..567ae5660 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -241,10 +241,8 @@ impl ItemScope {
241 check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type); 241 check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
242 check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type); 242 check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
243 243
244 if def.is_none() { 244 if def.is_none() && self.unresolved.insert(lookup.1) {
245 if self.unresolved.insert(lookup.1) { 245 changed = true;
246 changed = true;
247 }
248 } 246 }
249 247
250 changed 248 changed
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index e63bc8232..8b12e5a67 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -30,16 +30,16 @@ pub(super) fn print_item_tree(tree: &ItemTree) -> String {
30 30
31macro_rules! w { 31macro_rules! w {
32 ($dst:expr, $($arg:tt)*) => { 32 ($dst:expr, $($arg:tt)*) => {
33 drop(write!($dst, $($arg)*)) 33 { let _ = write!($dst, $($arg)*); }
34 }; 34 };
35} 35}
36 36
37macro_rules! wln { 37macro_rules! wln {
38 ($dst:expr) => { 38 ($dst:expr) => {
39 drop(writeln!($dst)) 39 { let _ = writeln!($dst); }
40 }; 40 };
41 ($dst:expr, $($arg:tt)*) => { 41 ($dst:expr, $($arg:tt)*) => {
42 drop(writeln!($dst, $($arg)*)) 42 { let _ = writeln!($dst, $($arg)*); }
43 }; 43 };
44} 44}
45 45
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index ebfcc26c4..9e6aa9607 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -367,10 +367,7 @@ impl DefMap {
367 pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> { 367 pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
368 match &self[local_mod].parent { 368 match &self[local_mod].parent {
369 Some(parent) => Some(self.module_id(*parent)), 369 Some(parent) => Some(self.module_id(*parent)),
370 None => match &self.block { 370 None => self.block.as_ref().map(|block| block.parent),
371 Some(block) => Some(block.parent),
372 None => None,
373 },
374 } 371 }
375 } 372 }
376 373
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index 629bc7952..229f57d77 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -55,7 +55,7 @@ impl ResolvePathResult {
55 segment_index: Option<usize>, 55 segment_index: Option<usize>,
56 krate: Option<CrateId>, 56 krate: Option<CrateId>,
57 ) -> ResolvePathResult { 57 ) -> ResolvePathResult {
58 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index, krate } 58 ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, krate }
59 } 59 }
60} 60}
61 61
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 4cdb5913d..667092cd2 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -209,7 +209,7 @@ impl Path {
209 209
210 pub fn is_self_type(&self) -> bool { 210 pub fn is_self_type(&self) -> bool {
211 self.type_anchor.is_none() 211 self.type_anchor.is_none()
212 && self.generic_args == &[None] 212 && self.generic_args == [None]
213 && self.mod_path.as_ident() == Some(&name!(Self)) 213 && self.mod_path.as_ident() == Some(&name!(Self))
214 } 214 }
215} 215}
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 49c573087..a11439c3b 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -388,9 +388,9 @@ impl Resolver {
388 self.module_scope().map(|t| t.0.krate()) 388 self.module_scope().map(|t| t.0.krate())
389 } 389 }
390 390
391 pub fn where_predicates_in_scope<'a>( 391 pub fn where_predicates_in_scope(
392 &'a self, 392 &self,
393 ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a { 393 ) -> impl Iterator<Item = &crate::generics::WherePredicate> {
394 self.scopes 394 self.scopes
395 .iter() 395 .iter()
396 .rev() 396 .rev()
@@ -464,16 +464,16 @@ impl Scope {
464 &Scope::GenericParams { ref params, def: parent } => { 464 &Scope::GenericParams { ref params, def: parent } => {
465 for (local_id, param) in params.types.iter() { 465 for (local_id, param) in params.types.iter() {
466 if let Some(ref name) = param.name { 466 if let Some(ref name) = param.name {
467 let id = TypeParamId { local_id, parent }; 467 let id = TypeParamId { parent, local_id };
468 f(name.clone(), ScopeDef::GenericParam(id.into())) 468 f(name.clone(), ScopeDef::GenericParam(id.into()))
469 } 469 }
470 } 470 }
471 for (local_id, param) in params.consts.iter() { 471 for (local_id, param) in params.consts.iter() {
472 let id = ConstParamId { local_id, parent }; 472 let id = ConstParamId { parent, local_id };
473 f(param.name.clone(), ScopeDef::GenericParam(id.into())) 473 f(param.name.clone(), ScopeDef::GenericParam(id.into()))
474 } 474 }
475 for (local_id, param) in params.lifetimes.iter() { 475 for (local_id, param) in params.lifetimes.iter() {
476 let id = LifetimeParamId { local_id, parent }; 476 let id = LifetimeParamId { parent, local_id };
477 f(param.name.clone(), ScopeDef::GenericParam(id.into())) 477 f(param.name.clone(), ScopeDef::GenericParam(id.into()))
478 } 478 }
479 } 479 }
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 4c83a2efe..f556bc751 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -420,7 +420,7 @@ fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> {
420 tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(it), 420 tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(it),
421 _ => None, 421 _ => None,
422 }) 422 })
423 .ok_or_else(|| mbe::ExpandError::ConversionError) 423 .ok_or(mbe::ExpandError::ConversionError)
424} 424}
425 425
426fn include_expand( 426fn include_expand(
@@ -432,9 +432,8 @@ fn include_expand(
432 let path = parse_string(tt)?; 432 let path = parse_string(tt)?;
433 let file_id = relative_file(db, arg_id, &path, false)?; 433 let file_id = relative_file(db, arg_id, &path, false)?;
434 434
435 let subtree = parse_to_token_tree(&db.file_text(file_id)) 435 let subtree =
436 .ok_or_else(|| mbe::ExpandError::ConversionError)? 436 parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?.0;
437 .0;
438 Ok((subtree, file_id)) 437 Ok((subtree, file_id))
439 })(); 438 })();
440 439
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index 584ddcf9f..66601f4df 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -128,7 +128,7 @@ pub fn expand_eager_macro(
128 }), 128 }),
129 kind: MacroCallKind::FnLike { ast_id: call_id, fragment: FragmentKind::Expr }, 129 kind: MacroCallKind::FnLike { ast_id: call_id, fragment: FragmentKind::Expr },
130 }); 130 });
131 let arg_file_id: MacroCallId = arg_id; 131 let arg_file_id = arg_id;
132 132
133 let parsed_args = 133 let parsed_args =
134 diagnostic_sink.result(mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr))?.0; 134 diagnostic_sink.result(mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr))?.0;
@@ -177,7 +177,7 @@ fn lazy_expand(
177 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value); 177 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
178 178
179 let fragment = crate::to_fragment_kind(&macro_call.value); 179 let fragment = crate::to_fragment_kind(&macro_call.value);
180 let id: MacroCallId = def.as_lazy_macro( 180 let id = def.as_lazy_macro(
181 db, 181 db,
182 krate, 182 krate,
183 MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), fragment }, 183 MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), fragment },
@@ -207,7 +207,7 @@ fn eager_macro_recur(
207 .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?; 207 .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?;
208 let insert = match def.kind { 208 let insert = match def.kind {
209 MacroDefKind::BuiltInEager(..) => { 209 MacroDefKind::BuiltInEager(..) => {
210 let id: MacroCallId = expand_eager_macro( 210 let id = expand_eager_macro(
211 db, 211 db,
212 krate, 212 krate,
213 curr.with_value(child.clone()), 213 curr.with_value(child.clone()),
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index a4c09c742..a55b99de0 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -2,6 +2,7 @@
2//! about the code that Chalk needs. 2//! about the code that Chalk needs.
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use cov_mark::hit;
5use log::debug; 6use log::debug;
6 7
7use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds}; 8use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
@@ -106,7 +107,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
106 }; 107 };
107 108
108 fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> { 109 fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> {
109 db.trait_impls_in_block(module.containing_block()?) 110 let block = module.containing_block()?;
111 hit!(block_local_impls);
112 db.trait_impls_in_block(block)
110 } 113 }
111 114
112 // Note: Since we're using impls_for_trait, only impls where the trait 115 // Note: Since we're using impls_for_trait, only impls where the trait
diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs
index 4640ea821..b99a03492 100644
--- a/crates/hir_ty/src/test_db.rs
+++ b/crates/hir_ty/src/test_db.rs
@@ -86,16 +86,20 @@ impl FileLoader for TestDB {
86} 86}
87 87
88impl TestDB { 88impl TestDB {
89 pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { 89 pub(crate) fn module_for_file_opt(&self, file_id: FileId) -> Option<ModuleId> {
90 for &krate in self.relevant_crates(file_id).iter() { 90 for &krate in self.relevant_crates(file_id).iter() {
91 let crate_def_map = self.crate_def_map(krate); 91 let crate_def_map = self.crate_def_map(krate);
92 for (local_id, data) in crate_def_map.modules() { 92 for (local_id, data) in crate_def_map.modules() {
93 if data.origin.file_id() == Some(file_id) { 93 if data.origin.file_id() == Some(file_id) {
94 return crate_def_map.module_id(local_id); 94 return Some(crate_def_map.module_id(local_id));
95 } 95 }
96 } 96 }
97 } 97 }
98 panic!("Can't find module for file") 98 None
99 }
100
101 pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
102 self.module_for_file_opt(file_id).unwrap()
99 } 103 }
100 104
101 pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { 105 pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index b873585c4..0651f34ae 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -11,23 +11,21 @@ mod incremental;
11 11
12use std::{collections::HashMap, env, sync::Arc}; 12use std::{collections::HashMap, env, sync::Arc};
13 13
14use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; 14use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt};
15use expect_test::Expect; 15use expect_test::Expect;
16use hir_def::{ 16use hir_def::{
17 body::{Body, BodySourceMap, SyntheticSyntax}, 17 body::{Body, BodySourceMap, SyntheticSyntax},
18 child_by_source::ChildBySource,
19 db::DefDatabase, 18 db::DefDatabase,
19 expr::{ExprId, PatId},
20 item_scope::ItemScope, 20 item_scope::ItemScope,
21 keys,
22 nameres::DefMap, 21 nameres::DefMap,
23 src::HasSource, 22 src::HasSource,
24 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 23 AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId,
25}; 24};
26use hir_expand::{db::AstDatabase, InFile}; 25use hir_expand::{db::AstDatabase, InFile};
27use once_cell::race::OnceBool; 26use once_cell::race::OnceBool;
28use stdx::format_to; 27use stdx::format_to;
29use syntax::{ 28use syntax::{
30 algo,
31 ast::{self, AstNode, NameOwner}, 29 ast::{self, AstNode, NameOwner},
32 SyntaxNode, 30 SyntaxNode,
33}; 31};
@@ -59,51 +57,55 @@ fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> {
59} 57}
60 58
61fn check_types(ra_fixture: &str) { 59fn check_types(ra_fixture: &str) {
62 check_types_impl(ra_fixture, false) 60 check_impl(ra_fixture, false, true, false)
63} 61}
64 62
65fn check_types_source_code(ra_fixture: &str) { 63fn check_types_source_code(ra_fixture: &str) {
66 check_types_impl(ra_fixture, true) 64 check_impl(ra_fixture, false, true, true)
67}
68
69fn check_types_impl(ra_fixture: &str, display_source: bool) {
70 let _tracing = setup_tracing();
71 let db = TestDB::with_files(ra_fixture);
72 let mut checked_one = false;
73 for (file_id, annotations) in db.extract_annotations() {
74 for (range, expected) in annotations {
75 let ty = type_at_range(&db, FileRange { file_id, range });
76 let actual = if display_source {
77 let module = db.module_for_file(file_id);
78 ty.display_source_code(&db, module).unwrap()
79 } else {
80 ty.display_test(&db).to_string()
81 };
82 assert_eq!(expected, actual);
83 checked_one = true;
84 }
85 }
86
87 assert!(checked_one, "no `//^` annotations found");
88} 65}
89 66
90fn check_no_mismatches(ra_fixture: &str) { 67fn check_no_mismatches(ra_fixture: &str) {
91 check_mismatches_impl(ra_fixture, true) 68 check_impl(ra_fixture, true, false, false)
92} 69}
93 70
94#[allow(unused)] 71fn check(ra_fixture: &str) {
95fn check_mismatches(ra_fixture: &str) { 72 check_impl(ra_fixture, false, false, false)
96 check_mismatches_impl(ra_fixture, false)
97} 73}
98 74
99fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) { 75fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_source: bool) {
100 let _tracing = setup_tracing(); 76 let _tracing = setup_tracing();
101 let (db, file_id) = TestDB::with_single_file(ra_fixture); 77 let (db, files) = TestDB::with_many_files(ra_fixture);
102 let module = db.module_for_file(file_id); 78
103 let def_map = module.def_map(&db); 79 let mut had_annotations = false;
80 let mut mismatches = HashMap::new();
81 let mut types = HashMap::new();
82 for (file_id, annotations) in db.extract_annotations() {
83 for (range, expected) in annotations {
84 let file_range = FileRange { file_id, range };
85 if only_types {
86 types.insert(file_range, expected);
87 } else if expected.starts_with("type: ") {
88 types.insert(file_range, expected.trim_start_matches("type: ").to_string());
89 } else if expected.starts_with("expected") {
90 mismatches.insert(file_range, expected);
91 } else {
92 panic!("unexpected annotation: {}", expected);
93 }
94 had_annotations = true;
95 }
96 }
97 assert!(had_annotations || allow_none, "no `//^` annotations found");
104 98
105 let mut defs: Vec<DefWithBodyId> = Vec::new(); 99 let mut defs: Vec<DefWithBodyId> = Vec::new();
106 visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it)); 100 for file_id in files {
101 let module = db.module_for_file_opt(file_id);
102 let module = match module {
103 Some(m) => m,
104 None => continue,
105 };
106 let def_map = module.def_map(&db);
107 visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it));
108 }
107 defs.sort_by_key(|def| match def { 109 defs.sort_by_key(|def| match def {
108 DefWithBodyId::FunctionId(it) => { 110 DefWithBodyId::FunctionId(it) => {
109 let loc = it.lookup(&db); 111 let loc = it.lookup(&db);
@@ -118,37 +120,59 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
118 loc.source(&db).value.syntax().text_range().start() 120 loc.source(&db).value.syntax().text_range().start()
119 } 121 }
120 }); 122 });
121 let mut mismatches = HashMap::new(); 123 let mut unexpected_type_mismatches = String::new();
122 let mut push_mismatch = |src_ptr: InFile<SyntaxNode>, mismatch: TypeMismatch| {
123 let range = src_ptr.value.text_range();
124 if src_ptr.file_id.call_node(&db).is_some() {
125 panic!("type mismatch in macro expansion");
126 }
127 let file_range = FileRange { file_id: src_ptr.file_id.original_file(&db), range };
128 let actual = format!(
129 "expected {}, got {}",
130 mismatch.expected.display_test(&db),
131 mismatch.actual.display_test(&db)
132 );
133 mismatches.insert(file_range, actual);
134 };
135 for def in defs { 124 for def in defs {
136 let (_body, body_source_map) = db.body_with_source_map(def); 125 let (_body, body_source_map) = db.body_with_source_map(def);
137 let inference_result = db.infer(def); 126 let inference_result = db.infer(def);
127
128 for (pat, ty) in inference_result.type_of_pat.iter() {
129 let node = match pat_node(&body_source_map, pat, &db) {
130 Some(value) => value,
131 None => continue,
132 };
133 let range = node.as_ref().original_file_range(&db);
134 if let Some(expected) = types.remove(&range) {
135 let actual = if display_source {
136 ty.display_source_code(&db, def.module(&db)).unwrap()
137 } else {
138 ty.display_test(&db).to_string()
139 };
140 assert_eq!(actual, expected);
141 }
142 }
143
144 for (expr, ty) in inference_result.type_of_expr.iter() {
145 let node = match expr_node(&body_source_map, expr, &db) {
146 Some(value) => value,
147 None => continue,
148 };
149 let range = node.as_ref().original_file_range(&db);
150 if let Some(expected) = types.remove(&range) {
151 let actual = if display_source {
152 ty.display_source_code(&db, def.module(&db)).unwrap()
153 } else {
154 ty.display_test(&db).to_string()
155 };
156 assert_eq!(actual, expected);
157 }
158 }
159
138 for (pat, mismatch) in inference_result.pat_type_mismatches() { 160 for (pat, mismatch) in inference_result.pat_type_mismatches() {
139 let syntax_ptr = match body_source_map.pat_syntax(pat) { 161 let node = match pat_node(&body_source_map, pat, &db) {
140 Ok(sp) => { 162 Some(value) => value,
141 let root = db.parse_or_expand(sp.file_id).unwrap(); 163 None => continue,
142 sp.map(|ptr| {
143 ptr.either(
144 |it| it.to_node(&root).syntax().clone(),
145 |it| it.to_node(&root).syntax().clone(),
146 )
147 })
148 }
149 Err(SyntheticSyntax) => continue,
150 }; 164 };
151 push_mismatch(syntax_ptr, mismatch.clone()); 165 let range = node.as_ref().original_file_range(&db);
166 let actual = format!(
167 "expected {}, got {}",
168 mismatch.expected.display_test(&db),
169 mismatch.actual.display_test(&db)
170 );
171 if let Some(annotation) = mismatches.remove(&range) {
172 assert_eq!(actual, annotation);
173 } else {
174 format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual);
175 }
152 } 176 }
153 for (expr, mismatch) in inference_result.expr_type_mismatches() { 177 for (expr, mismatch) in inference_result.expr_type_mismatches() {
154 let node = match body_source_map.expr_syntax(expr) { 178 let node = match body_source_map.expr_syntax(expr) {
@@ -158,45 +182,70 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
158 } 182 }
159 Err(SyntheticSyntax) => continue, 183 Err(SyntheticSyntax) => continue,
160 }; 184 };
161 push_mismatch(node, mismatch.clone()); 185 let range = node.as_ref().original_file_range(&db);
162 } 186 let actual = format!(
163 } 187 "expected {}, got {}",
164 let mut checked_one = false; 188 mismatch.expected.display_test(&db),
165 for (file_id, annotations) in db.extract_annotations() { 189 mismatch.actual.display_test(&db)
166 for (range, expected) in annotations { 190 );
167 let file_range = FileRange { file_id, range }; 191 if let Some(annotation) = mismatches.remove(&range) {
168 if let Some(mismatch) = mismatches.remove(&file_range) { 192 assert_eq!(actual, annotation);
169 assert_eq!(mismatch, expected);
170 } else { 193 } else {
171 assert!(false, "Expected mismatch not encountered: {}\n", expected); 194 format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual);
172 } 195 }
173 checked_one = true;
174 } 196 }
175 } 197 }
198
176 let mut buf = String::new(); 199 let mut buf = String::new();
177 for (range, mismatch) in mismatches { 200 if !unexpected_type_mismatches.is_empty() {
178 format_to!(buf, "{:?}: {}\n", range.range, mismatch,); 201 format_to!(buf, "Unexpected type mismatches:\n{}", unexpected_type_mismatches);
202 }
203 if !mismatches.is_empty() {
204 format_to!(buf, "Unchecked mismatch annotations:\n");
205 for m in mismatches {
206 format_to!(buf, "{:?}: {}\n", m.0.range, m.1);
207 }
179 } 208 }
180 assert!(buf.is_empty(), "Unexpected type mismatches:\n{}", buf); 209 if !types.is_empty() {
210 format_to!(buf, "Unchecked type annotations:\n");
211 for t in types {
212 format_to!(buf, "{:?}: type {}\n", t.0.range, t.1);
213 }
214 }
215 assert!(buf.is_empty(), "{}", buf);
216}
181 217
182 assert!(checked_one || allow_none, "no `//^` annotations found"); 218fn expr_node(
219 body_source_map: &BodySourceMap,
220 expr: ExprId,
221 db: &TestDB,
222) -> Option<InFile<SyntaxNode>> {
223 Some(match body_source_map.expr_syntax(expr) {
224 Ok(sp) => {
225 let root = db.parse_or_expand(sp.file_id).unwrap();
226 sp.map(|ptr| ptr.to_node(&root).syntax().clone())
227 }
228 Err(SyntheticSyntax) => return None,
229 })
183} 230}
184 231
185fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { 232fn pat_node(
186 let file = db.parse(pos.file_id).ok().unwrap(); 233 body_source_map: &BodySourceMap,
187 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); 234 pat: PatId,
188 let fn_def = expr.syntax().ancestors().find_map(ast::Fn::cast).unwrap(); 235 db: &TestDB,
189 let module = db.module_for_file(pos.file_id); 236) -> Option<InFile<SyntaxNode>> {
190 let func = *module.child_by_source(db)[keys::FUNCTION] 237 Some(match body_source_map.pat_syntax(pat) {
191 .get(&InFile::new(pos.file_id.into(), fn_def)) 238 Ok(sp) => {
192 .unwrap(); 239 let root = db.parse_or_expand(sp.file_id).unwrap();
193 240 sp.map(|ptr| {
194 let (_body, source_map) = db.body_with_source_map(func.into()); 241 ptr.either(
195 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { 242 |it| it.to_node(&root).syntax().clone(),
196 let infer = db.infer(func.into()); 243 |it| it.to_node(&root).syntax().clone(),
197 return infer[expr_id].clone(); 244 )
198 } 245 })
199 panic!("Can't find expression") 246 }
247 Err(SyntheticSyntax) => return None,
248 })
200} 249}
201 250
202fn infer(ra_fixture: &str) -> String { 251fn infer(ra_fixture: &str) -> String {
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index 713b74165..87089f09d 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -1,27 +1,22 @@
1use expect_test::expect; 1use super::{check, check_no_mismatches, check_types};
2
3use super::{check_infer, check_infer_with_mismatches, check_no_mismatches, check_types};
4 2
5#[test] 3#[test]
6fn infer_block_expr_type_mismatch() { 4fn block_expr_type_mismatch() {
7 check_infer( 5 // FIXME fix double type mismatch
6 check(
8 r" 7 r"
9 fn test() { 8fn test() {
10 let a: i32 = { 1i64 }; 9 let a: i32 = { 1i64 };
11 } 10 // ^^^^^^^^ expected i32, got i64
11 // ^^^^ expected i32, got i64
12}
12 ", 13 ",
13 expect![[r"
14 10..40 '{ ...4 }; }': ()
15 20..21 'a': i32
16 29..37 '{ 1i64 }': i64
17 31..35 '1i64': i64
18 "]],
19 ); 14 );
20} 15}
21 16
22#[test] 17#[test]
23fn coerce_places() { 18fn coerce_places() {
24 check_infer( 19 check_no_mismatches(
25 r#" 20 r#"
26//- minicore: coerce_unsized 21//- minicore: coerce_unsized
27struct S<T> { a: T } 22struct S<T> { a: T }
@@ -46,81 +41,25 @@ fn test2() {
46 let g: (&[_], &[_]) = (arr, arr); 41 let g: (&[_], &[_]) = (arr, arr);
47} 42}
48"#, 43"#,
49 expect![[r#"
50 30..31 '_': &[T]
51 44..55 '{ loop {} }': T
52 46..53 'loop {}': !
53 51..53 '{}': ()
54 64..65 '_': S<&[T]>
55 81..92 '{ loop {} }': T
56 83..90 'loop {}': !
57 88..90 '{}': ()
58 121..132 '{ loop {} }': *mut [T; 2]
59 123..130 'loop {}': !
60 128..130 '{}': ()
61 159..172 '{ gen() }': *mut [U]
62 165..168 'gen': fn gen<U>() -> *mut [U; 2]
63 165..170 'gen()': *mut [U; 2]
64 185..419 '{ ...rr); }': ()
65 195..198 'arr': &[u8; 1]
66 211..215 '&[1]': &[u8; 1]
67 212..215 '[1]': [u8; 1]
68 213..214 '1': u8
69 226..227 'a': &[u8]
70 236..239 'arr': &[u8; 1]
71 249..250 'b': u8
72 253..254 'f': fn f<u8>(&[u8]) -> u8
73 253..259 'f(arr)': u8
74 255..258 'arr': &[u8; 1]
75 269..270 'c': &[u8]
76 279..286 '{ arr }': &[u8]
77 281..284 'arr': &[u8; 1]
78 296..297 'd': u8
79 300..301 'g': fn g<u8>(S<&[u8]>) -> u8
80 300..315 'g(S { a: arr })': u8
81 302..314 'S { a: arr }': S<&[u8]>
82 309..312 'arr': &[u8; 1]
83 325..326 'e': [&[u8]; 1]
84 340..345 '[arr]': [&[u8]; 1]
85 341..344 'arr': &[u8; 1]
86 355..356 'f': [&[u8]; 2]
87 370..378 '[arr; 2]': [&[u8]; 2]
88 371..374 'arr': &[u8; 1]
89 376..377 '2': usize
90 388..389 'g': (&[u8], &[u8])
91 406..416 '(arr, arr)': (&[u8], &[u8])
92 407..410 'arr': &[u8; 1]
93 412..415 'arr': &[u8; 1]
94 "#]],
95 ); 44 );
96} 45}
97 46
98#[test] 47#[test]
99fn infer_let_stmt_coerce() { 48fn let_stmt_coerce() {
100 check_infer( 49 check_no_mismatches(
101 r" 50 r"
102 fn test() { 51//- minicore: coerce_unsized
103 let x: &[isize] = &[1]; 52fn test() {
104 let x: *const [isize] = &[1]; 53 let x: &[isize] = &[1];
105 } 54 let x: *const [isize] = &[1];
106 ", 55}
107 expect![[r#" 56",
108 10..75 '{ ...[1]; }': ()
109 20..21 'x': &[isize]
110 34..38 '&[1]': &[isize; 1]
111 35..38 '[1]': [isize; 1]
112 36..37 '1': isize
113 48..49 'x': *const [isize]
114 68..72 '&[1]': &[isize; 1]
115 69..72 '[1]': [isize; 1]
116 70..71 '1': isize
117 "#]],
118 ); 57 );
119} 58}
120 59
121#[test] 60#[test]
122fn infer_custom_coerce_unsized() { 61fn custom_coerce_unsized() {
123 check_infer( 62 check(
124 r#" 63 r#"
125//- minicore: coerce_unsized 64//- minicore: coerce_unsized
126use core::{marker::Unsize, ops::CoerceUnsized}; 65use core::{marker::Unsize, ops::CoerceUnsized};
@@ -138,46 +77,22 @@ fn foo3<T>(x: C<[T]>) -> C<[T]> { x }
138 77
139fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { 78fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) {
140 let d = foo1(a); 79 let d = foo1(a);
80 // ^ expected A<[{unknown}]>, got A<[u8; 2]>
141 let e = foo2(b); 81 let e = foo2(b);
82 // ^ type: B<[u8]>
142 let f = foo3(c); 83 let f = foo3(c);
84 // ^ type: C<[u8]>
143} 85}
144"#, 86"#,
145 expect![[r#"
146 306..307 'x': A<[T]>
147 327..332 '{ x }': A<[T]>
148 329..330 'x': A<[T]>
149 344..345 'x': B<[T]>
150 365..370 '{ x }': B<[T]>
151 367..368 'x': B<[T]>
152 382..383 'x': C<[T]>
153 403..408 '{ x }': C<[T]>
154 405..406 'x': C<[T]>
155 418..419 'a': A<[u8; 2]>
156 433..434 'b': B<[u8; 2]>
157 448..449 'c': C<[u8; 2]>
158 463..529 '{ ...(c); }': ()
159 473..474 'd': A<[{unknown}]>
160 477..481 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]>
161 477..484 'foo1(a)': A<[{unknown}]>
162 482..483 'a': A<[u8; 2]>
163 494..495 'e': B<[u8]>
164 498..502 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]>
165 498..505 'foo2(b)': B<[u8]>
166 503..504 'b': B<[u8; 2]>
167 515..516 'f': C<[u8]>
168 519..523 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]>
169 519..526 'foo3(c)': C<[u8]>
170 524..525 'c': C<[u8; 2]>
171 "#]],
172 ); 87 );
173} 88}
174 89
175#[test] 90#[test]
176fn infer_if_coerce() { 91fn if_coerce() {
177 check_infer( 92 check_no_mismatches(
178 r#" 93 r#"
179//- minicore: unsize 94//- minicore: coerce_unsized
180fn foo<T>(x: &[T]) -> &[T] { loop {} } 95fn foo<T>(x: &[T]) -> &[T] { x }
181fn test() { 96fn test() {
182 let x = if true { 97 let x = if true {
183 foo(&[1]) 98 foo(&[1])
@@ -186,35 +101,15 @@ fn test() {
186 }; 101 };
187} 102}
188"#, 103"#,
189 expect![[r#"
190 10..11 'x': &[T]
191 27..38 '{ loop {} }': &[T]
192 29..36 'loop {}': !
193 34..36 '{}': ()
194 49..125 '{ ... }; }': ()
195 59..60 'x': &[i32]
196 63..122 'if tru... }': &[i32]
197 66..70 'true': bool
198 71..96 '{ ... }': &[i32]
199 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32]
200 81..90 'foo(&[1])': &[i32]
201 85..89 '&[1]': &[i32; 1]
202 86..89 '[1]': [i32; 1]
203 87..88 '1': i32
204 102..122 '{ ... }': &[i32; 1]
205 112..116 '&[1]': &[i32; 1]
206 113..116 '[1]': [i32; 1]
207 114..115 '1': i32
208 "#]],
209 ); 104 );
210} 105}
211 106
212#[test] 107#[test]
213fn infer_if_else_coerce() { 108fn if_else_coerce() {
214 check_infer( 109 check_no_mismatches(
215 r#" 110 r#"
216//- minicore: coerce_unsized 111//- minicore: coerce_unsized
217fn foo<T>(x: &[T]) -> &[T] { loop {} } 112fn foo<T>(x: &[T]) -> &[T] { x }
218fn test() { 113fn test() {
219 let x = if true { 114 let x = if true {
220 &[1] 115 &[1]
@@ -223,35 +118,15 @@ fn test() {
223 }; 118 };
224} 119}
225"#, 120"#,
226 expect![[r#"
227 10..11 'x': &[T]
228 27..38 '{ loop {} }': &[T]
229 29..36 'loop {}': !
230 34..36 '{}': ()
231 49..125 '{ ... }; }': ()
232 59..60 'x': &[i32]
233 63..122 'if tru... }': &[i32]
234 66..70 'true': bool
235 71..91 '{ ... }': &[i32; 1]
236 81..85 '&[1]': &[i32; 1]
237 82..85 '[1]': [i32; 1]
238 83..84 '1': i32
239 97..122 '{ ... }': &[i32]
240 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32]
241 107..116 'foo(&[1])': &[i32]
242 111..115 '&[1]': &[i32; 1]
243 112..115 '[1]': [i32; 1]
244 113..114 '1': i32
245 "#]],
246 ) 121 )
247} 122}
248 123
249#[test] 124#[test]
250fn infer_match_first_coerce() { 125fn match_first_coerce() {
251 check_infer( 126 check_no_mismatches(
252 r#" 127 r#"
253//- minicore: unsize 128//- minicore: coerce_unsized
254fn foo<T>(x: &[T]) -> &[T] { loop {} } 129fn foo<T>(x: &[T]) -> &[T] { x }
255fn test(i: i32) { 130fn test(i: i32) {
256 let x = match i { 131 let x = match i {
257 2 => foo(&[2]), 132 2 => foo(&[2]),
@@ -260,39 +135,12 @@ fn test(i: i32) {
260 }; 135 };
261} 136}
262"#, 137"#,
263 expect![[r#"
264 10..11 'x': &[T]
265 27..38 '{ loop {} }': &[T]
266 29..36 'loop {}': !
267 34..36 '{}': ()
268 47..48 'i': i32
269 55..149 '{ ... }; }': ()
270 65..66 'x': &[i32]
271 69..146 'match ... }': &[i32]
272 75..76 'i': i32
273 87..88 '2': i32
274 87..88 '2': i32
275 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32]
276 92..101 'foo(&[2])': &[i32]
277 96..100 '&[2]': &[i32; 1]
278 97..100 '[2]': [i32; 1]
279 98..99 '2': i32
280 111..112 '1': i32
281 111..112 '1': i32
282 116..120 '&[1]': &[i32; 1]
283 117..120 '[1]': [i32; 1]
284 118..119 '1': i32
285 130..131 '_': i32
286 135..139 '&[3]': &[i32; 1]
287 136..139 '[3]': [i32; 1]
288 137..138 '3': i32
289 "#]],
290 ); 138 );
291} 139}
292 140
293#[test] 141#[test]
294fn infer_match_second_coerce() { 142fn match_second_coerce() {
295 check_infer( 143 check_no_mismatches(
296 r#" 144 r#"
297//- minicore: coerce_unsized 145//- minicore: coerce_unsized
298fn foo<T>(x: &[T]) -> &[T] { loop {} } 146fn foo<T>(x: &[T]) -> &[T] { loop {} }
@@ -304,33 +152,6 @@ fn test(i: i32) {
304 }; 152 };
305} 153}
306"#, 154"#,
307 expect![[r#"
308 10..11 'x': &[T]
309 27..38 '{ loop {} }': &[T]
310 29..36 'loop {}': !
311 34..36 '{}': ()
312 47..48 'i': i32
313 55..149 '{ ... }; }': ()
314 65..66 'x': &[i32]
315 69..146 'match ... }': &[i32]
316 75..76 'i': i32
317 87..88 '1': i32
318 87..88 '1': i32
319 92..96 '&[1]': &[i32; 1]
320 93..96 '[1]': [i32; 1]
321 94..95 '1': i32
322 106..107 '2': i32
323 106..107 '2': i32
324 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32]
325 111..120 'foo(&[2])': &[i32]
326 115..119 '&[2]': &[i32; 1]
327 116..119 '[2]': [i32; 1]
328 117..118 '2': i32
329 130..131 '_': i32
330 135..139 '&[3]': &[i32; 1]
331 136..139 '[3]': [i32; 1]
332 137..138 '3': i32
333 "#]],
334 ); 155 );
335} 156}
336 157
@@ -338,94 +159,52 @@ fn test(i: i32) {
338fn coerce_merge_one_by_one1() { 159fn coerce_merge_one_by_one1() {
339 cov_mark::check!(coerce_merge_fail_fallback); 160 cov_mark::check!(coerce_merge_fail_fallback);
340 161
341 check_infer( 162 check(
342 r" 163 r"
343 fn test() { 164fn test() {
344 let t = &mut 1; 165 let t = &mut 1;
345 let x = match 1 { 166 let x = match 1 {
346 1 => t as *mut i32, 167 1 => t as *mut i32,
347 2 => t as &i32, 168 2 => t as &i32,
348 _ => t as *const i32, 169 //^^^^^^^^^ expected *mut i32, got &i32
349 }; 170 _ => t as *const i32,
350 } 171 };
172 x;
173 //^ type: *const i32
174}
351 ", 175 ",
352 expect![[r"
353 10..144 '{ ... }; }': ()
354 20..21 't': &mut i32
355 24..30 '&mut 1': &mut i32
356 29..30 '1': i32
357 40..41 'x': *const i32
358 44..141 'match ... }': *const i32
359 50..51 '1': i32
360 62..63 '1': i32
361 62..63 '1': i32
362 67..68 't': &mut i32
363 67..80 't as *mut i32': *mut i32
364 90..91 '2': i32
365 90..91 '2': i32
366 95..96 't': &mut i32
367 95..104 't as &i32': &i32
368 114..115 '_': i32
369 119..120 't': &mut i32
370 119..134 't as *const i32': *const i32
371 "]],
372 ); 176 );
373} 177}
374 178
375#[test] 179#[test]
376fn return_coerce_unknown() { 180fn return_coerce_unknown() {
377 check_infer_with_mismatches( 181 check_types(
378 r" 182 r"
379 fn foo() -> u32 { 183fn foo() -> u32 {
380 return unknown; 184 return unknown;
381 } 185 //^^^^^^^ u32
186}
382 ", 187 ",
383 expect![[r"
384 16..39 '{ ...own; }': u32
385 22..36 'return unknown': !
386 29..36 'unknown': u32
387 "]],
388 ); 188 );
389} 189}
390 190
391#[test] 191#[test]
392fn coerce_autoderef() { 192fn coerce_autoderef() {
393 check_infer_with_mismatches( 193 check_no_mismatches(
394 r" 194 r"
395 struct Foo; 195struct Foo;
396 fn takes_ref_foo(x: &Foo) {} 196fn takes_ref_foo(x: &Foo) {}
397 fn test() { 197fn test() {
398 takes_ref_foo(&Foo); 198 takes_ref_foo(&Foo);
399 takes_ref_foo(&&Foo); 199 takes_ref_foo(&&Foo);
400 takes_ref_foo(&&&Foo); 200 takes_ref_foo(&&&Foo);
401 } 201}",
402 ",
403 expect![[r"
404 29..30 'x': &Foo
405 38..40 '{}': ()
406 51..132 '{ ...oo); }': ()
407 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo)
408 57..76 'takes_...(&Foo)': ()
409 71..75 '&Foo': &Foo
410 72..75 'Foo': Foo
411 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo)
412 82..102 'takes_...&&Foo)': ()
413 96..101 '&&Foo': &&Foo
414 97..101 '&Foo': &Foo
415 98..101 'Foo': Foo
416 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo)
417 108..129 'takes_...&&Foo)': ()
418 122..128 '&&&Foo': &&&Foo
419 123..128 '&&Foo': &&Foo
420 124..128 '&Foo': &Foo
421 125..128 'Foo': Foo
422 "]],
423 ); 202 );
424} 203}
425 204
426#[test] 205#[test]
427fn coerce_autoderef_generic() { 206fn coerce_autoderef_generic() {
428 check_infer_with_mismatches( 207 check_no_mismatches(
429 r#" 208 r#"
430struct Foo; 209struct Foo;
431fn takes_ref<T>(x: &T) -> T { *x } 210fn takes_ref<T>(x: &T) -> T { *x }
@@ -435,34 +214,12 @@ fn test() {
435 takes_ref(&&&Foo); 214 takes_ref(&&&Foo);
436} 215}
437"#, 216"#,
438 expect![[r"
439 28..29 'x': &T
440 40..46 '{ *x }': T
441 42..44 '*x': T
442 43..44 'x': &T
443 57..126 '{ ...oo); }': ()
444 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo
445 63..78 'takes_ref(&Foo)': Foo
446 73..77 '&Foo': &Foo
447 74..77 'Foo': Foo
448 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo
449 84..100 'takes_...&&Foo)': &Foo
450 94..99 '&&Foo': &&Foo
451 95..99 '&Foo': &Foo
452 96..99 'Foo': Foo
453 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo
454 106..123 'takes_...&&Foo)': &&Foo
455 116..122 '&&&Foo': &&&Foo
456 117..122 '&&Foo': &&Foo
457 118..122 '&Foo': &Foo
458 119..122 'Foo': Foo
459 "]],
460 ); 217 );
461} 218}
462 219
463#[test] 220#[test]
464fn coerce_autoderef_block() { 221fn coerce_autoderef_block() {
465 check_infer_with_mismatches( 222 check_no_mismatches(
466 r#" 223 r#"
467//- minicore: deref 224//- minicore: deref
468struct String {} 225struct String {}
@@ -473,71 +230,32 @@ fn test() {
473 takes_ref_str(&{ returns_string() }); 230 takes_ref_str(&{ returns_string() });
474} 231}
475"#, 232"#,
476 expect![[r#"
477 90..91 'x': &str
478 99..101 '{}': ()
479 132..143 '{ loop {} }': String
480 134..141 'loop {}': !
481 139..141 '{}': ()
482 154..199 '{ ... }); }': ()
483 160..173 'takes_ref_str': fn takes_ref_str(&str)
484 160..196 'takes_...g() })': ()
485 174..195 '&{ ret...ng() }': &String
486 175..195 '{ retu...ng() }': String
487 177..191 'returns_string': fn returns_string() -> String
488 177..193 'return...ring()': String
489 "#]],
490 ); 233 );
491} 234}
492 235
493#[test] 236#[test]
494fn closure_return_coerce() { 237fn closure_return_coerce() {
495 check_infer_with_mismatches( 238 check_no_mismatches(
496 r" 239 r"
497 fn foo() { 240fn foo() {
498 let x = || { 241 let x = || {
499 if true { 242 if true {
500 return &1u32; 243 return &1u32;
501 }
502 &&1u32
503 };
504 } 244 }
505 ", 245 &&1u32
506 expect![[r" 246 };
507 9..105 '{ ... }; }': () 247}",
508 19..20 'x': || -> &u32
509 23..102 '|| { ... }': || -> &u32
510 26..102 '{ ... }': &u32
511 36..81 'if tru... }': ()
512 39..43 'true': bool
513 44..81 '{ ... }': ()
514 58..70 'return &1u32': !
515 65..70 '&1u32': &u32
516 66..70 '1u32': u32
517 90..96 '&&1u32': &&u32
518 91..96 '&1u32': &u32
519 92..96 '1u32': u32
520 "]],
521 ); 248 );
522} 249}
523 250
524#[test] 251#[test]
525fn coerce_fn_item_to_fn_ptr() { 252fn coerce_fn_item_to_fn_ptr() {
526 check_infer_with_mismatches( 253 check_no_mismatches(
527 r" 254 r"
528 fn foo(x: u32) -> isize { 1 } 255fn foo(x: u32) -> isize { 1 }
529 fn test() { 256fn test() {
530 let f: fn(u32) -> isize = foo; 257 let f: fn(u32) -> isize = foo;
531 } 258}",
532 ",
533 expect![[r"
534 7..8 'x': u32
535 24..29 '{ 1 }': isize
536 26..27 '1': isize
537 40..78 '{ ...foo; }': ()
538 50..51 'f': fn(u32) -> isize
539 72..75 'foo': fn foo(u32) -> isize
540 "]],
541 ); 259 );
542} 260}
543 261
@@ -545,110 +263,62 @@ fn coerce_fn_item_to_fn_ptr() {
545fn coerce_fn_items_in_match_arms() { 263fn coerce_fn_items_in_match_arms() {
546 cov_mark::check!(coerce_fn_reification); 264 cov_mark::check!(coerce_fn_reification);
547 265
548 check_infer_with_mismatches( 266 check_types(
549 r" 267 r"
550 fn foo1(x: u32) -> isize { 1 } 268fn foo1(x: u32) -> isize { 1 }
551 fn foo2(x: u32) -> isize { 2 } 269fn foo2(x: u32) -> isize { 2 }
552 fn foo3(x: u32) -> isize { 3 } 270fn foo3(x: u32) -> isize { 3 }
553 fn test() { 271fn test() {
554 let x = match 1 { 272 let x = match 1 {
555 1 => foo1, 273 1 => foo1,
556 2 => foo2, 274 2 => foo2,
557 _ => foo3, 275 _ => foo3,
558 }; 276 };
559 } 277 x;
560 ", 278 //^ fn(u32) -> isize
561 expect![[r" 279}",
562 8..9 'x': u32
563 25..30 '{ 1 }': isize
564 27..28 '1': isize
565 39..40 'x': u32
566 56..61 '{ 2 }': isize
567 58..59 '2': isize
568 70..71 'x': u32
569 87..92 '{ 3 }': isize
570 89..90 '3': isize
571 103..192 '{ ... }; }': ()
572 113..114 'x': fn(u32) -> isize
573 117..189 'match ... }': fn(u32) -> isize
574 123..124 '1': i32
575 135..136 '1': i32
576 135..136 '1': i32
577 140..144 'foo1': fn foo1(u32) -> isize
578 154..155 '2': i32
579 154..155 '2': i32
580 159..163 'foo2': fn foo2(u32) -> isize
581 173..174 '_': i32
582 178..182 'foo3': fn foo3(u32) -> isize
583 "]],
584 ); 280 );
585} 281}
586 282
587#[test] 283#[test]
588fn coerce_closure_to_fn_ptr() { 284fn coerce_closure_to_fn_ptr() {
589 check_infer_with_mismatches( 285 check_no_mismatches(
590 r" 286 r"
591 fn test() { 287fn test() {
592 let f: fn(u32) -> isize = |x| { 1 }; 288 let f: fn(u32) -> isize = |x| { 1 };
593 } 289}",
594 ",
595 expect![[r"
596 10..54 '{ ...1 }; }': ()
597 20..21 'f': fn(u32) -> isize
598 42..51 '|x| { 1 }': |u32| -> isize
599 43..44 'x': u32
600 46..51 '{ 1 }': isize
601 48..49 '1': isize
602 "]],
603 ); 290 );
604} 291}
605 292
606#[test] 293#[test]
607fn coerce_placeholder_ref() { 294fn coerce_placeholder_ref() {
608 // placeholders should unify, even behind references 295 // placeholders should unify, even behind references
609 check_infer_with_mismatches( 296 check_no_mismatches(
610 r" 297 r"
611 struct S<T> { t: T } 298struct S<T> { t: T }
612 impl<TT> S<TT> { 299impl<TT> S<TT> {
613 fn get(&self) -> &TT { 300 fn get(&self) -> &TT {
614 &self.t 301 &self.t
615 } 302 }
616 } 303}",
617 ",
618 expect![[r"
619 50..54 'self': &S<TT>
620 63..86 '{ ... }': &TT
621 73..80 '&self.t': &TT
622 74..78 'self': &S<TT>
623 74..80 'self.t': TT
624 "]],
625 ); 304 );
626} 305}
627 306
628#[test] 307#[test]
629fn coerce_unsize_array() { 308fn coerce_unsize_array() {
630 check_infer_with_mismatches( 309 check_types(
631 r#" 310 r#"
632//- minicore: coerce_unsized 311//- minicore: coerce_unsized
633fn test() { 312fn test() {
634 let f: &[usize] = &[1, 2, 3]; 313 let f: &[usize] = &[1, 2, 3];
635} 314 //^ usize
636 "#, 315}"#,
637 expect![[r#"
638 10..47 '{ ... 3]; }': ()
639 20..21 'f': &[usize]
640 34..44 '&[1, 2, 3]': &[usize; 3]
641 35..44 '[1, 2, 3]': [usize; 3]
642 36..37 '1': usize
643 39..40 '2': usize
644 42..43 '3': usize
645 "#]],
646 ); 316 );
647} 317}
648 318
649#[test] 319#[test]
650fn coerce_unsize_trait_object_simple() { 320fn coerce_unsize_trait_object_simple() {
651 check_infer_with_mismatches( 321 check_types(
652 r#" 322 r#"
653//- minicore: coerce_unsized 323//- minicore: coerce_unsized
654trait Foo<T, U> {} 324trait Foo<T, U> {}
@@ -662,88 +332,18 @@ impl<T, X> Baz<T, X> for S<T, X> {}
662 332
663fn test() { 333fn test() {
664 let obj: &dyn Baz<i8, i16> = &S; 334 let obj: &dyn Baz<i8, i16> = &S;
335 //^ S<i8, i16>
665 let obj: &dyn Bar<_, i8, i16> = &S; 336 let obj: &dyn Bar<_, i8, i16> = &S;
337 //^ S<i8, i16>
666 let obj: &dyn Foo<i8, _> = &S; 338 let obj: &dyn Foo<i8, _> = &S;
667} 339 //^ S<i8, {unknown}>
668"#, 340}"#,
669 expect![[r#"
670 236..351 '{ ... &S; }': ()
671 246..249 'obj': &dyn Baz<i8, i16>
672 271..273 '&S': &S<i8, i16>
673 272..273 'S': S<i8, i16>
674 283..286 'obj': &dyn Bar<usize, i8, i16>
675 311..313 '&S': &S<i8, i16>
676 312..313 'S': S<i8, i16>
677 323..326 'obj': &dyn Foo<i8, usize>
678 346..348 '&S': &S<i8, {unknown}>
679 347..348 'S': S<i8, {unknown}>
680 "#]],
681 );
682}
683
684#[test]
685fn coerce_unsize_trait_object_to_trait_object() {
686 // FIXME: The rust reference says this should be possible, but rustc doesn't
687 // implement it. We used to support it, but Chalk doesn't. Here's the
688 // correct expect:
689 //
690 // 424..609 '{ ...bj2; }': ()
691 // 434..437 'obj': &dyn Baz<i8, i16>
692 // 459..461 '&S': &S<i8, i16>
693 // 460..461 'S': S<i8, i16>
694 // 471..474 'obj': &dyn Bar<usize, i8, i16>
695 // 496..499 'obj': &dyn Baz<i8, i16>
696 // 509..512 'obj': &dyn Foo<i8, usize>
697 // 531..534 'obj': &dyn Bar<usize, i8, i16>
698 // 544..548 'obj2': &dyn Baz<i8, i16>
699 // 570..572 '&S': &S<i8, i16>
700 // 571..572 'S': S<i8, i16>
701 // 582..583 '_': &dyn Foo<i8, usize>
702 // 602..606 'obj2': &dyn Baz<i8, i16>
703 check_infer_with_mismatches(
704 r#"
705//- minicore: coerce_unsized
706trait Foo<T, U> {}
707trait Bar<U, T, X>: Foo<T, U> {}
708trait Baz<T, X>: Bar<usize, T, X> {}
709
710struct S<T, X>;
711impl<T, X> Foo<T, usize> for S<T, X> {}
712impl<T, X> Bar<usize, T, X> for S<T, X> {}
713impl<T, X> Baz<T, X> for S<T, X> {}
714
715fn test() {
716 let obj: &dyn Baz<i8, i16> = &S;
717 let obj: &dyn Bar<_, _, _> = obj;
718 let obj: &dyn Foo<_, _> = obj;
719 let obj2: &dyn Baz<i8, i16> = &S;
720 let _: &dyn Foo<_, _> = obj2;
721}
722"#,
723 expect![[r#"
724 236..421 '{ ...bj2; }': ()
725 246..249 'obj': &dyn Baz<i8, i16>
726 271..273 '&S': &S<i8, i16>
727 272..273 'S': S<i8, i16>
728 283..286 'obj': &dyn Bar<{unknown}, {unknown}, {unknown}>
729 308..311 'obj': &dyn Baz<i8, i16>
730 321..324 'obj': &dyn Foo<{unknown}, {unknown}>
731 343..346 'obj': &dyn Bar<{unknown}, {unknown}, {unknown}>
732 356..360 'obj2': &dyn Baz<i8, i16>
733 382..384 '&S': &S<i8, i16>
734 383..384 'S': S<i8, i16>
735 394..395 '_': &dyn Foo<{unknown}, {unknown}>
736 414..418 'obj2': &dyn Baz<i8, i16>
737 308..311: expected &dyn Bar<{unknown}, {unknown}, {unknown}>, got &dyn Baz<i8, i16>
738 343..346: expected &dyn Foo<{unknown}, {unknown}>, got &dyn Bar<{unknown}, {unknown}, {unknown}>
739 414..418: expected &dyn Foo<{unknown}, {unknown}>, got &dyn Baz<i8, i16>
740 "#]],
741 ); 341 );
742} 342}
743 343
744#[test] 344#[test]
745fn coerce_unsize_super_trait_cycle() { 345fn coerce_unsize_super_trait_cycle() {
746 check_infer_with_mismatches( 346 check_no_mismatches(
747 r#" 347 r#"
748//- minicore: coerce_unsized 348//- minicore: coerce_unsized
749trait A {} 349trait A {}
@@ -762,22 +362,13 @@ fn test() {
762 let obj: &dyn A = &S; 362 let obj: &dyn A = &S;
763} 363}
764"#, 364"#,
765 expect![[r#"
766 140..195 '{ ... &S; }': ()
767 150..153 'obj': &dyn D
768 164..166 '&S': &S
769 165..166 'S': S
770 176..179 'obj': &dyn A
771 190..192 '&S': &S
772 191..192 'S': S
773 "#]],
774 ); 365 );
775} 366}
776 367
777#[test] 368#[test]
778fn coerce_unsize_generic() { 369fn coerce_unsize_generic() {
779 // FIXME: fix the type mismatches here 370 // FIXME: fix the type mismatches here
780 check_infer_with_mismatches( 371 check(
781 r#" 372 r#"
782//- minicore: coerce_unsized 373//- minicore: coerce_unsized
783struct Foo<T> { t: T }; 374struct Foo<T> { t: T };
@@ -785,73 +376,47 @@ struct Bar<T>(Foo<T>);
785 376
786fn test() { 377fn test() {
787 let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; 378 let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
379 //^^^^^^^^^ expected [usize], got [usize; 3]
788 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); 380 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
381 //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]>
789} 382}
790"#, 383"#,
791 expect![[r#"
792 58..166 '{ ... }); }': ()
793 68..69 '_': &Foo<[usize]>
794 87..108 '&Foo {..., 3] }': &Foo<[usize]>
795 88..108 'Foo { ..., 3] }': Foo<[usize]>
796 97..106 '[1, 2, 3]': [usize; 3]
797 98..99 '1': usize
798 101..102 '2': usize
799 104..105 '3': usize
800 118..119 '_': &Bar<[usize]>
801 137..163 '&Bar(F... 3] })': &Bar<[i32; 3]>
802 138..141 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]>
803 138..163 'Bar(Fo... 3] })': Bar<[i32; 3]>
804 142..162 'Foo { ..., 3] }': Foo<[i32; 3]>
805 151..160 '[1, 2, 3]': [i32; 3]
806 152..153 '1': i32
807 155..156 '2': i32
808 158..159 '3': i32
809 97..106: expected [usize], got [usize; 3]
810 137..163: expected &Bar<[usize]>, got &Bar<[i32; 3]>
811 "#]],
812 ); 384 );
813} 385}
814 386
815#[test] 387#[test]
816fn coerce_unsize_apit() { 388fn coerce_unsize_apit() {
817 // FIXME: #8984 389 // FIXME: #8984
818 check_infer_with_mismatches( 390 check(
819 r#" 391 r#"
820//- minicore: coerce_unsized 392//- minicore: coerce_unsized
821trait Foo {} 393trait Foo {}
822 394
823fn test(f: impl Foo) { 395fn test(f: impl Foo) {
824 let _: &dyn Foo = &f; 396 let _: &dyn Foo = &f;
397 //^^ expected &dyn Foo, got &impl Foo
825} 398}
826 "#, 399 "#,
827 expect![[r#"
828 22..23 'f': impl Foo
829 35..64 '{ ... &f; }': ()
830 45..46 '_': &dyn Foo
831 59..61 '&f': &impl Foo
832 60..61 'f': impl Foo
833 59..61: expected &dyn Foo, got &impl Foo
834 "#]],
835 ); 400 );
836} 401}
837 402
838#[test] 403#[test]
839fn infer_two_closures_lub() { 404fn two_closures_lub() {
840 check_types( 405 check_types(
841 r#" 406 r#"
842fn foo(c: i32) { 407fn foo(c: i32) {
843 let add = |a: i32, b: i32| a + b; 408 let add = |a: i32, b: i32| a + b;
844 let sub = |a, b| a - b; 409 let sub = |a, b| a - b;
845 //^ |i32, i32| -> i32 410 //^^^^^^^^^^^^ |i32, i32| -> i32
846 if c > 42 { add } else { sub }; 411 if c > 42 { add } else { sub };
847 //^ fn(i32, i32) -> i32 412 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fn(i32, i32) -> i32
848} 413}
849 "#, 414 "#,
850 ) 415 )
851} 416}
852 417
853#[test] 418#[test]
854fn infer_match_diverging_branch_1() { 419fn match_diverging_branch_1() {
855 check_types( 420 check_types(
856 r#" 421 r#"
857enum Result<T> { Ok(T), Err } 422enum Result<T> { Ok(T), Err }
@@ -870,7 +435,7 @@ fn test() -> i32 {
870} 435}
871 436
872#[test] 437#[test]
873fn infer_match_diverging_branch_2() { 438fn match_diverging_branch_2() {
874 // same as 1 except for order of branches 439 // same as 1 except for order of branches
875 check_types( 440 check_types(
876 r#" 441 r#"
diff --git a/crates/hir_ty/src/tests/display_source_code.rs b/crates/hir_ty/src/tests/display_source_code.rs
index 3d29021aa..058cd02d7 100644
--- a/crates/hir_ty/src/tests/display_source_code.rs
+++ b/crates/hir_ty/src/tests/display_source_code.rs
@@ -10,8 +10,8 @@ mod foo {
10 10
11fn bar() { 11fn bar() {
12 let foo: foo::Foo = foo::Foo; 12 let foo: foo::Foo = foo::Foo;
13 foo 13 foo;
14} //^ foo::Foo 14} //^^^ foo::Foo
15 15
16"#, 16"#,
17 ); 17 );
@@ -25,7 +25,7 @@ struct Foo<T = u8> { t: T }
25fn main() { 25fn main() {
26 let foo = Foo { t: 5u8 }; 26 let foo = Foo { t: 5u8 };
27 foo; 27 foo;
28} //^ Foo 28} //^^^ Foo
29"#, 29"#,
30 ); 30 );
31 31
@@ -35,7 +35,7 @@ struct Foo<K, T = u8> { k: K, t: T }
35fn main() { 35fn main() {
36 let foo = Foo { k: 400, t: 5u8 }; 36 let foo = Foo { k: 400, t: 5u8 };
37 foo; 37 foo;
38} //^ Foo<i32> 38} //^^^ Foo<i32>
39"#, 39"#,
40 ); 40 );
41} 41}
@@ -50,7 +50,7 @@ fn foo() -> *const (impl Unpin + Sized) { loop {} }
50fn main() { 50fn main() {
51 let foo = foo(); 51 let foo = foo();
52 foo; 52 foo;
53} //^ *const (impl Unpin + Sized) 53} //^^^ *const (impl Unpin + Sized)
54"#, 54"#,
55 ); 55 );
56} 56}
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index d14103aab..2cf41e49e 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -435,11 +435,11 @@ fn processes_impls_generated_by_macros() {
435macro_rules! m { 435macro_rules! m {
436 ($ident:ident) => (impl Trait for $ident {}) 436 ($ident:ident) => (impl Trait for $ident {})
437} 437}
438trait Trait { fn foo(self) -> u128 {} } 438trait Trait { fn foo(self) -> u128 { 0 } }
439struct S; 439struct S;
440m!(S); 440m!(S);
441fn test() { S.foo(); } 441fn test() { S.foo(); }
442 //^ u128 442 //^^^^^^^ u128
443"#, 443"#,
444 ); 444 );
445} 445}
@@ -457,7 +457,7 @@ impl S {
457} 457}
458 458
459fn test() { S.foo(); } 459fn test() { S.foo(); }
460 //^ u128 460 //^^^^^^^ u128
461"#, 461"#,
462 ); 462 );
463} 463}
@@ -479,7 +479,7 @@ impl S {
479} 479}
480 480
481fn test() { S.foo(); } 481fn test() { S.foo(); }
482 //^ u128 482 //^^^^^^^ u128
483"#, 483"#,
484 ); 484 );
485} 485}
@@ -743,7 +743,7 @@ include!("foo.rs");
743 743
744fn main() { 744fn main() {
745 bar(); 745 bar();
746} //^ u32 746} //^^^^^ u32
747 747
748//- /foo.rs 748//- /foo.rs
749fn bar() -> u32 {0} 749fn bar() -> u32 {0}
@@ -781,7 +781,7 @@ include!("f/foo.rs");
781 781
782fn main() { 782fn main() {
783 bar::bar(); 783 bar::bar();
784} //^ u32 784} //^^^^^^^^^^ u32
785 785
786//- /f/foo.rs 786//- /f/foo.rs
787pub mod bar; 787pub mod bar;
@@ -853,7 +853,7 @@ include!("foo.rs");
853 853
854fn main() { 854fn main() {
855 RegisterBlock { }; 855 RegisterBlock { };
856 //^ RegisterBlock 856 //^^^^^^^^^^^^^^^^^ RegisterBlock
857} 857}
858 "#; 858 "#;
859 let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data); 859 let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data);
@@ -879,7 +879,7 @@ include!(concat!("f", "oo.rs"));
879 879
880fn main() { 880fn main() {
881 bar(); 881 bar();
882} //^ u32 882} //^^^^^ u32
883 883
884//- /foo.rs 884//- /foo.rs
885fn bar() -> u32 {0} 885fn bar() -> u32 {0}
@@ -905,7 +905,7 @@ include!(concat!(env!("OUT_DIR"), "/foo.rs"));
905 905
906fn main() { 906fn main() {
907 bar(); 907 bar();
908} //^ {unknown} 908} //^^^^^ {unknown}
909 909
910//- /foo.rs 910//- /foo.rs
911fn bar() -> u32 {0} 911fn bar() -> u32 {0}
@@ -923,7 +923,7 @@ macro_rules! include {() => {}}
923include!("main.rs"); 923include!("main.rs");
924 924
925fn main() { 925fn main() {
926 0 926 0;
927} //^ i32 927} //^ i32
928"#, 928"#,
929 ); 929 );
@@ -979,7 +979,7 @@ fn infer_derive_clone_simple() {
979struct S; 979struct S;
980fn test() { 980fn test() {
981 S.clone(); 981 S.clone();
982} //^ S 982} //^^^^^^^^^ S
983 983
984//- /lib.rs crate:core 984//- /lib.rs crate:core
985pub mod prelude { 985pub mod prelude {
@@ -1028,7 +1028,7 @@ pub struct S;
1028use core::S; 1028use core::S;
1029fn test() { 1029fn test() {
1030 S.clone(); 1030 S.clone();
1031} //^ S 1031} //^^^^^^^^^ S
1032"#, 1032"#,
1033 ); 1033 );
1034} 1034}
@@ -1044,7 +1044,8 @@ struct S;
1044struct Wrapper<T>(T); 1044struct Wrapper<T>(T);
1045struct NonClone; 1045struct NonClone;
1046fn test() { 1046fn test() {
1047 (Wrapper(S).clone(), Wrapper(NonClone).clone()); 1047 let x = (Wrapper(S).clone(), Wrapper(NonClone).clone());
1048 x;
1048 //^ (Wrapper<S>, {unknown}) 1049 //^ (Wrapper<S>, {unknown})
1049} 1050}
1050 1051
@@ -1079,7 +1080,7 @@ struct S{}
1079 1080
1080fn test() { 1081fn test() {
1081 S{}; 1082 S{};
1082} //^ S 1083} //^^^ S
1083"#, 1084"#,
1084 ); 1085 );
1085} 1086}
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index d9b5ee9cf..3f7a37295 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -257,7 +257,7 @@ fn test() {
257mod foo { 257mod foo {
258 struct S; 258 struct S;
259 impl S { 259 impl S {
260 fn thing() -> i128 {} 260 fn thing() -> i128 { 0 }
261 } 261 }
262} 262}
263"#, 263"#,
@@ -267,164 +267,128 @@ mod foo {
267#[test] 267#[test]
268fn infer_trait_method_simple() { 268fn infer_trait_method_simple() {
269 // the trait implementation is intentionally incomplete -- it shouldn't matter 269 // the trait implementation is intentionally incomplete -- it shouldn't matter
270 check_infer( 270 check_types(
271 r#" 271 r#"
272 trait Trait1 { 272trait Trait1 {
273 fn method(&self) -> u32; 273 fn method(&self) -> u32;
274 } 274}
275 struct S1; 275struct S1;
276 impl Trait1 for S1 {} 276impl Trait1 for S1 {}
277 trait Trait2 { 277trait Trait2 {
278 fn method(&self) -> i128; 278 fn method(&self) -> i128;
279 } 279}
280 struct S2; 280struct S2;
281 impl Trait2 for S2 {} 281impl Trait2 for S2 {}
282 fn test() { 282fn test() {
283 S1.method(); // -> u32 283 S1.method();
284 S2.method(); // -> i128 284 //^^^^^^^^^^^ u32
285 } 285 S2.method(); // -> i128
286 //^^^^^^^^^^^ i128
287}
286 "#, 288 "#,
287 expect![[r#"
288 30..34 'self': &Self
289 109..113 'self': &Self
290 169..227 '{ ...i128 }': ()
291 175..177 'S1': S1
292 175..186 'S1.method()': u32
293 202..204 'S2': S2
294 202..213 'S2.method()': i128
295 "#]],
296 ); 289 );
297} 290}
298 291
299#[test] 292#[test]
300fn infer_trait_method_scoped() { 293fn infer_trait_method_scoped() {
301 // the trait implementation is intentionally incomplete -- it shouldn't matter 294 // the trait implementation is intentionally incomplete -- it shouldn't matter
302 check_infer( 295 check_types(
303 r#" 296 r#"
304 struct S; 297struct S;
305 mod foo { 298mod foo {
306 pub trait Trait1 { 299 pub trait Trait1 {
307 fn method(&self) -> u32; 300 fn method(&self) -> u32;
308 } 301 }
309 impl Trait1 for super::S {} 302 impl Trait1 for super::S {}
310 } 303}
311 mod bar { 304mod bar {
312 pub trait Trait2 { 305 pub trait Trait2 {
313 fn method(&self) -> i128; 306 fn method(&self) -> i128;
314 } 307 }
315 impl Trait2 for super::S {} 308 impl Trait2 for super::S {}
316 } 309}
317 310
318 mod foo_test { 311mod foo_test {
319 use super::S; 312 use super::S;
320 use super::foo::Trait1; 313 use super::foo::Trait1;
321 fn test() { 314 fn test() {
322 S.method(); // -> u32 315 S.method();
323 } 316 //^^^^^^^^^^ u32
324 } 317 }
318}
325 319
326 mod bar_test { 320mod bar_test {
327 use super::S; 321 use super::S;
328 use super::bar::Trait2; 322 use super::bar::Trait2;
329 fn test() { 323 fn test() {
330 S.method(); // -> i128 324 S.method();
331 } 325 //^^^^^^^^^^ i128
332 } 326 }
327}
333 "#, 328 "#,
334 expect![[r#"
335 62..66 'self': &Self
336 168..172 'self': &Self
337 299..336 '{ ... }': ()
338 309..310 'S': S
339 309..319 'S.method()': u32
340 415..453 '{ ... }': ()
341 425..426 'S': S
342 425..435 'S.method()': i128
343 "#]],
344 ); 329 );
345} 330}
346 331
347#[test] 332#[test]
348fn infer_trait_method_generic_1() { 333fn infer_trait_method_generic_1() {
349 // the trait implementation is intentionally incomplete -- it shouldn't matter 334 // the trait implementation is intentionally incomplete -- it shouldn't matter
350 check_infer( 335 check_types(
351 r#" 336 r#"
352 trait Trait<T> { 337trait Trait<T> {
353 fn method(&self) -> T; 338 fn method(&self) -> T;
354 } 339}
355 struct S; 340struct S;
356 impl Trait<u32> for S {} 341impl Trait<u32> for S {}
357 fn test() { 342fn test() {
358 S.method(); 343 S.method();
359 } 344 //^^^^^^^^^^ u32
345}
360 "#, 346 "#,
361 expect![[r#"
362 32..36 'self': &Self
363 91..110 '{ ...d(); }': ()
364 97..98 'S': S
365 97..107 'S.method()': u32
366 "#]],
367 ); 347 );
368} 348}
369 349
370#[test] 350#[test]
371fn infer_trait_method_generic_more_params() { 351fn infer_trait_method_generic_more_params() {
372 // the trait implementation is intentionally incomplete -- it shouldn't matter 352 // the trait implementation is intentionally incomplete -- it shouldn't matter
373 check_infer( 353 check_types(
374 r#" 354 r#"
375 trait Trait<T1, T2, T3> { 355trait Trait<T1, T2, T3> {
376 fn method1(&self) -> (T1, T2, T3); 356 fn method1(&self) -> (T1, T2, T3);
377 fn method2(&self) -> (T3, T2, T1); 357 fn method2(&self) -> (T3, T2, T1);
378 } 358}
379 struct S1; 359struct S1;
380 impl Trait<u8, u16, u32> for S1 {} 360impl Trait<u8, u16, u32> for S1 {}
381 struct S2; 361struct S2;
382 impl<T> Trait<i8, i16, T> for S2 {} 362impl<T> Trait<i8, i16, T> for S2 {}
383 fn test() { 363fn test() {
384 S1.method1(); // u8, u16, u32 364 S1.method1();
385 S1.method2(); // u32, u16, u8 365 //^^^^^^^^^^^^ (u8, u16, u32)
386 S2.method1(); // i8, i16, {unknown} 366 S1.method2();
387 S2.method2(); // {unknown}, i16, i8 367 //^^^^^^^^^^^^ (u32, u16, u8)
388 } 368 S2.method1();
369 //^^^^^^^^^^^^ (i8, i16, {unknown})
370 S2.method2();
371 //^^^^^^^^^^^^ ({unknown}, i16, i8)
372}
389 "#, 373 "#,
390 expect![[r#"
391 42..46 'self': &Self
392 81..85 'self': &Self
393 209..360 '{ ..., i8 }': ()
394 215..217 'S1': S1
395 215..227 'S1.method1()': (u8, u16, u32)
396 249..251 'S1': S1
397 249..261 'S1.method2()': (u32, u16, u8)
398 283..285 'S2': S2
399 283..295 'S2.method1()': (i8, i16, {unknown})
400 323..325 'S2': S2
401 323..335 'S2.method2()': ({unknown}, i16, i8)
402 "#]],
403 ); 374 );
404} 375}
405 376
406#[test] 377#[test]
407fn infer_trait_method_generic_2() { 378fn infer_trait_method_generic_2() {
408 // the trait implementation is intentionally incomplete -- it shouldn't matter 379 // the trait implementation is intentionally incomplete -- it shouldn't matter
409 check_infer( 380 check_types(
410 r#" 381 r#"
411 trait Trait<T> { 382trait Trait<T> {
412 fn method(&self) -> T; 383 fn method(&self) -> T;
413 } 384}
414 struct S<T>(T); 385struct S<T>(T);
415 impl<U> Trait<U> for S<U> {} 386impl<U> Trait<U> for S<U> {}
416 fn test() { 387fn test() {
417 S(1u32).method(); 388 S(1u32).method();
418 } 389 //^^^^^^^^^^^^^^^^ u32
390}
419 "#, 391 "#,
420 expect![[r#"
421 32..36 'self': &Self
422 101..126 '{ ...d(); }': ()
423 107..108 'S': S<u32>(u32) -> S<u32>
424 107..114 'S(1u32)': S<u32>
425 107..123 'S(1u32...thod()': u32
426 109..113 '1u32': u32
427 "#]],
428 ); 392 );
429} 393}
430 394
@@ -685,10 +649,10 @@ fn method_resolution_unify_impl_self_type() {
685 check_types( 649 check_types(
686 r#" 650 r#"
687struct S<T>; 651struct S<T>;
688impl S<u32> { fn foo(&self) -> u8 {} } 652impl S<u32> { fn foo(&self) -> u8 { 0 } }
689impl S<i32> { fn foo(&self) -> i8 {} } 653impl S<i32> { fn foo(&self) -> i8 { 0 } }
690fn test() { (S::<u32>.foo(), S::<i32>.foo()); } 654fn test() { (S::<u32>.foo(), S::<i32>.foo()); }
691 //^ (u8, i8) 655 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (u8, i8)
692"#, 656"#,
693 ); 657 );
694} 658}
@@ -702,7 +666,7 @@ struct S;
702impl S { fn foo(&self) -> i8 { 0 } } 666impl S { fn foo(&self) -> i8 { 0 } }
703impl Trait for S { fn foo(self) -> u128 { 0 } } 667impl Trait for S { fn foo(self) -> u128 { 0 } }
704fn test() { S.foo(); } 668fn test() { S.foo(); }
705 //^ u128 669 //^^^^^^^ u128
706"#, 670"#,
707 ); 671 );
708} 672}
@@ -716,7 +680,7 @@ struct S;
716impl Clone for S {} 680impl Clone for S {}
717impl Clone for &S {} 681impl Clone for &S {}
718fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } 682fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
719 //^ (S, S, &S) 683 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S)
720"#, 684"#,
721 ); 685 );
722} 686}
@@ -730,7 +694,7 @@ struct S;
730impl S { fn foo(self) -> i8 { 0 } } 694impl S { fn foo(self) -> i8 { 0 } }
731impl Trait for &S { fn foo(self) -> u128 { 0 } } 695impl Trait for &S { fn foo(self) -> u128 { 0 } }
732fn test() { (&S).foo(); } 696fn test() { (&S).foo(); }
733 //^ u128 697 //^^^^^^^^^^ u128
734"#, 698"#,
735 ); 699 );
736} 700}
@@ -744,7 +708,7 @@ struct S;
744impl S { fn foo(self) -> i8 { 0 } } 708impl S { fn foo(self) -> i8 { 0 } }
745impl Trait for S { fn foo(self) -> u128 { 0 } } 709impl Trait for S { fn foo(self) -> u128 { 0 } }
746fn test() { S.foo(); } 710fn test() { S.foo(); }
747 //^ i8 711 //^^^^^^^ i8
748"#, 712"#,
749 ); 713 );
750} 714}
@@ -758,7 +722,7 @@ struct S;
758impl S { fn foo(&self) -> i8 { 0 } } 722impl S { fn foo(&self) -> i8 { 0 } }
759impl Trait for &S { fn foo(self) -> u128 { 0 } } 723impl Trait for &S { fn foo(self) -> u128 { 0 } }
760fn test() { S.foo(); } 724fn test() { S.foo(); }
761 //^ i8 725 //^^^^^^^ i8
762"#, 726"#,
763 ); 727 );
764} 728}
@@ -771,7 +735,7 @@ trait Trait { fn foo(self) -> u128; }
771struct S; 735struct S;
772impl Trait for S { fn foo(self) -> u128 { 0 } } 736impl Trait for S { fn foo(self) -> u128 { 0 } }
773fn test() { (&S).foo(); } 737fn test() { (&S).foo(); }
774 //^ u128 738 //^^^^^^^^^^ u128
775"#, 739"#,
776 ); 740 );
777} 741}
@@ -784,7 +748,7 @@ fn method_resolution_unsize_array() {
784fn test() { 748fn test() {
785 let a = [1, 2, 3]; 749 let a = [1, 2, 3];
786 a.len(); 750 a.len();
787} //^ usize 751} //^^^^^^^ usize
788"#, 752"#,
789 ); 753 );
790} 754}
@@ -799,7 +763,7 @@ impl Clone for S {}
799 763
800fn test() { 764fn test() {
801 S.clone(); 765 S.clone();
802 //^ S 766 //^^^^^^^^^ S
803} 767}
804 768
805//- /lib.rs crate:core 769//- /lib.rs crate:core
@@ -823,7 +787,7 @@ trait Trait { fn foo(self) -> u128; }
823struct S; 787struct S;
824impl<T> Trait for T where T: UnknownTrait {} 788impl<T> Trait for T where T: UnknownTrait {}
825fn test() { (&S).foo(); } 789fn test() { (&S).foo(); }
826 //^ u128 790 //^^^^^^^^^^ u128
827"#, 791"#,
828 ); 792 );
829} 793}
@@ -841,7 +805,7 @@ trait Trait { fn foo(self) -> u128; }
841struct S; 805struct S;
842impl<T> Trait for T where T: Clone {} 806impl<T> Trait for T where T: Clone {}
843fn test() { (&S).foo(); } 807fn test() { (&S).foo(); }
844 //^ {unknown} 808 //^^^^^^^^^^ {unknown}
845"#, 809"#,
846 ); 810 );
847} 811}
@@ -856,7 +820,7 @@ trait Trait { fn foo(self) -> u128; }
856struct S; 820struct S;
857impl<T: Clone> Trait for T {} 821impl<T: Clone> Trait for T {}
858fn test() { (&S).foo(); } 822fn test() { (&S).foo(); }
859 //^ {unknown} 823 //^^^^^^^^^^ {unknown}
860"#, 824"#,
861 ); 825 );
862} 826}
@@ -871,7 +835,7 @@ struct S;
871impl Clone for S {} 835impl Clone for S {}
872impl<T> Trait for T where T: Clone {} 836impl<T> Trait for T where T: Clone {}
873fn test() { S.foo(); } 837fn test() { S.foo(); }
874 //^ u128 838 //^^^^^^^ u128
875"#, 839"#,
876 ); 840 );
877} 841}
@@ -887,7 +851,7 @@ struct S2;
887impl From<S2> for S1 {} 851impl From<S2> for S1 {}
888impl<T, U> Into<U> for T where U: From<T> {} 852impl<T, U> Into<U> for T where U: From<T> {}
889fn test() { S2.into(); } 853fn test() { S2.into(); }
890 //^ {unknown} 854 //^^^^^^^^^ {unknown}
891"#, 855"#,
892 ); 856 );
893} 857}
@@ -903,7 +867,7 @@ struct S2;
903impl From<S2> for S1 {} 867impl From<S2> for S1 {}
904impl<T, U: From<T>> Into<U> for T {} 868impl<T, U: From<T>> Into<U> for T {}
905fn test() { S2.into(); } 869fn test() { S2.into(); }
906 //^ {unknown} 870 //^^^^^^^^^ {unknown}
907"#, 871"#,
908 ); 872 );
909} 873}
@@ -933,7 +897,7 @@ fn main() {
933 let a = Wrapper::<Foo<f32>>::new(1.0); 897 let a = Wrapper::<Foo<f32>>::new(1.0);
934 let b = Wrapper::<Bar<f32>>::new(1.0); 898 let b = Wrapper::<Bar<f32>>::new(1.0);
935 (a, b); 899 (a, b);
936 //^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>) 900 //^^^^^^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)
937} 901}
938"#, 902"#,
939 ); 903 );
@@ -947,7 +911,7 @@ fn method_resolution_encountering_fn_type() {
947fn foo() {} 911fn foo() {}
948trait FnOnce { fn call(self); } 912trait FnOnce { fn call(self); }
949fn test() { foo.call(); } 913fn test() { foo.call(); }
950 //^ {unknown} 914 //^^^^^^^^^^ {unknown}
951"#, 915"#,
952 ); 916 );
953} 917}
@@ -1013,7 +977,7 @@ where
1013 Wrapper<T>: a::Foo, 977 Wrapper<T>: a::Foo,
1014{ 978{
1015 t.foo(); 979 t.foo();
1016} //^ {unknown} 980} //^^^^^^^ {unknown}
1017"#, 981"#,
1018 ); 982 );
1019} 983}
@@ -1030,7 +994,7 @@ impl A<i32> {
1030 994
1031fn main() { 995fn main() {
1032 A::from(3); 996 A::from(3);
1033} //^ A<i32> 997} //^^^^^^^^^^ A<i32>
1034"#, 998"#,
1035 ); 999 );
1036} 1000}
@@ -1058,7 +1022,7 @@ trait FnX {}
1058impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} 1022impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
1059 1023
1060fn test() { (S {}).method(); } 1024fn test() { (S {}).method(); }
1061 //^ () 1025 //^^^^^^^^^^^^^^^ ()
1062"#, 1026"#,
1063 ); 1027 );
1064} 1028}
@@ -1143,8 +1107,8 @@ impl<T> Slice<T> {
1143 1107
1144fn main() { 1108fn main() {
1145 let foo: Slice<u32>; 1109 let foo: Slice<u32>;
1146 (foo.into_vec()); // we don't actually support arbitrary self types, but we shouldn't crash at least 1110 foo.into_vec(); // we shouldn't crash on this at least
1147} //^ {unknown} 1111} //^^^^^^^^^^^^^^ {unknown}
1148"#, 1112"#,
1149 ); 1113 );
1150} 1114}
@@ -1165,7 +1129,7 @@ impl dyn Foo + '_ {
1165fn main() { 1129fn main() {
1166 let f = &42u32 as &dyn Foo; 1130 let f = &42u32 as &dyn Foo;
1167 f.dyn_foo(); 1131 f.dyn_foo();
1168 // ^u32 1132 // ^^^^^^^^^^^ u32
1169} 1133}
1170"#, 1134"#,
1171 ); 1135 );
@@ -1376,11 +1340,11 @@ pub trait IntoIterator {
1376 1340
1377impl<T> IntoIterator for [T; 1] { 1341impl<T> IntoIterator for [T; 1] {
1378 type Out = T; 1342 type Out = T;
1379 fn into_iter(self) -> Self::Out {} 1343 fn into_iter(self) -> Self::Out { loop {} }
1380} 1344}
1381impl<'a, T> IntoIterator for &'a [T] { 1345impl<'a, T> IntoIterator for &'a [T] {
1382 type Out = &'a T; 1346 type Out = &'a T;
1383 fn into_iter(self) -> Self::Out {} 1347 fn into_iter(self) -> Self::Out { loop {} }
1384} 1348}
1385 "#, 1349 "#,
1386 ); 1350 );
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 5adbe9c45..47aa30d2e 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_infer_with_mismatches, check_mismatches, check_types}; 3use super::{check, check_infer, check_infer_with_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn infer_pattern() { 6fn infer_pattern() {
@@ -518,7 +518,7 @@ fn infer_generics_in_patterns() {
518 518
519#[test] 519#[test]
520fn infer_const_pattern() { 520fn infer_const_pattern() {
521 check_mismatches( 521 check(
522 r#" 522 r#"
523enum Option<T> { None } 523enum Option<T> { None }
524use Option::None; 524use Option::None;
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 0f418ea49..8c5e8954c 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_types}; 3use super::{check_infer, check_no_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn bug_484() { 6fn bug_484() {
@@ -422,20 +422,20 @@ fn issue_2683_chars_impl() {
422pub struct Chars<'a> {} 422pub struct Chars<'a> {}
423impl<'a> Iterator for Chars<'a> { 423impl<'a> Iterator for Chars<'a> {
424 type Item = char; 424 type Item = char;
425 fn next(&mut self) -> Option<char> {} 425 fn next(&mut self) -> Option<char> { loop {} }
426} 426}
427 427
428fn test() { 428fn test() {
429 let chars: Chars<'_>; 429 let chars: Chars<'_>;
430 (chars.next(), chars.nth(1)); 430 (chars.next(), chars.nth(1));
431} //^ (Option<char>, Option<char>) 431} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Option<char>, Option<char>)
432"#, 432"#,
433 ); 433 );
434} 434}
435 435
436#[test] 436#[test]
437fn issue_3642_bad_macro_stackover() { 437fn issue_3642_bad_macro_stackover() {
438 check_types( 438 check_no_mismatches(
439 r#" 439 r#"
440#[macro_export] 440#[macro_export]
441macro_rules! match_ast { 441macro_rules! match_ast {
@@ -452,7 +452,6 @@ macro_rules! match_ast {
452 452
453fn main() { 453fn main() {
454 let anchor = match_ast! { 454 let anchor = match_ast! {
455 //^ ()
456 match parent { 455 match parent {
457 as => {}, 456 as => {},
458 _ => return None 457 _ => return None
@@ -956,7 +955,7 @@ trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
956 955
957fn clone_iter<T>(s: Iter<T>) { 956fn clone_iter<T>(s: Iter<T>) {
958 s.inner.clone_box(); 957 s.inner.clone_box();
959 //^^^^^^^^^^^^^^^^^^^ () 958 //^^^^^^^^^^^^^^^^^^^ ()
960} 959}
961"#, 960"#,
962 ) 961 )
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 108ff3179..b4bcc6d95 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -60,7 +60,7 @@ enum Nat { Succ(Self), Demo(Nat), Zero }
60fn test() { 60fn test() {
61 let foo: Nat = Nat::Zero; 61 let foo: Nat = Nat::Zero;
62 if let Nat::Succ(x) = foo { 62 if let Nat::Succ(x) = foo {
63 x 63 x;
64 } //^ Nat 64 } //^ Nat
65} 65}
66"#, 66"#,
@@ -138,7 +138,7 @@ enum Option<T> { Some(T), None }
138fn test() { 138fn test() {
139 let foo: Option<f32> = None; 139 let foo: Option<f32> = None;
140 while let Option::Some(x) = foo { 140 while let Option::Some(x) = foo {
141 x 141 x;
142 } //^ f32 142 } //^ f32
143} 143}
144"#, 144"#,
@@ -1745,7 +1745,7 @@ impl i32 { fn foo(&self) -> Foo { Foo } }
1745fn main() { 1745fn main() {
1746 let x: i32 = i32; 1746 let x: i32 = i32;
1747 x.foo(); 1747 x.foo();
1748 //^ Foo 1748 //^^^^^^^ Foo
1749}"#, 1749}"#,
1750 ); 1750 );
1751} 1751}
@@ -1763,7 +1763,7 @@ fn main() {
1763 fn inner() {} 1763 fn inner() {}
1764 let x: i32 = i32; 1764 let x: i32 = i32;
1765 x.foo(); 1765 x.foo();
1766 //^ Foo 1766 //^^^^^^^ Foo
1767}"#, 1767}"#,
1768 ); 1768 );
1769} 1769}
@@ -1781,7 +1781,7 @@ fn foo() -> &'static str { "" }
1781 1781
1782fn main() { 1782fn main() {
1783 foo(); 1783 foo();
1784 //^ &str 1784 //^^^^^ &str
1785}"#, 1785}"#,
1786 ); 1786 );
1787} 1787}
@@ -1799,7 +1799,7 @@ fn foo() -> &'static str { "" }
1799 1799
1800fn main() { 1800fn main() {
1801 str::foo(); 1801 str::foo();
1802 //^ u32 1802 //^^^^^^^^^^ u32
1803}"#, 1803}"#,
1804 ); 1804 );
1805} 1805}
@@ -1825,9 +1825,9 @@ mod d {
1825 1825
1826fn main() { 1826fn main() {
1827 d::foo(); 1827 d::foo();
1828 //^ u8 1828 //^^^^^^^^ u8
1829 d::foo{a:0}; 1829 d::foo{a:0};
1830 //^ u8 1830 //^^^^^^^^^^^ foo
1831}"#, 1831}"#,
1832 ); 1832 );
1833} 1833}
@@ -2677,7 +2677,7 @@ fn prelude_2015() {
2677//- /main.rs edition:2015 crate:main deps:core 2677//- /main.rs edition:2015 crate:main deps:core
2678fn f() { 2678fn f() {
2679 Rust; 2679 Rust;
2680 //^ Rust 2680 //^^^^ Rust
2681} 2681}
2682 2682
2683//- /core.rs crate:core 2683//- /core.rs crate:core
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 279a1354a..a0ddad570 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -1,6 +1,7 @@
1use cov_mark::check;
1use expect_test::expect; 2use expect_test::expect;
2 3
3use super::{check_infer, check_infer_with_mismatches, check_types}; 4use super::{check, check_infer, check_infer_with_mismatches, check_types};
4 5
5#[test] 6#[test]
6fn infer_await() { 7fn infer_await() {
@@ -285,7 +286,7 @@ mod ops {
285 286
286#[test] 287#[test]
287fn infer_from_bound_1() { 288fn infer_from_bound_1() {
288 check_infer( 289 check_types(
289 r#" 290 r#"
290trait Trait<T> {} 291trait Trait<T> {}
291struct S<T>(T); 292struct S<T>(T);
@@ -293,99 +294,62 @@ impl<U> Trait<U> for S<U> {}
293fn foo<T: Trait<u32>>(t: T) {} 294fn foo<T: Trait<u32>>(t: T) {}
294fn test() { 295fn test() {
295 let s = S(unknown); 296 let s = S(unknown);
297 // ^^^^^^^ u32
296 foo(s); 298 foo(s);
297}"#, 299}"#,
298 expect![[r#"
299 85..86 't': T
300 91..93 '{}': ()
301 104..143 '{ ...(s); }': ()
302 114..115 's': S<u32>
303 118..119 'S': S<u32>(u32) -> S<u32>
304 118..128 'S(unknown)': S<u32>
305 120..127 'unknown': u32
306 134..137 'foo': fn foo<S<u32>>(S<u32>)
307 134..140 'foo(s)': ()
308 138..139 's': S<u32>
309 "#]],
310 ); 300 );
311} 301}
312 302
313#[test] 303#[test]
314fn infer_from_bound_2() { 304fn infer_from_bound_2() {
315 check_infer( 305 check_types(
316 r#" 306 r#"
317trait Trait<T> {} 307trait Trait<T> {}
318struct S<T>(T); 308struct S<T>(T);
319impl<U> Trait<U> for S<U> {} 309impl<U> Trait<U> for S<U> {}
320fn foo<U, T: Trait<U>>(t: T) -> U {} 310fn foo<U, T: Trait<U>>(t: T) -> U { loop {} }
321fn test() { 311fn test() {
322 let s = S(unknown); 312 let s = S(unknown);
313 // ^^^^^^^ u32
323 let x: u32 = foo(s); 314 let x: u32 = foo(s);
324}"#, 315}"#,
325 expect![[r#"
326 86..87 't': T
327 97..99 '{}': ()
328 110..162 '{ ...(s); }': ()
329 120..121 's': S<u32>
330 124..125 'S': S<u32>(u32) -> S<u32>
331 124..134 'S(unknown)': S<u32>
332 126..133 'unknown': u32
333 144..145 'x': u32
334 153..156 'foo': fn foo<u32, S<u32>>(S<u32>) -> u32
335 153..159 'foo(s)': u32
336 157..158 's': S<u32>
337 "#]],
338 ); 316 );
339} 317}
340 318
341#[test] 319#[test]
342fn trait_default_method_self_bound_implements_trait() { 320fn trait_default_method_self_bound_implements_trait() {
343 cov_mark::check!(trait_self_implements_self); 321 cov_mark::check!(trait_self_implements_self);
344 check_infer( 322 check(
345 r#" 323 r#"
346trait Trait { 324trait Trait {
347 fn foo(&self) -> i64; 325 fn foo(&self) -> i64;
348 fn bar(&self) -> { 326 fn bar(&self) -> () {
349 let x = self.foo(); 327 self.foo();
328 // ^^^^^^^^^^ type: i64
350 } 329 }
351}"#, 330}"#,
352 expect![[r#"
353 26..30 'self': &Self
354 52..56 'self': &Self
355 61..96 '{ ... }': ()
356 75..76 'x': i64
357 79..83 'self': &Self
358 79..89 'self.foo()': i64
359 "#]],
360 ); 331 );
361} 332}
362 333
363#[test] 334#[test]
364fn trait_default_method_self_bound_implements_super_trait() { 335fn trait_default_method_self_bound_implements_super_trait() {
365 check_infer( 336 check(
366 r#" 337 r#"
367trait SuperTrait { 338trait SuperTrait {
368 fn foo(&self) -> i64; 339 fn foo(&self) -> i64;
369} 340}
370trait Trait: SuperTrait { 341trait Trait: SuperTrait {
371 fn bar(&self) -> { 342 fn bar(&self) -> () {
372 let x = self.foo(); 343 self.foo();
344 // ^^^^^^^^^^ type: i64
373 } 345 }
374}"#, 346}"#,
375 expect![[r#"
376 31..35 'self': &Self
377 85..89 'self': &Self
378 94..129 '{ ... }': ()
379 108..109 'x': i64
380 112..116 'self': &Self
381 112..122 'self.foo()': i64
382 "#]],
383 ); 347 );
384} 348}
385 349
386#[test] 350#[test]
387fn infer_project_associated_type() { 351fn infer_project_associated_type() {
388 check_infer( 352 check_types(
389 r#" 353 r#"
390trait Iterable { 354trait Iterable {
391 type Item; 355 type Item;
@@ -394,89 +358,62 @@ struct S;
394impl Iterable for S { type Item = u32; } 358impl Iterable for S { type Item = u32; }
395fn test<T: Iterable>() { 359fn test<T: Iterable>() {
396 let x: <S as Iterable>::Item = 1; 360 let x: <S as Iterable>::Item = 1;
397 let y: <T as Iterable>::Item = no_matter; 361 // ^ u32
398 let z: T::Item = no_matter; 362 let y: <T as Iterable>::Item = u;
399 let a: <T>::Item = no_matter; 363 // ^ Iterable::Item<T>
364 let z: T::Item = u;
365 // ^ Iterable::Item<T>
366 let a: <T>::Item = u;
367 // ^ Iterable::Item<T>
400}"#, 368}"#,
401 expect![[r#"
402 108..261 '{ ...ter; }': ()
403 118..119 'x': u32
404 145..146 '1': u32
405 156..157 'y': Iterable::Item<T>
406 183..192 'no_matter': Iterable::Item<T>
407 202..203 'z': Iterable::Item<T>
408 215..224 'no_matter': Iterable::Item<T>
409 234..235 'a': Iterable::Item<T>
410 249..258 'no_matter': Iterable::Item<T>
411 "#]],
412 ); 369 );
413} 370}
414 371
415#[test] 372#[test]
416fn infer_return_associated_type() { 373fn infer_return_associated_type() {
417 check_infer( 374 check_types(
418 r#" 375 r#"
419trait Iterable { 376trait Iterable {
420 type Item; 377 type Item;
421} 378}
422struct S; 379struct S;
423impl Iterable for S { type Item = u32; } 380impl Iterable for S { type Item = u32; }
424fn foo1<T: Iterable>(t: T) -> T::Item {} 381fn foo1<T: Iterable>(t: T) -> T::Item { loop {} }
425fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {} 382fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item { loop {} }
426fn foo3<T: Iterable>(t: T) -> <T>::Item {} 383fn foo3<T: Iterable>(t: T) -> <T>::Item { loop {} }
427fn test() { 384fn test() {
428 let x = foo1(S); 385 foo1(S);
429 let y = foo2(S); 386 // ^^^^^^^ u32
430 let z = foo3(S); 387 foo2(S);
388 // ^^^^^^^ u32
389 foo3(S);
390 // ^^^^^^^ u32
431}"#, 391}"#,
432 expect![[r#"
433 106..107 't': T
434 123..125 '{}': ()
435 147..148 't': T
436 178..180 '{}': ()
437 202..203 't': T
438 221..223 '{}': ()
439 234..300 '{ ...(S); }': ()
440 244..245 'x': u32
441 248..252 'foo1': fn foo1<S>(S) -> <S as Iterable>::Item
442 248..255 'foo1(S)': u32
443 253..254 'S': S
444 265..266 'y': u32
445 269..273 'foo2': fn foo2<S>(S) -> <S as Iterable>::Item
446 269..276 'foo2(S)': u32
447 274..275 'S': S
448 286..287 'z': u32
449 290..294 'foo3': fn foo3<S>(S) -> <S as Iterable>::Item
450 290..297 'foo3(S)': u32
451 295..296 'S': S
452 "#]],
453 ); 392 );
454} 393}
455 394
456#[test] 395#[test]
457fn infer_associated_type_bound() { 396fn infer_associated_type_bound() {
458 check_infer( 397 check_types(
459 r#" 398 r#"
460trait Iterable { 399trait Iterable {
461 type Item; 400 type Item;
462} 401}
463fn test<T: Iterable<Item=u32>>() { 402fn test<T: Iterable<Item=u32>>() {
464 let y: T::Item = unknown; 403 let y: T::Item = unknown;
404 // ^^^^^^^ u32
465}"#, 405}"#,
466 expect![[r#"
467 67..100 '{ ...own; }': ()
468 77..78 'y': u32
469 90..97 'unknown': u32
470 "#]],
471 ); 406 );
472} 407}
473 408
474#[test] 409#[test]
475fn infer_const_body() { 410fn infer_const_body() {
411 // FIXME make check_types work with other bodies
476 check_infer( 412 check_infer(
477 r#" 413 r#"
478const A: u32 = 1 + 1; 414const A: u32 = 1 + 1;
479static B: u64 = { let x = 1; x };"#, 415static B: u64 = { let x = 1; x };
416"#,
480 expect![[r#" 417 expect![[r#"
481 15..16 '1': u32 418 15..16 '1': u32
482 15..20 '1 + 1': u32 419 15..20 '1 + 1': u32
@@ -637,12 +574,12 @@ impl<T> core::ops::Deref for Arc<T> {
637 574
638struct S; 575struct S;
639impl S { 576impl S {
640 fn foo(&self) -> u128 {} 577 fn foo(&self) -> u128 { 0 }
641} 578}
642 579
643fn test(s: Arc<S>) { 580fn test(s: Arc<S>) {
644 (*s, s.foo()); 581 (*s, s.foo());
645} //^ (S, u128) 582} //^^^^^^^^^^^^^ (S, u128)
646"#, 583"#,
647 ); 584 );
648} 585}
@@ -653,7 +590,7 @@ fn deref_trait_with_inference_var() {
653 r#" 590 r#"
654//- minicore: deref 591//- minicore: deref
655struct Arc<T>; 592struct Arc<T>;
656fn new_arc<T>() -> Arc<T> {} 593fn new_arc<T>() -> Arc<T> { Arc }
657impl<T> core::ops::Deref for Arc<T> { 594impl<T> core::ops::Deref for Arc<T> {
658 type Target = T; 595 type Target = T;
659} 596}
@@ -663,8 +600,8 @@ fn foo(a: Arc<S>) {}
663 600
664fn test() { 601fn test() {
665 let a = new_arc(); 602 let a = new_arc();
666 let b = (*a); 603 let b = *a;
667 //^ S 604 //^^ S
668 foo(a); 605 foo(a);
669} 606}
670"#, 607"#,
@@ -684,7 +621,7 @@ impl core::ops::Deref for S {
684 621
685fn test(s: S) { 622fn test(s: S) {
686 s.foo(); 623 s.foo();
687} //^ {unknown} 624} //^^^^^^^ {unknown}
688"#, 625"#,
689 ); 626 );
690} 627}
@@ -701,12 +638,12 @@ impl<T: ?Sized> core::ops::Deref for Arc<T> {
701 638
702struct S; 639struct S;
703impl S { 640impl S {
704 fn foo(&self) -> u128 {} 641 fn foo(&self) -> u128 { 0 }
705} 642}
706 643
707fn test(s: Arc<S>) { 644fn test(s: Arc<S>) {
708 (*s, s.foo()); 645 (*s, s.foo());
709} //^ (S, u128) 646} //^^^^^^^^^^^^^ (S, u128)
710"#, 647"#,
711 ); 648 );
712} 649}
@@ -720,11 +657,11 @@ struct S;
720trait Trait<T> {} 657trait Trait<T> {}
721impl Trait<u32> for S {} 658impl Trait<u32> for S {}
722 659
723fn foo<T: Trait<U>, U>(t: T) -> U {} 660fn foo<T: Trait<U>, U>(t: T) -> U { loop {} }
724 661
725fn test(s: S) { 662fn test(s: S) {
726 (foo(s)); 663 foo(s);
727} //^ u32 664} //^^^^^^ u32
728"#, 665"#,
729 ); 666 );
730} 667}
@@ -741,12 +678,12 @@ impl Trait<isize> for S {}
741 678
742struct O; 679struct O;
743impl O { 680impl O {
744 fn foo<T: Trait<U>, U>(&self, t: T) -> U {} 681 fn foo<T: Trait<U>, U>(&self, t: T) -> U { loop {} }
745} 682}
746 683
747fn test() { 684fn test() {
748 O.foo(S); 685 O.foo(S);
749} //^ isize 686} //^^^^^^^^ isize
750"#, 687"#,
751 ); 688 );
752} 689}
@@ -761,12 +698,12 @@ trait Trait<T> {}
761impl Trait<i64> for S {} 698impl Trait<i64> for S {}
762 699
763impl S { 700impl S {
764 fn foo<U>(&self) -> U where Self: Trait<U> {} 701 fn foo<U>(&self) -> U where Self: Trait<U> { loop {} }
765} 702}
766 703
767fn test() { 704fn test() {
768 S.foo(); 705 S.foo();
769} //^ i64 706} //^^^^^^^ i64
770"#, 707"#,
771 ); 708 );
772} 709}
@@ -782,12 +719,12 @@ impl Trait<&str> for S {}
782 719
783struct O<T>; 720struct O<T>;
784impl<U, T: Trait<U>> O<T> { 721impl<U, T: Trait<U>> O<T> {
785 fn foo(&self) -> U {} 722 fn foo(&self) -> U { loop {} }
786} 723}
787 724
788fn test(o: O<S>) { 725fn test(o: O<S>) {
789 o.foo(); 726 o.foo();
790} //^ &str 727} //^^^^^^^ &str
791"#, 728"#,
792 ); 729 );
793} 730}
@@ -802,7 +739,7 @@ struct S;
802impl Clone for S {} 739impl Clone for S {}
803impl<T> Trait for T where T: Clone {} 740impl<T> Trait for T where T: Clone {}
804fn test<T: Clone>(t: T) { t.foo(); } 741fn test<T: Clone>(t: T) { t.foo(); }
805 //^ u128 742 //^^^^^^^ u128
806"#, 743"#,
807 ); 744 );
808} 745}
@@ -818,7 +755,7 @@ struct S;
818impl Clone for S {} 755impl Clone for S {}
819impl<T> Trait for T where T: Clone {} 756impl<T> Trait for T where T: Clone {}
820fn test<T>(t: T) { t.foo(); } 757fn test<T>(t: T) { t.foo(); }
821 //^ {unknown} 758 //^^^^^^^ {unknown}
822"#, 759"#,
823 ); 760 );
824} 761}
@@ -831,7 +768,7 @@ trait Trait { fn foo(self) -> u128; }
831struct S; 768struct S;
832impl Trait for S {} 769impl Trait for S {}
833fn test<T: Trait>(t: T) { t.foo(); } 770fn test<T: Trait>(t: T) { t.foo(); }
834 //^ u128 771 //^^^^^^^ u128
835"#, 772"#,
836 ); 773 );
837} 774}
@@ -844,7 +781,7 @@ trait Trait { fn foo(self) -> u128; }
844struct S; 781struct S;
845impl Trait for S {} 782impl Trait for S {}
846fn test<T>(t: T) { t.foo(); } 783fn test<T>(t: T) { t.foo(); }
847 //^ {unknown} 784 //^^^^^^^ {unknown}
848"#, 785"#,
849 ); 786 );
850} 787}
@@ -858,8 +795,8 @@ trait Trait {}
858impl<T> core::ops::Deref for T where T: Trait { 795impl<T> core::ops::Deref for T where T: Trait {
859 type Target = i128; 796 type Target = i128;
860} 797}
861fn test<T: Trait>(t: T) { (*t); } 798fn test<T: Trait>(t: T) { *t; }
862 //^ i128 799 //^^ i128
863"#, 800"#,
864 ); 801 );
865} 802}
@@ -1380,12 +1317,12 @@ fn error_bound_chalk() {
1380 check_types( 1317 check_types(
1381 r#" 1318 r#"
1382trait Trait { 1319trait Trait {
1383 fn foo(&self) -> u32 {} 1320 fn foo(&self) -> u32 { 0 }
1384} 1321}
1385 1322
1386fn test(x: (impl Trait + UnknownTrait)) { 1323fn test(x: (impl Trait + UnknownTrait)) {
1387 x.foo(); 1324 x.foo();
1388} //^ u32 1325} //^^^^^^^ u32
1389"#, 1326"#,
1390 ); 1327 );
1391} 1328}
@@ -1476,7 +1413,7 @@ trait Clone {
1476fn api_walkthrough() { 1413fn api_walkthrough() {
1477 for node in foo() { 1414 for node in foo() {
1478 node.clone(); 1415 node.clone();
1479 } //^ {unknown} 1416 } //^^^^^^^^^^^^ {unknown}
1480} 1417}
1481"#, 1418"#,
1482 ); 1419 );
@@ -1513,13 +1450,13 @@ fn where_clause_trait_in_scope_for_method_resolution() {
1513 r#" 1450 r#"
1514mod foo { 1451mod foo {
1515 trait Trait { 1452 trait Trait {
1516 fn foo(&self) -> u32 {} 1453 fn foo(&self) -> u32 { 0 }
1517 } 1454 }
1518} 1455}
1519 1456
1520fn test<T: foo::Trait>(x: T) { 1457fn test<T: foo::Trait>(x: T) {
1521 x.foo(); 1458 x.foo();
1522} //^ u32 1459} //^^^^^^^ u32
1523"#, 1460"#,
1524 ); 1461 );
1525} 1462}
@@ -1982,7 +1919,7 @@ fn fn_item_fn_trait() {
1982//- minicore: fn 1919//- minicore: fn
1983struct S; 1920struct S;
1984 1921
1985fn foo() -> S {} 1922fn foo() -> S { S }
1986 1923
1987fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() } 1924fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() }
1988 1925
@@ -2009,7 +1946,7 @@ trait Trait2 {
2009fn test<T: Trait>() where T::Item: Trait2 { 1946fn test<T: Trait>() where T::Item: Trait2 {
2010 let x: T::Item = no_matter; 1947 let x: T::Item = no_matter;
2011 x.foo(); 1948 x.foo();
2012} //^ u32 1949} //^^^^^^^ u32
2013"#, 1950"#,
2014 ); 1951 );
2015} 1952}
@@ -2029,7 +1966,7 @@ trait Trait2 {
2029fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { 1966fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
2030 let x: T::Item = no_matter; 1967 let x: T::Item = no_matter;
2031 x.foo(); 1968 x.foo();
2032} //^ u32 1969} //^^^^^^^ u32
2033"#, 1970"#,
2034 ); 1971 );
2035} 1972}
@@ -2092,7 +2029,7 @@ impl Trait for S {
2092 2029
2093fn test() { 2030fn test() {
2094 S.f(); 2031 S.f();
2095} //^ u32 2032} //^^^^^ u32
2096"#, 2033"#,
2097 ); 2034 );
2098} 2035}
@@ -2120,7 +2057,7 @@ where
2120 2057
2121fn foo<I: Interner>(interner: &I, t: Ty<I>) { 2058fn foo<I: Interner>(interner: &I, t: Ty<I>) {
2122 fold(interner, t); 2059 fold(interner, t);
2123} //^ Ty<I> 2060} //^^^^^^^^^^^^^^^^^ Ty<I>
2124"#, 2061"#,
2125 ); 2062 );
2126} 2063}
@@ -2139,7 +2076,7 @@ impl Trait<Self> for S {}
2139 2076
2140fn test() { 2077fn test() {
2141 S.foo(); 2078 S.foo();
2142} //^ () 2079} //^^^^^^^ ()
2143"#, 2080"#,
2144 ); 2081 );
2145} 2082}
@@ -2158,7 +2095,7 @@ impl Trait for S<Self> {}
2158 2095
2159fn test() { 2096fn test() {
2160 S.foo(); 2097 S.foo();
2161} //^ {unknown} 2098} //^^^^^^^ {unknown}
2162"#, 2099"#,
2163 ); 2100 );
2164} 2101}
@@ -2176,7 +2113,7 @@ trait Trait2<T> {}
2176 2113
2177fn test<T: Trait>() where T: Trait2<T::Item> { 2114fn test<T: Trait>() where T: Trait2<T::Item> {
2178 let x: T::Item = no_matter; 2115 let x: T::Item = no_matter;
2179} //^ {unknown} 2116} //^^^^^^^^^ {unknown}
2180"#, 2117"#,
2181 ); 2118 );
2182} 2119}
@@ -2193,7 +2130,7 @@ trait Trait<T> {
2193 2130
2194fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { 2131fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
2195 let x: T::Item = no_matter; 2132 let x: T::Item = no_matter;
2196} //^ {unknown} 2133} //^^^^^^^^^ {unknown}
2197"#, 2134"#,
2198 ); 2135 );
2199} 2136}
@@ -2211,7 +2148,7 @@ trait Trait {
2211 2148
2212fn test<T>() where T: Trait<OtherItem = T::Item> { 2149fn test<T>() where T: Trait<OtherItem = T::Item> {
2213 let x: T::Item = no_matter; 2150 let x: T::Item = no_matter;
2214} //^ Trait::Item<T> 2151} //^^^^^^^^^ Trait::Item<T>
2215"#, 2152"#,
2216 ); 2153 );
2217} 2154}
@@ -2243,7 +2180,7 @@ fn test<T>(t: T) where T: UnificationStoreMut {
2243 t.push(x); 2180 t.push(x);
2244 let y: Key<T>; 2181 let y: Key<T>;
2245 (x, y); 2182 (x, y);
2246} //^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>) 2183} //^^^^^^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>)
2247"#, 2184"#,
2248 ); 2185 );
2249} 2186}
@@ -2268,7 +2205,7 @@ impl<T: Iterator> Iterator for S<T> {
2268fn test<I: Iterator<Item: OtherTrait<u32>>>() { 2205fn test<I: Iterator<Item: OtherTrait<u32>>>() {
2269 let x: <S<I> as Iterator>::Item; 2206 let x: <S<I> as Iterator>::Item;
2270 x.foo(); 2207 x.foo();
2271} //^ u32 2208} //^^^^^^^ u32
2272"#, 2209"#,
2273 ); 2210 );
2274} 2211}
@@ -2470,7 +2407,7 @@ impl<T: Trait> Trait for S<T> {
2470fn test<T: Trait>() { 2407fn test<T: Trait>() {
2471 let y: <S<T> as Trait>::Item = no_matter; 2408 let y: <S<T> as Trait>::Item = no_matter;
2472 y.foo(); 2409 y.foo();
2473} //^ u32 2410} //^^^^^^^ u32
2474"#, 2411"#,
2475 ); 2412 );
2476} 2413}
@@ -2490,7 +2427,7 @@ trait Trait {
2490 2427
2491fn test(x: Box<dyn Trait>) { 2428fn test(x: Box<dyn Trait>) {
2492 x.foo(); 2429 x.foo();
2493} //^ () 2430} //^^^^^^^ ()
2494"#, 2431"#,
2495 ); 2432 );
2496} 2433}
@@ -2509,7 +2446,7 @@ impl ToOwned for str {
2509} 2446}
2510fn test() { 2447fn test() {
2511 "foo".to_owned(); 2448 "foo".to_owned();
2512} //^ String 2449} //^^^^^^^^^^^^^^^^ String
2513"#, 2450"#,
2514 ); 2451 );
2515} 2452}
@@ -2649,7 +2586,7 @@ impl<T:A> B for T {
2649 2586
2650fn main() { 2587fn main() {
2651 Bar::foo(); 2588 Bar::foo();
2652} //^ Foo 2589} //^^^^^^^^^^ Foo
2653"#, 2590"#,
2654 ); 2591 );
2655} 2592}
@@ -3002,7 +2939,7 @@ fn test() {
3002 S.get(1); 2939 S.get(1);
3003 //^^^^^^^^ u128 2940 //^^^^^^^^ u128
3004 S.get(1.); 2941 S.get(1.);
3005 //^^^^^^^^ f32 2942 //^^^^^^^^^ f32
3006} 2943}
3007 "#, 2944 "#,
3008 ); 2945 );
@@ -3477,14 +3414,12 @@ trait Convert {
3477 fn new() -> Self; 3414 fn new() -> Self;
3478} 3415}
3479impl Convert for u32 { 3416impl Convert for u32 {
3480 fn new() -> Self { 3417 fn new() -> Self { 0 }
3481 0
3482 }
3483} 3418}
3484 3419
3485async fn get_accounts() -> Result<u32, ()> { 3420async fn get_accounts() -> Result<u32, ()> {
3486 let ret = Fooey.collect(); 3421 let ret = Fooey.collect();
3487 // ^ u32 3422 // ^^^^^^^^^^^^^^^ u32
3488 Ok(ret) 3423 Ok(ret)
3489} 3424}
3490"#, 3425"#,
@@ -3493,6 +3428,7 @@ async fn get_accounts() -> Result<u32, ()> {
3493 3428
3494#[test] 3429#[test]
3495fn local_impl_1() { 3430fn local_impl_1() {
3431 check!(block_local_impls);
3496 check_types( 3432 check_types(
3497 r#" 3433 r#"
3498trait Trait<T> { 3434trait Trait<T> {
@@ -3502,7 +3438,7 @@ trait Trait<T> {
3502fn test() { 3438fn test() {
3503 struct S; 3439 struct S;
3504 impl Trait<u32> for S { 3440 impl Trait<u32> for S {
3505 fn foo(&self) { 0 } 3441 fn foo(&self) -> u32 { 0 }
3506 } 3442 }
3507 3443
3508 S.foo(); 3444 S.foo();
@@ -3514,6 +3450,7 @@ fn test() {
3514 3450
3515#[test] 3451#[test]
3516fn local_impl_2() { 3452fn local_impl_2() {
3453 check!(block_local_impls);
3517 check_types( 3454 check_types(
3518 r#" 3455 r#"
3519struct S; 3456struct S;
@@ -3523,7 +3460,7 @@ fn test() {
3523 fn foo(&self) -> T; 3460 fn foo(&self) -> T;
3524 } 3461 }
3525 impl Trait<u32> for S { 3462 impl Trait<u32> for S {
3526 fn foo(&self) { 0 } 3463 fn foo(&self) -> u32 { 0 }
3527 } 3464 }
3528 3465
3529 S.foo(); 3466 S.foo();
@@ -3535,6 +3472,7 @@ fn test() {
3535 3472
3536#[test] 3473#[test]
3537fn local_impl_3() { 3474fn local_impl_3() {
3475 check!(block_local_impls);
3538 check_types( 3476 check_types(
3539 r#" 3477 r#"
3540trait Trait<T> { 3478trait Trait<T> {
@@ -3547,7 +3485,7 @@ fn test() {
3547 struct S2; 3485 struct S2;
3548 3486
3549 impl Trait<S1> for S2 { 3487 impl Trait<S1> for S2 {
3550 fn foo(&self) { S1 } 3488 fn foo(&self) -> S1 { S1 }
3551 } 3489 }
3552 3490
3553 S2.foo(); 3491 S2.foo();
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 05a2b1293..c6d6bb74a 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,8 +1,5 @@
1use either::Either; 1use either::Either;
2use hir::{ 2use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
3 AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module,
4 ModuleDef, Semantics,
5};
6use ide_db::{ 3use ide_db::{
7 base_db::SourceDatabase, 4 base_db::SourceDatabase,
8 defs::{Definition, NameClass, NameRefClass}, 5 defs::{Definition, NameClass, NameRefClass},
@@ -33,37 +30,20 @@ use crate::{
33 30
34#[derive(Clone, Debug, PartialEq, Eq)] 31#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct HoverConfig { 32pub struct HoverConfig {
36 pub implementations: bool,
37 pub references: bool,
38 pub run: bool,
39 pub debug: bool,
40 pub goto_type_def: bool,
41 pub links_in_hover: bool, 33 pub links_in_hover: bool,
42 pub markdown: bool, 34 pub documentation: Option<HoverDocFormat>,
43} 35}
44 36
45impl HoverConfig { 37impl HoverConfig {
46 pub const NO_ACTIONS: Self = Self { 38 fn markdown(&self) -> bool {
47 implementations: false, 39 matches!(self.documentation, Some(HoverDocFormat::Markdown))
48 references: false,
49 run: false,
50 debug: false,
51 goto_type_def: false,
52 links_in_hover: true,
53 markdown: true,
54 };
55
56 pub fn any(&self) -> bool {
57 self.implementations || self.references || self.runnable() || self.goto_type_def
58 }
59
60 pub fn none(&self) -> bool {
61 !self.any()
62 } 40 }
41}
63 42
64 pub fn runnable(&self) -> bool { 43#[derive(Clone, Debug, PartialEq, Eq)]
65 self.run || self.debug 44pub enum HoverDocFormat {
66 } 45 Markdown,
46 PlainText,
67} 47}
68 48
69#[derive(Debug, Clone)] 49#[derive(Debug, Clone)]
@@ -96,10 +76,9 @@ pub struct HoverResult {
96pub(crate) fn hover( 76pub(crate) fn hover(
97 db: &RootDatabase, 77 db: &RootDatabase,
98 position: FilePosition, 78 position: FilePosition,
99 links_in_hover: bool, 79 config: &HoverConfig,
100 markdown: bool,
101) -> Option<RangeInfo<HoverResult>> { 80) -> Option<RangeInfo<HoverResult>> {
102 let sema = Semantics::new(db); 81 let sema = hir::Semantics::new(db);
103 let file = sema.parse(position.file_id).syntax().clone(); 82 let file = sema.parse(position.file_id).syntax().clone();
104 let token = pick_best(file.token_at_offset(position.offset))?; 83 let token = pick_best(file.token_at_offset(position.offset))?;
105 let token = sema.descend_into_macros(token); 84 let token = sema.descend_into_macros(token);
@@ -131,7 +110,7 @@ pub(crate) fn hover(
131 let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; 110 let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
132 let (idl_range, link, ns) = 111 let (idl_range, link, ns) =
133 extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| { 112 extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| {
134 let InFile { file_id, value: range } = doc_mapping.map(range)?; 113 let hir::InFile { file_id, value: range } = doc_mapping.map(range)?;
135 if file_id == position.file_id.into() && range.contains(position.offset) { 114 if file_id == position.file_id.into() && range.contains(position.offset) {
136 Some((range, link, ns)) 115 Some((range, link, ns))
137 } else { 116 } else {
@@ -151,13 +130,13 @@ pub(crate) fn hover(
151 130
152 if let Some(definition) = definition { 131 if let Some(definition) = definition {
153 let famous_defs = match &definition { 132 let famous_defs = match &definition {
154 Definition::ModuleDef(ModuleDef::BuiltinType(_)) => { 133 Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => {
155 Some(FamousDefs(&sema, sema.scope(&node).krate())) 134 Some(FamousDefs(&sema, sema.scope(&node).krate()))
156 } 135 }
157 _ => None, 136 _ => None,
158 }; 137 };
159 if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref()) { 138 if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref(), config) {
160 res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown); 139 res.markup = process_markup(sema.db, definition, &markup, config);
161 if let Some(action) = show_implementations_action(db, definition) { 140 if let Some(action) = show_implementations_action(db, definition) {
162 res.actions.push(action); 141 res.actions.push(action);
163 } 142 }
@@ -179,7 +158,7 @@ pub(crate) fn hover(
179 } 158 }
180 } 159 }
181 160
182 if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, &token) { 161 if let res @ Some(_) = hover_for_keyword(&sema, config, &token) {
183 return res; 162 return res;
184 } 163 }
185 164
@@ -198,7 +177,7 @@ pub(crate) fn hover(
198 } 177 }
199 }; 178 };
200 179
201 res.markup = if markdown { 180 res.markup = if config.markdown() {
202 Markup::fenced_block(&ty.display(db)) 181 Markup::fenced_block(&ty.display(db))
203 } else { 182 } else {
204 ty.display(db).to_string().into() 183 ty.display(db).to_string().into()
@@ -261,8 +240,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
261 } 240 }
262 241
263 let adt = match def { 242 let adt = match def {
264 Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), 243 Definition::ModuleDef(hir::ModuleDef::Trait(it)) => {
265 Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), 244 return it.try_to_nav(db).map(to_action)
245 }
246 Definition::ModuleDef(hir::ModuleDef::Adt(it)) => Some(it),
266 Definition::SelfType(it) => it.self_ty(db).as_adt(), 247 Definition::SelfType(it) => it.self_ty(db).as_adt(),
267 _ => None, 248 _ => None,
268 }?; 249 }?;
@@ -271,25 +252,27 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
271 252
272fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { 253fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
273 match def { 254 match def {
274 Definition::ModuleDef(ModuleDef::Function(it)) => it.try_to_nav(db).map(|nav_target| { 255 Definition::ModuleDef(hir::ModuleDef::Function(it)) => {
275 HoverAction::Reference(FilePosition { 256 it.try_to_nav(db).map(|nav_target| {
276 file_id: nav_target.file_id, 257 HoverAction::Reference(FilePosition {
277 offset: nav_target.focus_or_full_range().start(), 258 file_id: nav_target.file_id,
259 offset: nav_target.focus_or_full_range().start(),
260 })
278 }) 261 })
279 }), 262 }
280 _ => None, 263 _ => None,
281 } 264 }
282} 265}
283 266
284fn runnable_action( 267fn runnable_action(
285 sema: &Semantics<RootDatabase>, 268 sema: &hir::Semantics<RootDatabase>,
286 def: Definition, 269 def: Definition,
287 file_id: FileId, 270 file_id: FileId,
288) -> Option<HoverAction> { 271) -> Option<HoverAction> {
289 match def { 272 match def {
290 Definition::ModuleDef(it) => match it { 273 Definition::ModuleDef(it) => match it {
291 ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable), 274 hir::ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable),
292 ModuleDef::Function(func) => { 275 hir::ModuleDef::Function(func) => {
293 let src = func.source(sema.db)?; 276 let src = func.source(sema.db)?;
294 if src.file_id != file_id.into() { 277 if src.file_id != file_id.into() {
295 cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment); 278 cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment);
@@ -306,19 +289,19 @@ fn runnable_action(
306} 289}
307 290
308fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { 291fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
309 let mut targets: Vec<ModuleDef> = Vec::new(); 292 let mut targets: Vec<hir::ModuleDef> = Vec::new();
310 let mut push_new_def = |item: ModuleDef| { 293 let mut push_new_def = |item: hir::ModuleDef| {
311 if !targets.contains(&item) { 294 if !targets.contains(&item) {
312 targets.push(item); 295 targets.push(item);
313 } 296 }
314 }; 297 };
315 298
316 if let Definition::GenericParam(GenericParam::TypeParam(it)) = def { 299 if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def {
317 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); 300 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
318 } else { 301 } else {
319 let ty = match def { 302 let ty = match def {
320 Definition::Local(it) => it.ty(db), 303 Definition::Local(it) => it.ty(db),
321 Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db), 304 Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db),
322 _ => return None, 305 _ => return None,
323 }; 306 };
324 307
@@ -348,42 +331,32 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
348 Some(HoverAction::GoToType(targets)) 331 Some(HoverAction::GoToType(targets))
349} 332}
350 333
351fn hover_markup( 334fn hover_markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> {
352 docs: Option<String>, 335 let mut buf = String::new();
353 desc: Option<String>,
354 mod_path: Option<String>,
355) -> Option<Markup> {
356 match desc {
357 Some(desc) => {
358 let mut buf = String::new();
359
360 if let Some(mod_path) = mod_path {
361 if !mod_path.is_empty() {
362 format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
363 }
364 }
365 format_to!(buf, "```rust\n{}\n```", desc);
366 336
367 if let Some(doc) = docs { 337 if let Some(mod_path) = mod_path {
368 format_to!(buf, "\n___\n\n{}", doc); 338 if !mod_path.is_empty() {
369 } 339 format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
370 Some(buf.into())
371 } 340 }
372 None => docs.map(Markup::from),
373 } 341 }
342 format_to!(buf, "```rust\n{}\n```", desc);
343
344 if let Some(doc) = docs {
345 format_to!(buf, "\n___\n\n{}", doc);
346 }
347 Some(buf.into())
374} 348}
375 349
376fn process_markup( 350fn process_markup(
377 db: &RootDatabase, 351 db: &RootDatabase,
378 def: Definition, 352 def: Definition,
379 markup: &Markup, 353 markup: &Markup,
380 links_in_hover: bool, 354 config: &HoverConfig,
381 markdown: bool,
382) -> Markup { 355) -> Markup {
383 let markup = markup.as_str(); 356 let markup = markup.as_str();
384 let markup = if !markdown { 357 let markup = if !config.markdown() {
385 remove_markdown(markup) 358 remove_markdown(markup)
386 } else if links_in_hover { 359 } else if config.links_in_hover {
387 rewrite_links(db, markup, &def) 360 rewrite_links(db, markup, &def)
388 } else { 361 } else {
389 remove_links(markup) 362 remove_links(markup)
@@ -396,11 +369,11 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
396 Definition::Field(f) => Some(f.parent_def(db).name(db)), 369 Definition::Field(f) => Some(f.parent_def(db).name(db)),
397 Definition::Local(l) => l.parent(db).name(db), 370 Definition::Local(l) => l.parent(db).name(db),
398 Definition::ModuleDef(md) => match md { 371 Definition::ModuleDef(md) => match md {
399 ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { 372 hir::ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
400 AssocItemContainer::Trait(t) => Some(t.name(db)), 373 hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
401 AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), 374 hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
402 }, 375 },
403 ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), 376 hir::ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)),
404 _ => None, 377 _ => None,
405 }, 378 },
406 _ => None, 379 _ => None,
@@ -408,7 +381,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
408 .map(|name| name.to_string()) 381 .map(|name| name.to_string())
409} 382}
410 383
411fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> String { 384fn render_path(db: &RootDatabase, module: hir::Module, item_name: Option<String>) -> String {
412 let crate_name = 385 let crate_name =
413 db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); 386 db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string());
414 let module_path = module 387 let module_path = module
@@ -420,6 +393,9 @@ fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) ->
420} 393}
421 394
422fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { 395fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
396 if let Definition::GenericParam(_) = def {
397 return None;
398 }
423 def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def))) 399 def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def)))
424} 400}
425 401
@@ -427,60 +403,57 @@ fn hover_for_definition(
427 db: &RootDatabase, 403 db: &RootDatabase,
428 def: Definition, 404 def: Definition,
429 famous_defs: Option<&FamousDefs>, 405 famous_defs: Option<&FamousDefs>,
406 config: &HoverConfig,
430) -> Option<Markup> { 407) -> Option<Markup> {
431 let mod_path = definition_mod_path(db, &def); 408 let mod_path = definition_mod_path(db, &def);
432 return match def { 409 let (label, docs) = match def {
433 Definition::Macro(it) => match &it.source(db)?.value { 410 Definition::Macro(it) => match &it.source(db)?.value {
434 Either::Left(mac) => { 411 Either::Left(mac) => {
435 let label = macro_label(mac); 412 let label = macro_label(mac);
436 from_def_source_labeled(db, it, Some(label), mod_path) 413 (label, it.attrs(db).docs())
437 } 414 }
438 Either::Right(_) => { 415 Either::Right(_) => {
439 // FIXME 416 // FIXME
440 None 417 return None;
441 } 418 }
442 }, 419 },
443 Definition::Field(def) => from_hir_fmt(db, def, mod_path), 420 Definition::Field(def) => label_and_docs(db, def),
444 Definition::ModuleDef(it) => match it { 421 Definition::ModuleDef(it) => match it {
445 ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path), 422 hir::ModuleDef::Module(it) => label_and_docs(db, it),
446 ModuleDef::Function(it) => from_hir_fmt(db, it, mod_path), 423 hir::ModuleDef::Function(it) => label_and_docs(db, it),
447 ModuleDef::Adt(it) => from_hir_fmt(db, it, mod_path), 424 hir::ModuleDef::Adt(it) => label_and_docs(db, it),
448 ModuleDef::Variant(it) => from_hir_fmt(db, it, mod_path), 425 hir::ModuleDef::Variant(it) => label_and_docs(db, it),
449 ModuleDef::Const(it) => from_hir_fmt(db, it, mod_path), 426 hir::ModuleDef::Const(it) => label_and_docs(db, it),
450 ModuleDef::Static(it) => from_hir_fmt(db, it, mod_path), 427 hir::ModuleDef::Static(it) => label_and_docs(db, it),
451 ModuleDef::Trait(it) => from_hir_fmt(db, it, mod_path), 428 hir::ModuleDef::Trait(it) => label_and_docs(db, it),
452 ModuleDef::TypeAlias(it) => from_hir_fmt(db, it, mod_path), 429 hir::ModuleDef::TypeAlias(it) => label_and_docs(db, it),
453 ModuleDef::BuiltinType(it) => famous_defs 430 hir::ModuleDef::BuiltinType(it) => {
454 .and_then(|fd| hover_for_builtin(fd, it)) 431 return famous_defs
455 .or_else(|| Some(Markup::fenced_block(&it.name()))), 432 .and_then(|fd| hover_for_builtin(fd, it))
433 .or_else(|| Some(Markup::fenced_block(&it.name())))
434 }
456 }, 435 },
457 Definition::Local(it) => hover_for_local(it, db), 436 Definition::Local(it) => return hover_for_local(it, db),
458 Definition::SelfType(impl_def) => { 437 Definition::SelfType(impl_def) => {
459 impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) 438 impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))?
460 } 439 }
461 Definition::GenericParam(it) => from_hir_fmt(db, it, None), 440 Definition::GenericParam(it) => label_and_docs(db, it),
462 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), 441 Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))),
463 }; 442 };
464 443
465 fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> 444 return hover_markup(
445 docs.filter(|_| config.documentation.is_some()).map(Into::into),
446 label,
447 mod_path,
448 );
449
450 fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
466 where 451 where
467 D: HasAttrs + HirDisplay, 452 D: HasAttrs + HirDisplay,
468 { 453 {
469 let label = def.display(db).to_string(); 454 let label = def.display(db).to_string();
470 from_def_source_labeled(db, def, Some(label), mod_path) 455 let docs = def.attrs(db).docs();
471 } 456 (label, docs)
472
473 fn from_def_source_labeled<D>(
474 db: &RootDatabase,
475 def: D,
476 short_label: Option<String>,
477 mod_path: Option<String>,
478 ) -> Option<Markup>
479 where
480 D: HasAttrs,
481 {
482 let docs = def.attrs(db).docs().map(Into::into);
483 hover_markup(docs, short_label, mod_path)
484 } 457 }
485} 458}
486 459
@@ -504,16 +477,15 @@ fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> {
504 } 477 }
505 Either::Right(_) => format!("{}self: {}", is_mut, ty), 478 Either::Right(_) => format!("{}self: {}", is_mut, ty),
506 }; 479 };
507 hover_markup(None, Some(desc), None) 480 hover_markup(None, desc, None)
508} 481}
509 482
510fn hover_for_keyword( 483fn hover_for_keyword(
511 sema: &Semantics<RootDatabase>, 484 sema: &Semantics<RootDatabase>,
512 links_in_hover: bool, 485 config: &HoverConfig,
513 markdown: bool,
514 token: &SyntaxToken, 486 token: &SyntaxToken,
515) -> Option<RangeInfo<HoverResult>> { 487) -> Option<RangeInfo<HoverResult>> {
516 if !token.kind().is_keyword() { 488 if !token.kind().is_keyword() || !config.documentation.is_some() {
517 return None; 489 return None;
518 } 490 }
519 let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate()); 491 let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate());
@@ -524,9 +496,8 @@ fn hover_for_keyword(
524 let markup = process_markup( 496 let markup = process_markup(
525 sema.db, 497 sema.db,
526 Definition::ModuleDef(doc_owner.into()), 498 Definition::ModuleDef(doc_owner.into()),
527 &hover_markup(Some(docs.into()), Some(token.text().into()), None)?, 499 &hover_markup(Some(docs.into()), token.text().into(), None)?,
528 links_in_hover, 500 config,
529 markdown,
530 ); 501 );
531 Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() })) 502 Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() }))
532} 503}
@@ -536,7 +507,7 @@ fn hover_for_builtin(famous_defs: &FamousDefs, builtin: hir::BuiltinType) -> Opt
536 let primitive_mod = format!("prim_{}", builtin.name()); 507 let primitive_mod = format!("prim_{}", builtin.name());
537 let doc_owner = find_std_module(famous_defs, &primitive_mod)?; 508 let doc_owner = find_std_module(famous_defs, &primitive_mod)?;
538 let docs = doc_owner.attrs(famous_defs.0.db).docs()?; 509 let docs = doc_owner.attrs(famous_defs.0.db).docs()?;
539 hover_markup(Some(docs.into()), Some(builtin.name().to_string()), None) 510 hover_markup(Some(docs.into()), builtin.name().to_string(), None)
540} 511}
541 512
542fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> { 513fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> {
@@ -566,16 +537,34 @@ mod tests {
566 use expect_test::{expect, Expect}; 537 use expect_test::{expect, Expect};
567 use ide_db::base_db::FileLoader; 538 use ide_db::base_db::FileLoader;
568 539
569 use crate::fixture; 540 use crate::{fixture, hover::HoverDocFormat, HoverConfig};
570 541
571 fn check_hover_no_result(ra_fixture: &str) { 542 fn check_hover_no_result(ra_fixture: &str) {
572 let (analysis, position) = fixture::position(ra_fixture); 543 let (analysis, position) = fixture::position(ra_fixture);
573 assert!(analysis.hover(position, true, true).unwrap().is_none()); 544 assert!(analysis
545 .hover(
546 position,
547 &HoverConfig {
548 links_in_hover: true,
549 documentation: Some(HoverDocFormat::Markdown)
550 }
551 )
552 .unwrap()
553 .is_none());
574 } 554 }
575 555
576 fn check(ra_fixture: &str, expect: Expect) { 556 fn check(ra_fixture: &str, expect: Expect) {
577 let (analysis, position) = fixture::position(ra_fixture); 557 let (analysis, position) = fixture::position(ra_fixture);
578 let hover = analysis.hover(position, true, true).unwrap().unwrap(); 558 let hover = analysis
559 .hover(
560 position,
561 &HoverConfig {
562 links_in_hover: true,
563 documentation: Some(HoverDocFormat::Markdown),
564 },
565 )
566 .unwrap()
567 .unwrap();
579 568
580 let content = analysis.db.file_text(position.file_id); 569 let content = analysis.db.file_text(position.file_id);
581 let hovered_element = &content[hover.range]; 570 let hovered_element = &content[hover.range];
@@ -586,7 +575,16 @@ mod tests {
586 575
587 fn check_hover_no_links(ra_fixture: &str, expect: Expect) { 576 fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
588 let (analysis, position) = fixture::position(ra_fixture); 577 let (analysis, position) = fixture::position(ra_fixture);
589 let hover = analysis.hover(position, false, true).unwrap().unwrap(); 578 let hover = analysis
579 .hover(
580 position,
581 &HoverConfig {
582 links_in_hover: false,
583 documentation: Some(HoverDocFormat::Markdown),
584 },
585 )
586 .unwrap()
587 .unwrap();
590 588
591 let content = analysis.db.file_text(position.file_id); 589 let content = analysis.db.file_text(position.file_id);
592 let hovered_element = &content[hover.range]; 590 let hovered_element = &content[hover.range];
@@ -597,7 +595,16 @@ mod tests {
597 595
598 fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { 596 fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
599 let (analysis, position) = fixture::position(ra_fixture); 597 let (analysis, position) = fixture::position(ra_fixture);
600 let hover = analysis.hover(position, true, false).unwrap().unwrap(); 598 let hover = analysis
599 .hover(
600 position,
601 &HoverConfig {
602 links_in_hover: true,
603 documentation: Some(HoverDocFormat::PlainText),
604 },
605 )
606 .unwrap()
607 .unwrap();
601 608
602 let content = analysis.db.file_text(position.file_id); 609 let content = analysis.db.file_text(position.file_id);
603 let hovered_element = &content[hover.range]; 610 let hovered_element = &content[hover.range];
@@ -608,7 +615,16 @@ mod tests {
608 615
609 fn check_actions(ra_fixture: &str, expect: Expect) { 616 fn check_actions(ra_fixture: &str, expect: Expect) {
610 let (analysis, position) = fixture::position(ra_fixture); 617 let (analysis, position) = fixture::position(ra_fixture);
611 let hover = analysis.hover(position, true, true).unwrap().unwrap(); 618 let hover = analysis
619 .hover(
620 position,
621 &HoverConfig {
622 links_in_hover: true,
623 documentation: Some(HoverDocFormat::Markdown),
624 },
625 )
626 .unwrap()
627 .unwrap();
612 expect.assert_debug_eq(&hover.info.actions) 628 expect.assert_debug_eq(&hover.info.actions)
613 } 629 }
614 630
@@ -2258,7 +2274,7 @@ pub fn fo$0o() {}
2258 case 13. collapsed link: foo 2274 case 13. collapsed link: foo
2259 case 14. shortcut link: foo 2275 case 14. shortcut link: foo
2260 case 15. inline without URL: foo 2276 case 15. inline without URL: foo
2261 case 16. just escaped text: \[foo] 2277 case 16. just escaped text: \[foo\]
2262 case 17. inline link: Foo 2278 case 17. inline link: Foo
2263 2279
2264 [^example]: https://www.example.com/ 2280 [^example]: https://www.example.com/
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 4bd073cc3..b978e36af 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -75,7 +75,7 @@ pub use crate::{
75 expand_macro::ExpandedMacro, 75 expand_macro::ExpandedMacro,
76 file_structure::{StructureNode, StructureNodeKind}, 76 file_structure::{StructureNode, StructureNodeKind},
77 folding_ranges::{Fold, FoldKind}, 77 folding_ranges::{Fold, FoldKind},
78 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, 78 hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
79 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 79 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
80 markup::Markup, 80 markup::Markup,
81 move_item::Direction, 81 move_item::Direction,
@@ -217,6 +217,7 @@ impl Analysis {
217 file_id, 217 file_id,
218 Edition::Edition2018, 218 Edition::Edition2018,
219 None, 219 None,
220 cfg_options.clone(),
220 cfg_options, 221 cfg_options,
221 Env::default(), 222 Env::default(),
222 Default::default(), 223 Default::default(),
@@ -407,10 +408,9 @@ impl Analysis {
407 pub fn hover( 408 pub fn hover(
408 &self, 409 &self,
409 position: FilePosition, 410 position: FilePosition,
410 links_in_hover: bool, 411 config: &HoverConfig,
411 markdown: bool,
412 ) -> Cancellable<Option<RangeInfo<HoverResult>>> { 412 ) -> Cancellable<Option<RangeInfo<HoverResult>>> {
413 self.with_db(|db| hover::hover(db, position, links_in_hover, markdown)) 413 self.with_db(|db| hover::hover(db, position, config))
414 } 414 }
415 415
416 /// Return URL(s) for the documentation of the symbol under the cursor. 416 /// Return URL(s) for the documentation of the symbol under the cursor.
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs
index 8096dfa0e..96bd07708 100644
--- a/crates/ide/src/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -10,7 +10,7 @@ use ide_db::{
10 rename::{bail, format_err, source_edit_from_references, IdentifierKind}, 10 rename::{bail, format_err, source_edit_from_references, IdentifierKind},
11 RootDatabase, 11 RootDatabase,
12}; 12};
13use stdx::never; 13use stdx::{always, never};
14use syntax::{ast, AstNode, SyntaxNode}; 14use syntax::{ast, AstNode, SyntaxNode};
15 15
16use text_edit::TextEdit; 16use text_edit::TextEdit;
@@ -31,10 +31,13 @@ pub(crate) fn prepare_rename(
31 let source_file = sema.parse(position.file_id); 31 let source_file = sema.parse(position.file_id);
32 let syntax = source_file.syntax(); 32 let syntax = source_file.syntax();
33 33
34 let def = find_definition(&sema, syntax, position)?; 34 let (name_like, def) = find_definition(&sema, syntax, position)?;
35 let frange = def 35 if def.range_for_rename(&sema).is_none() {
36 .range_for_rename(&sema) 36 bail!("No references found at position")
37 .ok_or_else(|| format_err!("No references found at position"))?; 37 }
38
39 let frange = sema.original_range(name_like.syntax());
40 always!(frange.range.contains_inclusive(position.offset) && frange.file_id == position.file_id);
38 Ok(RangeInfo::new(frange.range, ())) 41 Ok(RangeInfo::new(frange.range, ()))
39} 42}
40 43
@@ -55,31 +58,23 @@ pub(crate) fn rename(
55 new_name: &str, 58 new_name: &str,
56) -> RenameResult<SourceChange> { 59) -> RenameResult<SourceChange> {
57 let sema = Semantics::new(db); 60 let sema = Semantics::new(db);
58 rename_with_semantics(&sema, position, new_name)
59}
60
61pub(crate) fn rename_with_semantics(
62 sema: &Semantics<RootDatabase>,
63 position: FilePosition,
64 new_name: &str,
65) -> RenameResult<SourceChange> {
66 let source_file = sema.parse(position.file_id); 61 let source_file = sema.parse(position.file_id);
67 let syntax = source_file.syntax(); 62 let syntax = source_file.syntax();
68 63
69 let def = find_definition(sema, syntax, position)?; 64 let (_name_like, def) = find_definition(&sema, syntax, position)?;
70 65
71 if let Definition::Local(local) = def { 66 if let Definition::Local(local) = def {
72 if let Some(self_param) = local.as_self_param(sema.db) { 67 if let Some(self_param) = local.as_self_param(sema.db) {
73 cov_mark::hit!(rename_self_to_param); 68 cov_mark::hit!(rename_self_to_param);
74 return rename_self_to_param(sema, local, self_param, new_name); 69 return rename_self_to_param(&sema, local, self_param, new_name);
75 } 70 }
76 if new_name == "self" { 71 if new_name == "self" {
77 cov_mark::hit!(rename_to_self); 72 cov_mark::hit!(rename_to_self);
78 return rename_to_self(sema, local); 73 return rename_to_self(&sema, local);
79 } 74 }
80 } 75 }
81 76
82 def.rename(sema, new_name) 77 def.rename(&sema, new_name)
83} 78}
84 79
85/// Called by the client when it is about to rename a file. 80/// Called by the client when it is about to rename a file.
@@ -100,11 +95,12 @@ fn find_definition(
100 sema: &Semantics<RootDatabase>, 95 sema: &Semantics<RootDatabase>,
101 syntax: &SyntaxNode, 96 syntax: &SyntaxNode,
102 position: FilePosition, 97 position: FilePosition,
103) -> RenameResult<Definition> { 98) -> RenameResult<(ast::NameLike, Definition)> {
104 match sema 99 let name_like = sema
105 .find_node_at_offset_with_descend(syntax, position.offset) 100 .find_node_at_offset_with_descend::<ast::NameLike>(syntax, position.offset)
106 .ok_or_else(|| format_err!("No references found at position"))? 101 .ok_or_else(|| format_err!("No references found at position"))?;
107 { 102
103 let def = match &name_like {
108 // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet 104 // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet
109 ast::NameLike::Name(name) 105 ast::NameLike::Name(name)
110 if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) => 106 if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) =>
@@ -134,7 +130,9 @@ fn find_definition(
134 .map(|it| it.referenced_or_defined(sema.db)) 130 .map(|it| it.referenced_or_defined(sema.db))
135 }), 131 }),
136 } 132 }
137 .ok_or_else(|| format_err!("No references found at position")) 133 .ok_or_else(|| format_err!("No references found at position"))?;
134
135 Ok((name_like, def))
138} 136}
139 137
140fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { 138fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> {
@@ -328,7 +326,7 @@ mod tests {
328 fn test_prepare_rename_namelikes() { 326 fn test_prepare_rename_namelikes() {
329 check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]); 327 check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]);
330 check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"8..17: 'lifetime"#]]); 328 check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"8..17: 'lifetime"#]]);
331 check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"3..7: name"#]]); 329 check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"23..27: name"#]]);
332 } 330 }
333 331
334 #[test] 332 #[test]
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 4ad49eca0..37ae92350 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -23,7 +23,7 @@ use syntax::{
23 algo::find_node_at_offset, 23 algo::find_node_at_offset,
24 ast::{self, edit::IndentLevel, AstToken}, 24 ast::{self, edit::IndentLevel, AstToken},
25 AstNode, Parse, SourceFile, 25 AstNode, Parse, SourceFile,
26 SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, 26 SyntaxKind::{self, FIELD_EXPR, METHOD_CALL_EXPR},
27 TextRange, TextSize, 27 TextRange, TextSize,
28}; 28};
29 29
@@ -95,9 +95,16 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
95 } 95 }
96 96
97 let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; 97 let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?;
98 if brace_token.kind() != SyntaxKind::L_CURLY {
99 return None;
100 }
98 101
99 // Remove the `{` to get a better parse tree, and reparse 102 // Remove the `{` to get a better parse tree, and reparse.
100 let file = file.reparse(&Indel::delete(brace_token.text_range())); 103 let range = brace_token.text_range();
104 if !stdx::always!(range.len() == TextSize::of('{')) {
105 return None;
106 }
107 let file = file.reparse(&Indel::delete(range));
101 108
102 if let Some(edit) = brace_expr(&file.tree(), offset) { 109 if let Some(edit) = brace_expr(&file.tree(), offset) {
103 return Some(edit); 110 return Some(edit);
@@ -550,6 +557,29 @@ fn f() {
550 } 557 }
551 558
552 #[test] 559 #[test]
560 fn noop_in_string_literal() {
561 // Regression test for #9351
562 type_char_noop(
563 '{',
564 r##"
565fn check_with(ra_fixture: &str, expect: Expect) {
566 let base = r#"
567enum E { T(), R$0, C }
568use self::E::X;
569const Z: E = E::C;
570mod m {}
571asdasdasdasdasdasda
572sdasdasdasdasdasda
573sdasdasdasdasd
574"#;
575 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
576 expect.assert_eq(&actual)
577}
578 "##,
579 );
580 }
581
582 #[test]
553 fn adds_closing_brace_for_use_tree() { 583 fn adds_closing_brace_for_use_tree() {
554 type_char( 584 type_char(
555 '{', 585 '{',
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index ac7f0959b..870d4f665 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -109,10 +109,15 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
109 109
110 let new_indent = IndentLevel::from_node(&insert_after); 110 let new_indent = IndentLevel::from_node(&insert_after);
111 let old_indent = fun.body.indent_level(); 111 let old_indent = fun.body.indent_level();
112 let body_contains_await = body_contains_await(&fun.body);
112 113
113 builder.replace(target_range, format_replacement(ctx, &fun, old_indent)); 114 builder.replace(
115 target_range,
116 format_replacement(ctx, &fun, old_indent, body_contains_await),
117 );
114 118
115 let fn_def = format_function(ctx, module, &fun, old_indent, new_indent); 119 let fn_def =
120 format_function(ctx, module, &fun, old_indent, new_indent, body_contains_await);
116 let insert_offset = insert_after.text_range().end(); 121 let insert_offset = insert_after.text_range().end();
117 match ctx.config.snippet_cap { 122 match ctx.config.snippet_cap {
118 Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def), 123 Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def),
@@ -954,7 +959,12 @@ fn scope_for_fn_insertion_node(node: &SyntaxNode, anchor: Anchor) -> Option<Synt
954 last_ancestor 959 last_ancestor
955} 960}
956 961
957fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel) -> String { 962fn format_replacement(
963 ctx: &AssistContext,
964 fun: &Function,
965 indent: IndentLevel,
966 body_contains_await: bool,
967) -> String {
958 let ret_ty = fun.return_type(ctx); 968 let ret_ty = fun.return_type(ctx);
959 969
960 let args = fun.params.iter().map(|param| param.to_arg(ctx)); 970 let args = fun.params.iter().map(|param| param.to_arg(ctx));
@@ -994,6 +1004,9 @@ fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel)
994 } 1004 }
995 } 1005 }
996 format_to!(buf, "{}", expr); 1006 format_to!(buf, "{}", expr);
1007 if body_contains_await {
1008 buf.push_str(".await");
1009 }
997 if fun.ret_ty.is_unit() 1010 if fun.ret_ty.is_unit()
998 && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like()) 1011 && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like())
999 { 1012 {
@@ -1122,12 +1135,13 @@ fn format_function(
1122 fun: &Function, 1135 fun: &Function,
1123 old_indent: IndentLevel, 1136 old_indent: IndentLevel,
1124 new_indent: IndentLevel, 1137 new_indent: IndentLevel,
1138 body_contains_await: bool,
1125) -> String { 1139) -> String {
1126 let mut fn_def = String::new(); 1140 let mut fn_def = String::new();
1127 let params = make_param_list(ctx, module, fun); 1141 let params = make_param_list(ctx, module, fun);
1128 let ret_ty = make_ret_ty(ctx, module, fun); 1142 let ret_ty = make_ret_ty(ctx, module, fun);
1129 let body = make_body(ctx, old_indent, new_indent, fun); 1143 let body = make_body(ctx, old_indent, new_indent, fun);
1130 let async_kw = if body_contains_await(&fun.body) { "async " } else { "" }; 1144 let async_kw = if body_contains_await { "async " } else { "" };
1131 match ctx.config.snippet_cap { 1145 match ctx.config.snippet_cap {
1132 Some(_) => format_to!(fn_def, "\n\n{}{}fn $0{}{}", new_indent, async_kw, fun.name, params), 1146 Some(_) => format_to!(fn_def, "\n\n{}{}fn $0{}{}", new_indent, async_kw, fun.name, params),
1133 None => format_to!(fn_def, "\n\n{}{}fn {}{}", new_indent, async_kw, fun.name, params), 1147 None => format_to!(fn_def, "\n\n{}{}fn {}{}", new_indent, async_kw, fun.name, params),
@@ -3681,7 +3695,7 @@ async fn some_function() {
3681"#, 3695"#,
3682 r#" 3696 r#"
3683fn main() { 3697fn main() {
3684 fun_name(); 3698 fun_name().await;
3685} 3699}
3686 3700
3687async fn $0fun_name() { 3701async fn $0fun_name() {
@@ -3710,7 +3724,7 @@ async fn some_function() {
3710"#, 3724"#,
3711 r#" 3725 r#"
3712fn main() { 3726fn main() {
3713 fun_name(); 3727 fun_name().await;
3714} 3728}
3715 3729
3716async fn $0fun_name() { 3730async fn $0fun_name() {
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 78fc30e16..cc4f4b2af 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -15,6 +15,7 @@ use crate::{
15 Completions, 15 Completions,
16}; 16};
17 17
18mod cfg;
18mod derive; 19mod derive;
19mod lint; 20mod lint;
20mod repr; 21mod repr;
@@ -30,6 +31,9 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
30 lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); 31 lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS);
31 lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); 32 lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
32 } 33 }
34 "cfg" => {
35 cfg::complete_cfg(acc, ctx);
36 }
33 _ => (), 37 _ => (),
34 }, 38 },
35 (None, Some(_)) => (), 39 (None, Some(_)) => (),
@@ -852,4 +856,15 @@ mod tests {
852 "#]], 856 "#]],
853 ); 857 );
854 } 858 }
859
860 #[test]
861 fn test_cfg() {
862 check(
863 r#"#[cfg(target_endian = $0"#,
864 expect![[r#"
865 at little
866 at big
867"#]],
868 );
869 }
855} 870}
diff --git a/crates/ide_completion/src/completions/attribute/cfg.rs b/crates/ide_completion/src/completions/attribute/cfg.rs
new file mode 100644
index 000000000..847e6529a
--- /dev/null
+++ b/crates/ide_completion/src/completions/attribute/cfg.rs
@@ -0,0 +1,112 @@
1//! Completion for cfg
2
3use std::iter;
4
5use syntax::SyntaxKind;
6
7use crate::{
8 completions::Completions, context::CompletionContext, item::CompletionKind, CompletionItem,
9 CompletionItemKind,
10};
11
12pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
13 let add_completion = |item: &&str| {
14 let mut completion =
15 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), *item);
16 completion.insert_text(format!(r#""{}""#, item));
17 completion.kind(CompletionItemKind::Attribute);
18 acc.add(completion.build());
19 };
20
21 let previous = iter::successors(ctx.original_token.prev_token(), |t| {
22 (matches!(t.kind(), SyntaxKind::EQ) || t.kind().is_trivia())
23 .then(|| t.prev_token())
24 .flatten()
25 })
26 .find(|t| matches!(t.kind(), SyntaxKind::IDENT));
27
28 match previous.as_ref().map(|p| p.text()) {
29 Some("target_arch") => KNOWN_ARCH.iter().for_each(add_completion),
30 Some("target_env") => KNOWN_ENV.iter().for_each(add_completion),
31 Some("target_os") => KNOWN_OS.iter().for_each(add_completion),
32 Some("target_vendor") => KNOWN_VENDOR.iter().for_each(add_completion),
33 Some("target_endian") => ["little", "big"].iter().for_each(add_completion),
34 Some(name) => {
35 ctx.krate.map(|krate| {
36 krate.potential_cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| {
37 let mut item = CompletionItem::new(
38 CompletionKind::Attribute,
39 ctx.source_range(),
40 s.as_str(),
41 );
42 item.insert_text(format!(r#""{}""#, s));
43
44 acc.add(item.build());
45 })
46 });
47 }
48 None => {
49 ctx.krate.map(|krate| {
50 krate.potential_cfg(ctx.db).get_cfg_keys().iter().for_each(|s| {
51 let item = CompletionItem::new(
52 CompletionKind::Attribute,
53 ctx.source_range(),
54 s.as_str(),
55 );
56 acc.add(item.build());
57 })
58 });
59 }
60 };
61}
62
63const KNOWN_ARCH: [&'static str; 19] = [
64 "aarch64",
65 "arm",
66 "avr",
67 "hexagon",
68 "mips",
69 "mips64",
70 "msp430",
71 "nvptx64",
72 "powerpc",
73 "powerpc64",
74 "riscv32",
75 "riscv64",
76 "s390x",
77 "sparc",
78 "sparc64",
79 "wasm32",
80 "wasm64",
81 "x86",
82 "x86_64",
83];
84
85const KNOWN_ENV: [&'static str; 7] =
86 ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"];
87
88const KNOWN_OS: [&'static str; 20] = [
89 "cuda",
90 "dragonfly",
91 "emscripten",
92 "freebsd",
93 "fuchsia",
94 "haiku",
95 "hermit",
96 "illumos",
97 "l4re",
98 "linux",
99 "netbsd",
100 "none",
101 "openbsd",
102 "psp",
103 "redox",
104 "solaris",
105 "uefi",
106 "unknown",
107 "vxworks",
108 "windows",
109];
110
111const KNOWN_VENDOR: [&'static str; 8] =
112 ["apple", "fortanix", "nvidia", "pc", "sony", "unknown", "wrs", "uwp"];
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 07541c79c..407f796ef 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -92,7 +92,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
92 } 92 }
93 93
94 if !ctx.has_visibility_prev_sibling() 94 if !ctx.has_visibility_prev_sibling()
95 && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field()) 95 && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field())
96 { 96 {
97 add_keyword("pub(crate)", "pub(crate) "); 97 add_keyword("pub(crate)", "pub(crate) ");
98 add_keyword("pub", "pub "); 98 add_keyword("pub", "pub ");
@@ -122,6 +122,10 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
122 add_keyword("union", "union $1 {\n $0\n}"); 122 add_keyword("union", "union $1 {\n $0\n}");
123 } 123 }
124 124
125 if ctx.expects_type() {
126 return;
127 }
128
125 if ctx.expects_expression() { 129 if ctx.expects_expression() {
126 if !has_block_expr_parent { 130 if !has_block_expr_parent {
127 add_keyword("unsafe", "unsafe {\n $0\n}"); 131 add_keyword("unsafe", "unsafe {\n $0\n}");
@@ -373,28 +377,6 @@ fn quux() -> i32 {
373 } 377 }
374 378
375 #[test] 379 #[test]
376 fn test_mut_in_ref_and_in_fn_parameters_list() {
377 check(
378 r"fn my_fn(&$0) {}",
379 expect![[r#"
380 kw mut
381 "#]],
382 );
383 check(
384 r"fn my_fn($0) {}",
385 expect![[r#"
386 kw mut
387 "#]],
388 );
389 check(
390 r"fn my_fn() { let &$0 }",
391 expect![[r#"
392 kw mut
393 "#]],
394 );
395 }
396
397 #[test]
398 fn no_keyword_completion_in_comments() { 380 fn no_keyword_completion_in_comments() {
399 cov_mark::check!(no_keyword_completion_in_comments); 381 cov_mark::check!(no_keyword_completion_in_comments);
400 check( 382 check(
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index efe3c957a..bd13a62d7 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -55,398 +55,3 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
55 } 55 }
56 }); 56 });
57} 57}
58
59#[cfg(test)]
60mod tests {
61 use expect_test::{expect, Expect};
62
63 use crate::{
64 tests::{check_edit, filtered_completion_list},
65 CompletionKind,
66 };
67
68 fn check(ra_fixture: &str, expect: Expect) {
69 let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
70 expect.assert_eq(&actual)
71 }
72
73 fn check_snippet(ra_fixture: &str, expect: Expect) {
74 let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet);
75 expect.assert_eq(&actual)
76 }
77
78 #[test]
79 fn completes_enum_variants_and_modules() {
80 check(
81 r#"
82enum E { X }
83use self::E::X;
84const Z: E = E::X;
85mod m {}
86
87static FOO: E = E::X;
88struct Bar { f: u32 }
89
90fn foo() {
91 match E::X { a$0 }
92}
93"#,
94 expect![[r#"
95 en E
96 ct Z
97 st Bar
98 ev X
99 md m
100 "#]],
101 );
102 }
103
104 #[test]
105 fn does_not_complete_non_fn_macros() {
106 check(
107 r#"
108macro_rules! m { ($e:expr) => { $e } }
109enum E { X }
110
111#[rustc_builtin_macro]
112macro Clone {}
113
114fn foo() {
115 match E::X { $0 }
116}
117"#,
118 expect![[r#"
119 ev E::X ()
120 en E
121 ma m!(…) macro_rules! m
122 "#]],
123 );
124 }
125
126 #[test]
127 fn completes_in_simple_macro_call() {
128 check(
129 r#"
130macro_rules! m { ($e:expr) => { $e } }
131enum E { X }
132
133fn foo() {
134 m!(match E::X { a$0 })
135}
136"#,
137 expect![[r#"
138 ev E::X ()
139 en E
140 ma m!(…) macro_rules! m
141 "#]],
142 );
143 }
144
145 #[test]
146 fn completes_in_irrefutable_let() {
147 check(
148 r#"
149enum E { X }
150use self::E::X;
151const Z: E = E::X;
152mod m {}
153
154static FOO: E = E::X;
155struct Bar { f: u32 }
156
157fn foo() {
158 let a$0
159}
160"#,
161 expect![[r#"
162 st Bar
163 "#]],
164 );
165 }
166
167 #[test]
168 fn completes_in_param() {
169 check(
170 r#"
171enum E { X }
172
173static FOO: E = E::X;
174struct Bar { f: u32 }
175
176fn foo(a$0) {
177}
178"#,
179 expect![[r#"
180 st Bar
181 "#]],
182 );
183 }
184
185 #[test]
186 fn completes_pat_in_let() {
187 check_snippet(
188 r#"
189struct Bar { f: u32 }
190
191fn foo() {
192 let a$0
193}
194"#,
195 expect![[r#"
196 bn Bar Bar { f$1 }$0
197 "#]],
198 );
199 }
200
201 #[test]
202 fn completes_param_pattern() {
203 check_snippet(
204 r#"
205struct Foo { bar: String, baz: String }
206struct Bar(String, String);
207struct Baz;
208fn outer(a$0) {}
209"#,
210 expect![[r#"
211 bn Foo Foo { bar$1, baz$2 }: Foo$0
212 bn Bar Bar($1, $2): Bar$0
213 "#]],
214 )
215 }
216
217 #[test]
218 fn completes_let_pattern() {
219 check_snippet(
220 r#"
221struct Foo { bar: String, baz: String }
222struct Bar(String, String);
223struct Baz;
224fn outer() {
225 let a$0
226}
227"#,
228 expect![[r#"
229 bn Foo Foo { bar$1, baz$2 }$0
230 bn Bar Bar($1, $2)$0
231 "#]],
232 )
233 }
234
235 #[test]
236 fn completes_refutable_pattern() {
237 check_snippet(
238 r#"
239struct Foo { bar: i32, baz: i32 }
240struct Bar(String, String);
241struct Baz;
242fn outer() {
243 match () {
244 a$0
245 }
246}
247"#,
248 expect![[r#"
249 bn Foo Foo { bar$1, baz$2 }$0
250 bn Bar Bar($1, $2)$0
251 "#]],
252 )
253 }
254
255 #[test]
256 fn omits_private_fields_pat() {
257 check_snippet(
258 r#"
259mod foo {
260 pub struct Foo { pub bar: i32, baz: i32 }
261 pub struct Bar(pub String, String);
262 pub struct Invisible(String, String);
263}
264use foo::*;
265
266fn outer() {
267 match () {
268 a$0
269 }
270}
271"#,
272 expect![[r#"
273 bn Foo Foo { bar$1, .. }$0
274 bn Bar Bar($1, ..)$0
275 "#]],
276 )
277 }
278
279 #[test]
280 fn only_shows_ident_completion() {
281 check_edit(
282 "Foo",
283 r#"
284struct Foo(i32);
285fn main() {
286 match Foo(92) {
287 a$0(92) => (),
288 }
289}
290"#,
291 r#"
292struct Foo(i32);
293fn main() {
294 match Foo(92) {
295 Foo(92) => (),
296 }
297}
298"#,
299 );
300 }
301
302 #[test]
303 fn completes_self_pats() {
304 check_snippet(
305 r#"
306struct Foo(i32);
307impl Foo {
308 fn foo() {
309 match () {
310 a$0
311 }
312 }
313}
314 "#,
315 expect![[r#"
316 bn Self Self($1)$0
317 bn Foo Foo($1)$0
318 "#]],
319 )
320 }
321
322 #[test]
323 fn completes_qualified_variant() {
324 check_snippet(
325 r#"
326enum Foo {
327 Bar { baz: i32 }
328}
329impl Foo {
330 fn foo() {
331 match {Foo::Bar { baz: 0 }} {
332 B$0
333 }
334 }
335}
336 "#,
337 expect![[r#"
338 bn Self::Bar Self::Bar { baz$1 }$0
339 bn Foo::Bar Foo::Bar { baz$1 }$0
340 "#]],
341 )
342 }
343
344 #[test]
345 fn completes_enum_variant_matcharm() {
346 check(
347 r#"
348enum Foo { Bar, Baz, Quux }
349
350fn main() {
351 let foo = Foo::Quux;
352 match foo { Qu$0 }
353}
354"#,
355 expect![[r#"
356 ev Foo::Bar ()
357 ev Foo::Baz ()
358 ev Foo::Quux ()
359 en Foo
360 "#]],
361 )
362 }
363
364 #[test]
365 fn completes_enum_variant_matcharm_ref() {
366 check(
367 r#"
368enum Foo { Bar, Baz, Quux }
369
370fn main() {
371 let foo = Foo::Quux;
372 match &foo { Qu$0 }
373}
374"#,
375 expect![[r#"
376 ev Foo::Bar ()
377 ev Foo::Baz ()
378 ev Foo::Quux ()
379 en Foo
380 "#]],
381 )
382 }
383
384 #[test]
385 fn completes_enum_variant_iflet() {
386 check(
387 r#"
388enum Foo { Bar, Baz, Quux }
389
390fn main() {
391 let foo = Foo::Quux;
392 if let Qu$0 = foo { }
393}
394"#,
395 expect![[r#"
396 ev Foo::Bar ()
397 ev Foo::Baz ()
398 ev Foo::Quux ()
399 en Foo
400 "#]],
401 )
402 }
403
404 #[test]
405 fn completes_enum_variant_impl() {
406 check(
407 r#"
408enum Foo { Bar, Baz, Quux }
409impl Foo {
410 fn foo() { match Foo::Bar { Q$0 } }
411}
412"#,
413 expect![[r#"
414 ev Self::Bar ()
415 ev Self::Baz ()
416 ev Self::Quux ()
417 ev Foo::Bar ()
418 ev Foo::Baz ()
419 ev Foo::Quux ()
420 sp Self
421 en Foo
422 "#]],
423 )
424 }
425
426 #[test]
427 fn completes_in_record_field_pat() {
428 check_snippet(
429 r#"
430struct Foo { bar: Bar }
431struct Bar(u32);
432fn outer(Foo { bar: $0 }: Foo) {}
433"#,
434 expect![[r#"
435 bn Foo Foo { bar$1 }$0
436 bn Bar Bar($1)$0
437 "#]],
438 )
439 }
440
441 #[test]
442 fn skips_in_record_field_pat_name() {
443 check_snippet(
444 r#"
445struct Foo { bar: Bar }
446struct Bar(u32);
447fn outer(Foo { bar$0 }: Foo) {}
448"#,
449 expect![[r#""#]],
450 )
451 }
452}
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index f5dbd203b..1b8997ecf 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -219,36 +219,6 @@ mod tests {
219 } 219 }
220 220
221 #[test] 221 #[test]
222 fn dont_complete_values_in_type_pos() {
223 check(
224 r#"
225const FOO: () = ();
226static BAR: () = ();
227struct Baz;
228fn foo() {
229 let _: self::$0;
230}
231"#,
232 expect![[r#"
233 st Baz
234 "#]],
235 );
236 }
237
238 #[test]
239 fn dont_complete_enum_variants_in_type_pos() {
240 check(
241 r#"
242enum Foo { Bar }
243fn foo() {
244 let _: Foo::$0;
245}
246"#,
247 expect![[r#""#]],
248 );
249 }
250
251 #[test]
252 fn dont_complete_primitive_in_use() { 222 fn dont_complete_primitive_in_use() {
253 check_builtin(r#"use self::$0;"#, expect![[""]]); 223 check_builtin(r#"use self::$0;"#, expect![[""]]);
254 } 224 }
@@ -259,32 +229,6 @@ fn foo() {
259 } 229 }
260 230
261 #[test] 231 #[test]
262 fn completes_primitives() {
263 check_builtin(
264 r#"fn main() { let _: $0 = 92; }"#,
265 expect![[r#"
266 bt u32
267 bt bool
268 bt u8
269 bt isize
270 bt u16
271 bt u64
272 bt u128
273 bt f32
274 bt i128
275 bt i16
276 bt str
277 bt i64
278 bt char
279 bt f64
280 bt i32
281 bt i8
282 bt usize
283 "#]],
284 );
285 }
286
287 #[test]
288 fn completes_enum_variant() { 232 fn completes_enum_variant() {
289 check( 233 check(
290 r#" 234 r#"
@@ -749,24 +693,4 @@ fn main() {
749 "#]], 693 "#]],
750 ); 694 );
751 } 695 }
752
753 #[test]
754 fn completes_types_and_const_in_arg_list() {
755 check(
756 r#"
757mod foo {
758 pub const CONST: () = ();
759 pub type Type = ();
760}
761
762struct Foo<T>(t);
763
764fn foo(_: Foo<foo::$0>) {}
765"#,
766 expect![[r#"
767 ta Type
768 ct CONST
769 "#]],
770 );
771 }
772} 696}
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 81c4fb305..380c1e079 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -113,78 +113,6 @@ mod tests {
113 } 113 }
114 114
115 #[test] 115 #[test]
116 fn dont_complete_values_in_type_pos() {
117 check(
118 r#"
119const FOO: () = ();
120static BAR: () = ();
121enum Foo {
122 Bar
123}
124struct Baz;
125fn foo() {
126 let local = ();
127 let _: $0;
128}
129"#,
130 expect![[r#"
131 en Foo
132 st Baz
133 "#]],
134 );
135 }
136
137 #[test]
138 fn bind_pat_and_path_ignore_at() {
139 check(
140 r#"
141enum Enum { A, B }
142fn quux(x: Option<Enum>) {
143 match x {
144 None => (),
145 Some(en$0 @ Enum::A) => (),
146 }
147}
148"#,
149 expect![[r#""#]],
150 );
151 }
152
153 #[test]
154 fn bind_pat_and_path_ignore_ref() {
155 check(
156 r#"
157enum Enum { A, B }
158fn quux(x: Option<Enum>) {
159 match x {
160 None => (),
161 Some(ref en$0) => (),
162 }
163}
164"#,
165 expect![[r#""#]],
166 );
167 }
168
169 #[test]
170 fn bind_pat_and_path() {
171 check(
172 r#"
173enum Enum { A, B }
174fn quux(x: Option<Enum>) {
175 match x {
176 None => (),
177 Some(En$0) => (),
178 }
179}
180"#,
181 expect![[r#"
182 en Enum
183 "#]],
184 );
185 }
186
187 #[test]
188 fn completes_bindings_from_let() { 116 fn completes_bindings_from_let() {
189 check( 117 check(
190 r#" 118 r#"
@@ -289,29 +217,6 @@ fn main() {
289 } 217 }
290 218
291 #[test] 219 #[test]
292 fn completes_generic_params_in_struct() {
293 check(
294 r#"struct S<T> { x: $0}"#,
295 expect![[r#"
296 sp Self
297 tp T
298 st S<…>
299 "#]],
300 );
301 }
302
303 #[test]
304 fn completes_self_in_enum() {
305 check(
306 r#"enum X { Y($0) }"#,
307 expect![[r#"
308 sp Self
309 en X
310 "#]],
311 );
312 }
313
314 #[test]
315 fn completes_module_items() { 220 fn completes_module_items() {
316 check( 221 check(
317 r#" 222 r#"
@@ -365,19 +270,6 @@ mod m {
365 } 270 }
366 271
367 #[test] 272 #[test]
368 fn completes_return_type() {
369 check(
370 r#"
371struct Foo;
372fn x() -> $0
373"#,
374 expect![[r#"
375 st Foo
376 "#]],
377 );
378 }
379
380 #[test]
381 fn dont_show_both_completions_for_shadowing() { 273 fn dont_show_both_completions_for_shadowing() {
382 check( 274 check(
383 r#" 275 r#"
@@ -559,19 +451,6 @@ fn foo() { $0 }
559 } 451 }
560 452
561 #[test] 453 #[test]
562 fn completes_macros_as_type() {
563 check(
564 r#"
565macro_rules! foo { () => {} }
566fn main() { let x: $0 }
567"#,
568 expect![[r#"
569 ma foo!(…) macro_rules! foo
570 "#]],
571 );
572 }
573
574 #[test]
575 fn completes_macros_as_stmt() { 454 fn completes_macros_as_stmt() {
576 check( 455 check(
577 r#" 456 r#"
@@ -716,30 +595,4 @@ fn f() {}
716 expect![[""]], 595 expect![[""]],
717 ) 596 )
718 } 597 }
719
720 #[test]
721 fn completes_types_and_const_in_arg_list() {
722 check(
723 r#"
724enum Bar {
725 Baz
726}
727trait Foo {
728 type Bar;
729}
730
731const CONST: () = ();
732
733fn foo<T: Foo<$0>, const CONST_PARAM: usize>(_: T) {}
734"#,
735 expect![[r#"
736 ta Bar = type Bar;
737 tp T
738 cp CONST_PARAM
739 tt Foo
740 en Bar
741 ct CONST
742 "#]],
743 );
744 }
745} 598}
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index e49e434fa..f0da98739 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -286,8 +286,11 @@ impl<'a> CompletionContext<'a> {
286 ) 286 )
287 } 287 }
288 288
289 pub(crate) fn expect_record_field(&self) -> bool { 289 pub(crate) fn expect_field(&self) -> bool {
290 matches!(self.completion_location, Some(ImmediateLocation::RecordField)) 290 matches!(
291 self.completion_location,
292 Some(ImmediateLocation::RecordField | ImmediateLocation::TupleField)
293 )
291 } 294 }
292 295
293 pub(crate) fn in_use_tree(&self) -> bool { 296 pub(crate) fn in_use_tree(&self) -> bool {
@@ -385,14 +388,19 @@ impl<'a> CompletionContext<'a> {
385 (ty, name) 388 (ty, name)
386 }, 389 },
387 ast::ArgList(_it) => { 390 ast::ArgList(_it) => {
388 cov_mark::hit!(expected_type_fn_param_with_leading_char); 391 cov_mark::hit!(expected_type_fn_param);
389 cov_mark::hit!(expected_type_fn_param_without_leading_char);
390 ActiveParameter::at_token( 392 ActiveParameter::at_token(
391 &self.sema, 393 &self.sema,
392 self.token.clone(), 394 self.token.clone(),
393 ).map(|ap| { 395 ).map(|ap| {
394 let name = ap.ident().map(NameOrNameRef::Name); 396 let name = ap.ident().map(NameOrNameRef::Name);
395 (Some(ap.ty), name) 397 let ty = if has_ref(&self.token) {
398 cov_mark::hit!(expected_type_fn_param_ref);
399 ap.ty.remove_ref()
400 } else {
401 Some(ap.ty)
402 };
403 (ty, name)
396 }) 404 })
397 .unwrap_or((None, None)) 405 .unwrap_or((None, None))
398 }, 406 },
@@ -697,6 +705,19 @@ fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
697 use_tree.path().zip(Some(true)) 705 use_tree.path().zip(Some(true))
698} 706}
699 707
708fn has_ref(token: &SyntaxToken) -> bool {
709 let mut token = token.clone();
710 for skip in [WHITESPACE, IDENT, T![mut]] {
711 if token.kind() == skip {
712 token = match token.prev_token() {
713 Some(it) => it,
714 None => return false,
715 }
716 }
717 }
718 token.kind() == T![&]
719}
720
700#[cfg(test)] 721#[cfg(test)]
701mod tests { 722mod tests {
702 use expect_test::{expect, Expect}; 723 use expect_test::{expect, Expect};
@@ -769,14 +790,18 @@ fn foo() {
769 } 790 }
770 791
771 #[test] 792 #[test]
772 fn expected_type_fn_param_without_leading_char() { 793 fn expected_type_fn_param() {
773 cov_mark::check!(expected_type_fn_param_without_leading_char); 794 cov_mark::check!(expected_type_fn_param);
774 check_expected_type_and_name( 795 check_expected_type_and_name(
775 r#" 796 r#"
776fn foo() { 797fn foo() { bar($0); }
777 bar($0); 798fn bar(x: u32) {}
778} 799"#,
779 800 expect![[r#"ty: u32, name: x"#]],
801 );
802 check_expected_type_and_name(
803 r#"
804fn foo() { bar(c$0); }
780fn bar(x: u32) {} 805fn bar(x: u32) {}
781"#, 806"#,
782 expect![[r#"ty: u32, name: x"#]], 807 expect![[r#"ty: u32, name: x"#]],
@@ -784,18 +809,29 @@ fn bar(x: u32) {}
784 } 809 }
785 810
786 #[test] 811 #[test]
787 fn expected_type_fn_param_with_leading_char() { 812 fn expected_type_fn_param_ref() {
788 cov_mark::check!(expected_type_fn_param_with_leading_char); 813 cov_mark::check!(expected_type_fn_param_ref);
789 check_expected_type_and_name( 814 check_expected_type_and_name(
790 r#" 815 r#"
791fn foo() { 816fn foo() { bar(&$0); }
792 bar(c$0); 817fn bar(x: &u32) {}
793}
794
795fn bar(x: u32) {}
796"#, 818"#,
797 expect![[r#"ty: u32, name: x"#]], 819 expect![[r#"ty: u32, name: x"#]],
798 ); 820 );
821 check_expected_type_and_name(
822 r#"
823fn foo() { bar(&mut $0); }
824fn bar(x: &mut u32) {}
825"#,
826 expect![[r#"ty: u32, name: x"#]],
827 );
828 check_expected_type_and_name(
829 r#"
830fn foo() { bar(&c$0); }
831fn bar(x: &u32) {}
832 "#,
833 expect![[r#"ty: u32, name: x"#]],
834 );
799 } 835 }
800 836
801 #[test] 837 #[test]
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 271409c38..757c9a3da 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -31,6 +31,7 @@ pub(crate) enum ImmediateLocation {
31 Impl, 31 Impl,
32 Trait, 32 Trait,
33 RecordField, 33 RecordField,
34 TupleField,
34 RefExpr, 35 RefExpr,
35 IdentPat, 36 IdentPat,
36 BlockExpr, 37 BlockExpr,
@@ -187,7 +188,13 @@ pub(crate) fn determine_location(
187 ast::SourceFile(_it) => ImmediateLocation::ItemList, 188 ast::SourceFile(_it) => ImmediateLocation::ItemList,
188 ast::ItemList(_it) => ImmediateLocation::ItemList, 189 ast::ItemList(_it) => ImmediateLocation::ItemList,
189 ast::RefExpr(_it) => ImmediateLocation::RefExpr, 190 ast::RefExpr(_it) => ImmediateLocation::RefExpr,
190 ast::RecordField(_it) => ImmediateLocation::RecordField, 191 ast::RecordField(it) => if it.ty().map_or(false, |it| it.syntax().text_range().contains(offset)) {
192 return None;
193 } else {
194 ImmediateLocation::RecordField
195 },
196 ast::TupleField(_it) => ImmediateLocation::TupleField,
197 ast::TupleFieldList(_it) => ImmediateLocation::TupleField,
191 ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) { 198 ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) {
192 Some(IMPL) => ImmediateLocation::Impl, 199 Some(IMPL) => ImmediateLocation::Impl,
193 Some(TRAIT) => ImmediateLocation::Trait, 200 Some(TRAIT) => ImmediateLocation::Trait,
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 9bec03e17..1a9b6212a 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -1057,7 +1057,7 @@ fn f() {
1057 #[test] 1057 #[test]
1058 fn suggest_ref_mut() { 1058 fn suggest_ref_mut() {
1059 cov_mark::check!(suggest_ref); 1059 cov_mark::check!(suggest_ref);
1060 check( 1060 check_relevance(
1061 r#" 1061 r#"
1062struct S; 1062struct S;
1063fn foo(s: &mut S) {} 1063fn foo(s: &mut S) {}
@@ -1067,58 +1067,29 @@ fn main() {
1067} 1067}
1068 "#, 1068 "#,
1069 expect![[r#" 1069 expect![[r#"
1070 [ 1070 lc s [name+local]
1071 CompletionItem { 1071 lc &mut s [type+name+local]
1072 label: "S", 1072 st S []
1073 source_range: 70..70, 1073 fn main() []
1074 delete: 70..70, 1074 fn foo(…) []
1075 insert: "S",
1076 kind: SymbolKind(
1077 Struct,
1078 ),
1079 },
1080 CompletionItem {
1081 label: "foo(…)",
1082 source_range: 70..70,
1083 delete: 70..70,
1084 insert: "foo(${1:&mut s})$0",
1085 kind: SymbolKind(
1086 Function,
1087 ),
1088 lookup: "foo",
1089 detail: "fn(&mut S)",
1090 trigger_call_info: true,
1091 },
1092 CompletionItem {
1093 label: "main()",
1094 source_range: 70..70,
1095 delete: 70..70,
1096 insert: "main()$0",
1097 kind: SymbolKind(
1098 Function,
1099 ),
1100 lookup: "main",
1101 detail: "fn()",
1102 },
1103 CompletionItem {
1104 label: "s",
1105 source_range: 70..70,
1106 delete: 70..70,
1107 insert: "s",
1108 kind: SymbolKind(
1109 Local,
1110 ),
1111 detail: "S",
1112 relevance: CompletionRelevance {
1113 exact_name_match: true,
1114 type_match: None,
1115 is_local: true,
1116 },
1117 ref_match: "&mut ",
1118 },
1119 ]
1120 "#]], 1075 "#]],
1121 ) 1076 );
1077 check_relevance(
1078 r#"
1079struct S;
1080fn foo(s: &mut S) {}
1081fn main() {
1082 let mut s = S;
1083 foo(&mut $0);
1084}
1085 "#,
1086 expect![[r#"
1087 lc s [type+name+local]
1088 st S []
1089 fn main() []
1090 fn foo(…) []
1091 "#]],
1092 );
1122 } 1093 }
1123 1094
1124 #[test] 1095 #[test]
diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs
index 211c89c40..97298ff27 100644
--- a/crates/ide_completion/src/tests.rs
+++ b/crates/ide_completion/src/tests.rs
@@ -7,6 +7,10 @@
7mod item_list; 7mod item_list;
8mod use_tree; 8mod use_tree;
9mod items; 9mod items;
10mod pattern;
11mod type_pos;
12
13use std::mem;
10 14
11use hir::{PrefixKind, Semantics}; 15use hir::{PrefixKind, Semantics};
12use ide_db::{ 16use ide_db::{
@@ -45,7 +49,16 @@ pub(crate) fn completion_list(code: &str) -> String {
45} 49}
46 50
47fn completion_list_with_config(config: CompletionConfig, code: &str) -> String { 51fn completion_list_with_config(config: CompletionConfig, code: &str) -> String {
48 render_completion_list(get_all_items(config, code)) 52 // filter out all but one builtintype completion for smaller test outputs
53 let items = get_all_items(config, code);
54 let mut bt_seen = false;
55 let items = items
56 .into_iter()
57 .filter(|it| {
58 it.completion_kind != CompletionKind::BuiltinType || !mem::replace(&mut bt_seen, true)
59 })
60 .collect();
61 render_completion_list(items)
49} 62}
50 63
51/// Creates analysis from a multi-file fixture, returns positions marked with $0. 64/// Creates analysis from a multi-file fixture, returns positions marked with $0.
diff --git a/crates/ide_completion/src/tests/items.rs b/crates/ide_completion/src/tests/items.rs
index 8dfb8221b..b98baffd6 100644
--- a/crates/ide_completion/src/tests/items.rs
+++ b/crates/ide_completion/src/tests/items.rs
@@ -35,22 +35,6 @@ impl Tra$0
35 ma foo!(…) #[macro_export] macro_rules! foo 35 ma foo!(…) #[macro_export] macro_rules! foo
36 ma foo!(…) #[macro_export] macro_rules! foo 36 ma foo!(…) #[macro_export] macro_rules! foo
37 bt u32 37 bt u32
38 bt bool
39 bt u8
40 bt isize
41 bt u16
42 bt u64
43 bt u128
44 bt f32
45 bt i128
46 bt i16
47 bt str
48 bt i64
49 bt char
50 bt f64
51 bt i32
52 bt i8
53 bt usize
54 "##]], 38 "##]],
55 ) 39 )
56} 40}
@@ -69,22 +53,6 @@ impl Trait for Str$0
69 ma foo!(…) #[macro_export] macro_rules! foo 53 ma foo!(…) #[macro_export] macro_rules! foo
70 ma foo!(…) #[macro_export] macro_rules! foo 54 ma foo!(…) #[macro_export] macro_rules! foo
71 bt u32 55 bt u32
72 bt bool
73 bt u8
74 bt isize
75 bt u16
76 bt u64
77 bt u128
78 bt f32
79 bt i128
80 bt i16
81 bt str
82 bt i64
83 bt char
84 bt f64
85 bt i32
86 bt i8
87 bt usize
88 "##]], 56 "##]],
89 ) 57 )
90} 58}
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs
new file mode 100644
index 000000000..1ad5ccd97
--- /dev/null
+++ b/crates/ide_completion/src/tests/pattern.rs
@@ -0,0 +1,348 @@
1//! Completions tests for pattern position.
2use expect_test::{expect, Expect};
3
4use crate::tests::completion_list;
5
6fn check(ra_fixture: &str, expect: Expect) {
7 let actual = completion_list(ra_fixture);
8 expect.assert_eq(&actual)
9}
10
11fn check_with(ra_fixture: &str, expect: Expect) {
12 let base = r#"
13enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
14use self::Enum::TupleV;
15mod module {}
16
17static STATIC: Unit = Unit;
18const CONST: Unit = Unit;
19struct Record { field: u32 }
20struct Tuple(u32);
21struct Unit
22macro_rules! makro {}
23"#;
24 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
25 expect.assert_eq(&actual)
26}
27
28#[test]
29fn ident_rebind_pat() {
30 check(
31 r#"
32fn quux() {
33 let en$0 @ x
34}
35"#,
36 expect![[r#"
37 kw mut
38 "#]],
39 );
40}
41
42#[test]
43fn ident_ref_pat() {
44 check(
45 r#"
46fn quux() {
47 let ref en$0
48}
49"#,
50 expect![[r#"
51 kw mut
52 "#]],
53 );
54 check(
55 r#"
56fn quux() {
57 let ref en$0 @ x
58}
59"#,
60 expect![[r#"
61 kw mut
62 "#]],
63 );
64}
65
66#[test]
67fn ident_ref_mut_pat() {
68 // FIXME mut is already here, don't complete it again
69 check(
70 r#"
71fn quux() {
72 let ref mut en$0
73}
74"#,
75 expect![[r#"
76 kw mut
77 "#]],
78 );
79 check(
80 r#"
81fn quux() {
82 let ref mut en$0 @ x
83}
84"#,
85 expect![[r#"
86 kw mut
87 "#]],
88 );
89}
90
91#[test]
92fn ref_pat() {
93 check(
94 r#"
95fn quux() {
96 let &en$0
97}
98"#,
99 expect![[r#"
100 kw mut
101 "#]],
102 );
103 // FIXME mut is already here, don't complete it again
104 check(
105 r#"
106fn quux() {
107 let &mut en$0
108}
109"#,
110 expect![[r#"
111 kw mut
112 "#]],
113 );
114}
115
116#[test]
117fn refutable() {
118 check_with(
119 r#"
120fn foo() {
121 if let a$0
122}
123"#,
124 expect![[r#"
125 kw mut
126 bn Record Record { field$1 }$0
127 st Record
128 en Enum
129 bn Tuple Tuple($1)$0
130 st Tuple
131 md module
132 bn TupleV TupleV($1)$0
133 ev TupleV
134 st Unit
135 ct CONST
136 ma makro!(…) macro_rules! makro
137 "#]],
138 );
139}
140
141#[test]
142fn irrefutable() {
143 check_with(
144 r#"
145fn foo() {
146 let a$0
147}
148"#,
149 expect![[r#"
150 kw mut
151 bn Record Record { field$1 }$0
152 st Record
153 bn Tuple Tuple($1)$0
154 st Tuple
155 st Unit
156 ma makro!(…) macro_rules! makro
157 "#]],
158 );
159}
160
161#[test]
162fn in_param() {
163 check_with(
164 r#"
165fn foo(a$0) {
166}
167"#,
168 expect![[r#"
169 kw mut
170 bn Record Record { field$1 }: Record$0
171 st Record
172 bn Tuple Tuple($1): Tuple$0
173 st Tuple
174 st Unit
175 ma makro!(…) macro_rules! makro
176 "#]],
177 );
178}
179
180#[test]
181fn only_fn_like_macros() {
182 check(
183 r#"
184macro_rules! m { ($e:expr) => { $e } }
185
186#[rustc_builtin_macro]
187macro Clone {}
188
189fn foo() {
190 let x$0
191}
192"#,
193 expect![[r#"
194 kw mut
195 ma m!(…) macro_rules! m
196 "#]],
197 );
198}
199
200#[test]
201fn in_simple_macro_call() {
202 check(
203 r#"
204macro_rules! m { ($e:expr) => { $e } }
205enum E { X }
206
207fn foo() {
208 m!(match E::X { a$0 })
209}
210"#,
211 expect![[r#"
212 kw mut
213 ev E::X ()
214 en E
215 ma m!(…) macro_rules! m
216 "#]],
217 );
218}
219
220#[test]
221fn omits_private_fields_pat() {
222 check(
223 r#"
224mod foo {
225 pub struct Record { pub field: i32, _field: i32 }
226 pub struct Tuple(pub u32, u32);
227 pub struct Invisible(u32, u32);
228}
229use foo::*;
230
231fn outer() {
232 if let a$0
233}
234"#,
235 expect![[r#"
236 kw mut
237 bn Record Record { field$1, .. }$0
238 st Record
239 bn Tuple Tuple($1, ..)$0
240 st Tuple
241 st Invisible
242 md foo
243 "#]],
244 )
245}
246
247// #[test]
248// fn only_shows_ident_completion() {
249// check_edit(
250// "Foo",
251// r#"
252// struct Foo(i32);
253// fn main() {
254// match Foo(92) {
255// a$0(92) => (),
256// }
257// }
258// "#,
259// r#"
260// struct Foo(i32);
261// fn main() {
262// match Foo(92) {
263// Foo(92) => (),
264// }
265// }
266// "#,
267// );
268// }
269
270#[test]
271fn completes_self_pats() {
272 check(
273 r#"
274struct Foo(i32);
275impl Foo {
276 fn foo() {
277 match Foo(0) {
278 a$0
279 }
280 }
281}
282 "#,
283 expect![[r#"
284 kw mut
285 bn Self Self($1)$0
286 sp Self
287 bn Foo Foo($1)$0
288 st Foo
289 "#]],
290 )
291}
292
293#[test]
294fn completes_qualified_variant() {
295 check(
296 r#"
297enum Foo {
298 Bar { baz: i32 }
299}
300impl Foo {
301 fn foo() {
302 match {Foo::Bar { baz: 0 }} {
303 B$0
304 }
305 }
306}
307 "#,
308 expect![[r#"
309 kw mut
310 bn Self::Bar Self::Bar { baz$1 }$0
311 ev Self::Bar { baz: i32 }
312 bn Foo::Bar Foo::Bar { baz$1 }$0
313 ev Foo::Bar { baz: i32 }
314 sp Self
315 en Foo
316 "#]],
317 )
318}
319
320#[test]
321fn completes_in_record_field_pat() {
322 check(
323 r#"
324struct Foo { bar: Bar }
325struct Bar(u32);
326fn outer(Foo { bar: $0 }: Foo) {}
327"#,
328 expect![[r#"
329 kw mut
330 bn Foo Foo { bar$1 }$0
331 st Foo
332 bn Bar Bar($1)$0
333 st Bar
334 "#]],
335 )
336}
337
338#[test]
339fn skips_in_record_field_pat_name() {
340 check(
341 r#"
342struct Foo { bar: Bar }
343struct Bar(u32);
344fn outer(Foo { bar$0 }: Foo) {}
345"#,
346 expect![[r#""#]],
347 )
348}
diff --git a/crates/ide_completion/src/tests/type_pos.rs b/crates/ide_completion/src/tests/type_pos.rs
new file mode 100644
index 000000000..1ab47b27e
--- /dev/null
+++ b/crates/ide_completion/src/tests/type_pos.rs
@@ -0,0 +1,177 @@
1//! Completions tests for type position.
2use expect_test::{expect, Expect};
3
4use crate::tests::completion_list;
5
6fn check_with(ra_fixture: &str, expect: Expect) {
7 let base = r#"
8enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
9use self::Enum::TupleV;
10mod module {}
11
12trait Trait {}
13static STATIC: Unit = Unit;
14const CONST: Unit = Unit;
15struct Record { field: u32 }
16struct Tuple(u32);
17struct Unit
18macro_rules! makro {}
19"#;
20 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
21 expect.assert_eq(&actual)
22}
23
24#[test]
25fn record_field_ty() {
26 check_with(
27 r#"
28struct Foo<'lt, T, const C: usize> {
29 f: $0
30}
31"#,
32 expect![[r#"
33 sp Self
34 tp T
35 tt Trait
36 en Enum
37 st Record
38 st Tuple
39 md module
40 st Foo<…>
41 st Unit
42 ma makro!(…) macro_rules! makro
43 bt u32
44 "#]],
45 )
46}
47
48#[test]
49fn tuple_struct_field() {
50 check_with(
51 r#"
52struct Foo<'lt, T, const C: usize>(f$0);
53"#,
54 expect![[r#"
55 kw pub(crate)
56 kw pub
57 sp Self
58 tp T
59 tt Trait
60 en Enum
61 st Record
62 st Tuple
63 md module
64 st Foo<…>
65 st Unit
66 ma makro!(…) macro_rules! makro
67 bt u32
68 "#]],
69 )
70}
71
72#[test]
73fn fn_return_type() {
74 check_with(
75 r#"
76fn x<'lt, T, const C: usize>() -> $0
77"#,
78 expect![[r#"
79 tp T
80 tt Trait
81 en Enum
82 st Record
83 st Tuple
84 md module
85 st Unit
86 ma makro!(…) macro_rules! makro
87 bt u32
88 "#]],
89 );
90}
91
92#[test]
93fn body_type_pos() {
94 check_with(
95 r#"
96fn foo<'lt, T, const C: usize>() {
97 let local = ();
98 let _: $0;
99}
100"#,
101 expect![[r#"
102 tp T
103 tt Trait
104 en Enum
105 st Record
106 st Tuple
107 md module
108 st Unit
109 ma makro!(…) macro_rules! makro
110 bt u32
111 "#]],
112 );
113 check_with(
114 r#"
115fn foo<'lt, T, const C: usize>() {
116 let local = ();
117 let _: self::$0;
118}
119"#,
120 expect![[r#"
121 tt Trait
122 en Enum
123 st Record
124 st Tuple
125 md module
126 st Unit
127 "#]],
128 );
129}
130
131#[test]
132fn completes_types_and_const_in_arg_list() {
133 // FIXME: we should complete the lifetime here for now
134 check_with(
135 r#"
136trait Trait2 {
137 type Foo;
138}
139
140fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
141"#,
142 expect![[r#"
143 ta Foo = type Foo;
144 tp T
145 cp CONST_PARAM
146 tt Trait
147 en Enum
148 st Record
149 st Tuple
150 tt Trait2
151 md module
152 st Unit
153 ct CONST
154 ma makro!(…) macro_rules! makro
155 bt u32
156 "#]],
157 );
158 check_with(
159 r#"
160trait Trait2 {
161 type Foo;
162}
163
164fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {}
165 "#,
166 expect![[r#"
167 tt Trait
168 en Enum
169 st Record
170 st Tuple
171 tt Trait2
172 md module
173 st Unit
174 ct CONST
175 "#]],
176 );
177}
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index b4f2fe9a4..0d694b1a7 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -645,7 +645,7 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
645 None if match_res.err.is_none() => { 645 None if match_res.err.is_none() => {
646 bindings_builder.push_optional(&mut item.bindings, name); 646 bindings_builder.push_optional(&mut item.bindings, name);
647 } 647 }
648 _ => {} 648 None => {}
649 } 649 }
650 if let Some(err) = match_res.err { 650 if let Some(err) = match_res.err {
651 res.add_err(err); 651 res.add_err(err);
@@ -756,7 +756,7 @@ impl<'a> TtIter<'a> {
756 let ok = match separator { 756 let ok = match separator {
757 Separator::Ident(lhs) if idx == 0 => match fork.expect_ident_or_underscore() { 757 Separator::Ident(lhs) if idx == 0 => match fork.expect_ident_or_underscore() {
758 Ok(rhs) => rhs.text == lhs.text, 758 Ok(rhs) => rhs.text == lhs.text,
759 _ => false, 759 Err(_) => false,
760 }, 760 },
761 Separator::Literal(lhs) if idx == 0 => match fork.expect_literal() { 761 Separator::Literal(lhs) if idx == 0 => match fork.expect_literal() {
762 Ok(rhs) => match rhs { 762 Ok(rhs) => match rhs {
@@ -764,11 +764,11 @@ impl<'a> TtIter<'a> {
764 tt::Leaf::Ident(rhs) => rhs.text == lhs.text, 764 tt::Leaf::Ident(rhs) => rhs.text == lhs.text,
765 tt::Leaf::Punct(_) => false, 765 tt::Leaf::Punct(_) => false,
766 }, 766 },
767 _ => false, 767 Err(_) => false,
768 }, 768 },
769 Separator::Puncts(lhss) if idx < lhss.len() => match fork.expect_punct() { 769 Separator::Puncts(lhss) if idx < lhss.len() => match fork.expect_punct() {
770 Ok(rhs) => rhs.char == lhss[idx].char, 770 Ok(rhs) => rhs.char == lhss[idx].char,
771 _ => false, 771 Err(_) => false,
772 }, 772 },
773 _ => false, 773 _ => false,
774 }; 774 };
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index 49a137577..4894e2a0c 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -241,6 +241,6 @@ fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
241fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) { 241fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
242 match tt.delimiter { 242 match tt.delimiter {
243 None => buf.extend(tt.token_trees), 243 None => buf.extend(tt.token_trees),
244 _ => buf.push(tt.into()), 244 Some(_) => buf.push(tt.into()),
245 } 245 }
246} 246}
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 8c8528aaf..fcc596756 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -135,7 +135,7 @@ impl Shift {
135 135
136 /// Shift given TokenTree token id 136 /// Shift given TokenTree token id
137 fn shift_all(self, tt: &mut tt::Subtree) { 137 fn shift_all(self, tt: &mut tt::Subtree) {
138 for t in tt.token_trees.iter_mut() { 138 for t in &mut tt.token_trees {
139 match t { 139 match t {
140 tt::TokenTree::Leaf(leaf) => match leaf { 140 tt::TokenTree::Leaf(leaf) => match leaf {
141 tt::Leaf::Ident(ident) => ident.id = self.shift(ident.id), 141 tt::Leaf::Ident(ident) => ident.id = self.shift(ident.id),
@@ -188,7 +188,7 @@ impl MacroRules {
188 } 188 }
189 } 189 }
190 190
191 for rule in rules.iter() { 191 for rule in &rules {
192 validate(&rule.lhs)?; 192 validate(&rule.lhs)?;
193 } 193 }
194 194
@@ -241,7 +241,7 @@ impl MacroDef {
241 } 241 }
242 rules.push(rule); 242 rules.push(rule);
243 } 243 }
244 for rule in rules.iter() { 244 for rule in &rules {
245 validate(&rule.lhs)?; 245 validate(&rule.lhs)?;
246 } 246 }
247 247
@@ -268,7 +268,7 @@ impl MacroDef {
268} 268}
269 269
270impl Rule { 270impl Rule {
271 fn parse(src: &mut TtIter, expect_arrow: bool) -> Result<Rule, ParseError> { 271 fn parse(src: &mut TtIter, expect_arrow: bool) -> Result<Self, ParseError> {
272 let lhs = src 272 let lhs = src
273 .expect_subtree() 273 .expect_subtree()
274 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; 274 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?;
@@ -356,7 +356,7 @@ impl<T> ExpandResult<T> {
356 } 356 }
357 357
358 pub fn result(self) -> Result<T, ExpandError> { 358 pub fn result(self) -> Result<T, ExpandError> {
359 self.err.map(Err).unwrap_or(Ok(self.value)) 359 self.err.map_or(Ok(self.value), Err)
360 } 360 }
361} 361}
362 362
diff --git a/crates/mbe/src/subtree_source.rs b/crates/mbe/src/subtree_source.rs
index ee80807ad..ffc2a6017 100644
--- a/crates/mbe/src/subtree_source.rs
+++ b/crates/mbe/src/subtree_source.rs
@@ -115,7 +115,7 @@ impl<'a> TokenSource for SubtreeTokenSource {
115 fn is_keyword(&self, kw: &str) -> bool { 115 fn is_keyword(&self, kw: &str) -> bool {
116 match self.cached.get(self.curr.1) { 116 match self.cached.get(self.curr.1) {
117 Some(t) => t.text == *kw, 117 Some(t) => t.text == *kw,
118 _ => false, 118 None => false,
119 } 119 }
120 } 120 }
121} 121}
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index cdc22425d..7526bd8e6 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -283,7 +283,7 @@ trait TokenConvertor {
283 let (id, idx) = self.id_alloc().open_delim(range); 283 let (id, idx) = self.id_alloc().open_delim(range);
284 subtree.delimiter = Some(tt::Delimiter { id, kind }); 284 subtree.delimiter = Some(tt::Delimiter { id, kind });
285 285
286 while self.peek().map(|it| it.kind() != closed).unwrap_or(false) { 286 while self.peek().map_or(false, |it| it.kind() != closed) {
287 self.collect_leaf(&mut subtree.token_trees); 287 self.collect_leaf(&mut subtree.token_trees);
288 } 288 }
289 let last_range = match self.bump() { 289 let last_range = match self.bump() {
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
index 5a4eca7bf..65da83476 100644
--- a/crates/mbe/src/tt_iter.rs
+++ b/crates/mbe/src/tt_iter.rs
@@ -121,10 +121,11 @@ impl<'a> TtIter<'a> {
121 121
122 parser::parse_fragment(&mut src, &mut sink, fragment_kind); 122 parser::parse_fragment(&mut src, &mut sink, fragment_kind);
123 123
124 let mut err = None; 124 let mut err = if !sink.cursor.is_root() || sink.error {
125 if !sink.cursor.is_root() || sink.error { 125 Some(err!("expected {:?}", fragment_kind))
126 err = Some(err!("expected {:?}", fragment_kind)); 126 } else {
127 } 127 None
128 };
128 129
129 let mut curr = buffer.begin(); 130 let mut curr = buffer.begin();
130 let mut res = vec![]; 131 let mut res = vec![];
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs
index 65ca3eb6c..e252e89a5 100644
--- a/crates/proc_macro_srv/src/rustc_server.rs
+++ b/crates/proc_macro_srv/src/rustc_server.rs
@@ -248,7 +248,7 @@ pub mod token_stream {
248 token_trees: subtree 248 token_trees: subtree
249 .token_trees 249 .token_trees
250 .into_iter() 250 .into_iter()
251 .map(|t| token_tree_replace_token_ids_with_unspecified(t)) 251 .map(token_tree_replace_token_ids_with_unspecified)
252 .collect(), 252 .collect(),
253 } 253 }
254 } 254 }
@@ -457,7 +457,7 @@ impl server::Group for Rustc {
457 } 457 }
458 458
459 fn span(&mut self, group: &Self::Group) -> Self::Span { 459 fn span(&mut self, group: &Self::Group) -> Self::Span {
460 group.delimiter.map(|it| it.id).unwrap_or_else(|| tt::TokenId::unspecified()) 460 group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified)
461 } 461 }
462 462
463 fn set_span(&mut self, _group: &mut Self::Group, _span: Self::Span) { 463 fn set_span(&mut self, _group: &mut Self::Group, _span: Self::Span) {
diff --git a/crates/proc_macro_test/build.rs b/crates/proc_macro_test/build.rs
index 4653a93dd..1e7aa026f 100644
--- a/crates/proc_macro_test/build.rs
+++ b/crates/proc_macro_test/build.rs
@@ -17,9 +17,16 @@ fn main() {
17 17
18 let name = "proc_macro_test_impl"; 18 let name = "proc_macro_test_impl";
19 let version = "0.0.0"; 19 let version = "0.0.0";
20 let target_dir = out_dir.join("target");
20 let output = Command::new(toolchain::cargo()) 21 let output = Command::new(toolchain::cargo())
21 .current_dir("imp") 22 .current_dir("imp")
22 .args(&["build", "-p", "proc_macro_test_impl", "--message-format", "json"]) 23 .args(&["build", "-p", "proc_macro_test_impl", "--message-format", "json"])
24 // Explicit override the target directory to avoid using the same one which the parent
25 // cargo is using, or we'll deadlock.
26 // This can happen when `CARGO_TARGET_DIR` is set or global config forces all cargo
27 // instance to use the same target directory.
28 .arg("--target-dir")
29 .arg(&target_dir)
23 .output() 30 .output()
24 .unwrap(); 31 .unwrap();
25 assert!(output.status.success()); 32 assert!(output.status.success());
@@ -39,10 +46,9 @@ fn main() {
39 } 46 }
40 } 47 }
41 48
42 let src_path = artifact_path.expect("no dylib for proc_macro_test_impl found"); 49 // This file is under `target_dir` and is already under `OUT_DIR`.
43 let dest_path = out_dir.join(src_path.file_name().unwrap()); 50 let artifact_path = artifact_path.expect("no dylib for proc_macro_test_impl found");
44 fs::copy(src_path, &dest_path).unwrap();
45 51
46 let info_path = out_dir.join("proc_macro_test_location.txt"); 52 let info_path = out_dir.join("proc_macro_test_location.txt");
47 fs::write(info_path, dest_path.to_str().unwrap()).unwrap(); 53 fs::write(info_path, artifact_path.to_str().unwrap()).unwrap();
48} 54}
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index ac079f83e..0935ea967 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -1,5 +1,6 @@
1//! See [`CargoWorkspace`]. 1//! See [`CargoWorkspace`].
2 2
3use std::iter;
3use std::path::PathBuf; 4use std::path::PathBuf;
4use std::{convert::TryInto, ops, process::Command, sync::Arc}; 5use std::{convert::TryInto, ops, process::Command, sync::Arc};
5 6
@@ -12,6 +13,7 @@ use rustc_hash::FxHashMap;
12use serde::Deserialize; 13use serde::Deserialize;
13use serde_json::from_value; 14use serde_json::from_value;
14 15
16use crate::CfgOverrides;
15use crate::{build_data::BuildDataConfig, utf8_stdout}; 17use crate::{build_data::BuildDataConfig, utf8_stdout};
16 18
17/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo 19/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
@@ -76,6 +78,21 @@ pub struct CargoConfig {
76 78
77 /// rustc private crate source 79 /// rustc private crate source
78 pub rustc_source: Option<RustcSource>, 80 pub rustc_source: Option<RustcSource>,
81
82 /// crates to disable `#[cfg(test)]` on
83 pub unset_test_crates: Vec<String>,
84}
85
86impl CargoConfig {
87 pub fn cfg_overrides(&self) -> CfgOverrides {
88 self.unset_test_crates
89 .iter()
90 .cloned()
91 .zip(iter::repeat_with(|| {
92 cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap()
93 }))
94 .collect()
95 }
79} 96}
80 97
81pub type Package = Idx<PackageData>; 98pub type Package = Idx<PackageData>;
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs
index 8c6cf94c2..1d408dff2 100644
--- a/crates/project_model/src/lib.rs
+++ b/crates/project_model/src/lib.rs
@@ -41,7 +41,7 @@ pub use crate::{
41 }, 41 },
42 project_json::{ProjectJson, ProjectJsonData}, 42 project_json::{ProjectJson, ProjectJsonData},
43 sysroot::Sysroot, 43 sysroot::Sysroot,
44 workspace::{PackageRoot, ProjectWorkspace}, 44 workspace::{CfgOverrides, PackageRoot, ProjectWorkspace},
45}; 45};
46 46
47pub use proc_macro_api::ProcMacroClient; 47pub use proc_macro_api::ProcMacroClient;
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs
index a22f79c15..006263da8 100644
--- a/crates/project_model/src/sysroot.rs
+++ b/crates/project_model/src/sysroot.rs
@@ -68,8 +68,9 @@ impl Sysroot {
68 pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> { 68 pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> {
69 let mut sysroot = Sysroot { crates: Arena::default() }; 69 let mut sysroot = Sysroot { crates: Arena::default() };
70 70
71 for name in SYSROOT_CRATES.trim().lines() { 71 for path in SYSROOT_CRATES.trim().lines() {
72 let root = [format!("{}/src/lib.rs", name), format!("lib{}/lib.rs", name)] 72 let name = path.split('/').last().unwrap();
73 let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)]
73 .iter() 74 .iter()
74 .map(|it| sysroot_src_dir.join(it)) 75 .map(|it| sysroot_src_dir.join(it))
75 .find(|it| it.exists()); 76 .find(|it| it.exists());
@@ -191,9 +192,8 @@ panic_abort
191panic_unwind 192panic_unwind
192proc_macro 193proc_macro
193profiler_builtins 194profiler_builtins
194rtstartup
195std 195std
196stdarch 196stdarch/crates/std_detect
197term 197term
198test 198test
199unwind"; 199unwind";
@@ -204,9 +204,8 @@ core
204panic_abort 204panic_abort
205panic_unwind 205panic_unwind
206profiler_builtins 206profiler_builtins
207rtstartup
208proc_macro 207proc_macro
209stdarch 208std_detect
210term 209term
211test 210test
212unwind"; 211unwind";
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index ef0f3c9e4..e67ba2bd9 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, path::Path, process::Command};
7use anyhow::{format_err, Context, Result}; 7use anyhow::{format_err, Context, Result};
8use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; 8use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro};
9use cargo_workspace::DepKind; 9use cargo_workspace::DepKind;
10use cfg::CfgOptions; 10use cfg::{CfgDiff, CfgOptions};
11use paths::{AbsPath, AbsPathBuf}; 11use paths::{AbsPath, AbsPathBuf};
12use proc_macro_api::ProcMacroClient; 12use proc_macro_api::ProcMacroClient;
13use rustc_hash::{FxHashMap, FxHashSet}; 13use rustc_hash::{FxHashMap, FxHashSet};
@@ -22,6 +22,8 @@ use crate::{
22 Sysroot, TargetKind, 22 Sysroot, TargetKind,
23}; 23};
24 24
25pub type CfgOverrides = FxHashMap<String, CfgDiff>;
26
25/// `PackageRoot` describes a package root folder. 27/// `PackageRoot` describes a package root folder.
26/// Which may be an external dependency, or a member of 28/// Which may be an external dependency, or a member of
27/// the current workspace. 29/// the current workspace.
@@ -46,6 +48,7 @@ pub enum ProjectWorkspace {
46 /// FIXME: make this a per-crate map, as, eg, build.rs might have a 48 /// FIXME: make this a per-crate map, as, eg, build.rs might have a
47 /// different target. 49 /// different target.
48 rustc_cfg: Vec<CfgFlag>, 50 rustc_cfg: Vec<CfgFlag>,
51 cfg_overrides: CfgOverrides,
49 }, 52 },
50 /// Project workspace was manually specified using a `rust-project.json` file. 53 /// Project workspace was manually specified using a `rust-project.json` file.
51 Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, 54 Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
@@ -67,7 +70,7 @@ impl fmt::Debug for ProjectWorkspace {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 // Make sure this isn't too verbose. 71 // Make sure this isn't too verbose.
69 match self { 72 match self {
70 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f 73 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => f
71 .debug_struct("Cargo") 74 .debug_struct("Cargo")
72 .field("root", &cargo.workspace_root().file_name()) 75 .field("root", &cargo.workspace_root().file_name())
73 .field("n_packages", &cargo.packages().len()) 76 .field("n_packages", &cargo.packages().len())
@@ -77,6 +80,7 @@ impl fmt::Debug for ProjectWorkspace {
77 &rustc.as_ref().map_or(0, |rc| rc.packages().len()), 80 &rustc.as_ref().map_or(0, |rc| rc.packages().len()),
78 ) 81 )
79 .field("n_rustc_cfg", &rustc_cfg.len()) 82 .field("n_rustc_cfg", &rustc_cfg.len())
83 .field("n_cfg_overrides", &cfg_overrides.len())
80 .finish(), 84 .finish(),
81 ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { 85 ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
82 let mut debug_struct = f.debug_struct("Json"); 86 let mut debug_struct = f.debug_struct("Json");
@@ -164,7 +168,9 @@ impl ProjectWorkspace {
164 }; 168 };
165 169
166 let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); 170 let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
167 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } 171
172 let cfg_overrides = config.cfg_overrides();
173 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides }
168 } 174 }
169 }; 175 };
170 176
@@ -213,43 +219,45 @@ impl ProjectWorkspace {
213 }) 219 })
214 })) 220 }))
215 .collect::<Vec<_>>(), 221 .collect::<Vec<_>>(),
216 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo 222 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _, cfg_overrides: _ } => {
217 .packages() 223 cargo
218 .map(|pkg| { 224 .packages()
219 let is_member = cargo[pkg].is_member; 225 .map(|pkg| {
220 let pkg_root = cargo[pkg].root().to_path_buf(); 226 let is_member = cargo[pkg].is_member;
221 227 let pkg_root = cargo[pkg].root().to_path_buf();
222 let mut include = vec![pkg_root.clone()]; 228
223 include.extend( 229 let mut include = vec![pkg_root.clone()];
224 build_data 230 include.extend(
225 .and_then(|it| it.get(cargo.workspace_root())) 231 build_data
226 .and_then(|map| map.get(&cargo[pkg].id)) 232 .and_then(|it| it.get(cargo.workspace_root()))
227 .and_then(|it| it.out_dir.clone()), 233 .and_then(|map| map.get(&cargo[pkg].id))
228 ); 234 .and_then(|it| it.out_dir.clone()),
235 );
229 236
230 let mut exclude = vec![pkg_root.join(".git")]; 237 let mut exclude = vec![pkg_root.join(".git")];
231 if is_member { 238 if is_member {
232 exclude.push(pkg_root.join("target")); 239 exclude.push(pkg_root.join("target"));
233 } else { 240 } else {
234 exclude.push(pkg_root.join("tests")); 241 exclude.push(pkg_root.join("tests"));
235 exclude.push(pkg_root.join("examples")); 242 exclude.push(pkg_root.join("examples"));
236 exclude.push(pkg_root.join("benches")); 243 exclude.push(pkg_root.join("benches"));
237 } 244 }
238 PackageRoot { is_member, include, exclude } 245 PackageRoot { is_member, include, exclude }
239 }) 246 })
240 .chain(sysroot.crates().map(|krate| PackageRoot { 247 .chain(sysroot.crates().map(|krate| PackageRoot {
241 is_member: false,
242 include: vec![sysroot[krate].root_dir().to_path_buf()],
243 exclude: Vec::new(),
244 }))
245 .chain(rustc.into_iter().flat_map(|rustc| {
246 rustc.packages().map(move |krate| PackageRoot {
247 is_member: false, 248 is_member: false,
248 include: vec![rustc[krate].root().to_path_buf()], 249 include: vec![sysroot[krate].root_dir().to_path_buf()],
249 exclude: Vec::new(), 250 exclude: Vec::new(),
250 }) 251 }))
251 })) 252 .chain(rustc.into_iter().flat_map(|rustc| {
252 .collect(), 253 rustc.packages().map(move |krate| PackageRoot {
254 is_member: false,
255 include: vec![rustc[krate].root().to_path_buf()],
256 exclude: Vec::new(),
257 })
258 }))
259 .collect()
260 }
253 ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files 261 ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files
254 .into_iter() 262 .into_iter()
255 .map(|detached_file| PackageRoot { 263 .map(|detached_file| PackageRoot {
@@ -299,16 +307,22 @@ impl ProjectWorkspace {
299 project, 307 project,
300 sysroot, 308 sysroot,
301 ), 309 ),
302 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph( 310 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => {
303 rustc_cfg.clone(), 311 cargo_to_crate_graph(
304 &proc_macro_loader, 312 rustc_cfg.clone(),
305 load, 313 cfg_overrides,
306 cargo, 314 &proc_macro_loader,
307 build_data.and_then(|it| it.get(cargo.workspace_root())), 315 load,
308 sysroot, 316 cargo,
309 rustc, 317 build_data.and_then(|it| it.get(cargo.workspace_root())),
310 rustc.as_ref().zip(build_data).and_then(|(it, map)| map.get(it.workspace_root())), 318 sysroot,
311 ), 319 rustc,
320 rustc
321 .as_ref()
322 .zip(build_data)
323 .and_then(|(it, map)| map.get(it.workspace_root())),
324 )
325 }
312 ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { 326 ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
313 detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) 327 detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot)
314 } 328 }
@@ -370,6 +384,7 @@ fn project_json_to_crate_graph(
370 file_id, 384 file_id,
371 krate.edition, 385 krate.edition,
372 krate.display_name.clone(), 386 krate.display_name.clone(),
387 cfg_options.clone(),
373 cfg_options, 388 cfg_options,
374 env, 389 env,
375 proc_macro.unwrap_or_default(), 390 proc_macro.unwrap_or_default(),
@@ -398,6 +413,7 @@ fn project_json_to_crate_graph(
398 413
399fn cargo_to_crate_graph( 414fn cargo_to_crate_graph(
400 rustc_cfg: Vec<CfgFlag>, 415 rustc_cfg: Vec<CfgFlag>,
416 override_cfg: &CfgOverrides,
401 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, 417 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
402 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, 418 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
403 cargo: &CargoWorkspace, 419 cargo: &CargoWorkspace,
@@ -425,6 +441,21 @@ fn cargo_to_crate_graph(
425 let mut has_private = false; 441 let mut has_private = false;
426 // Next, create crates for each package, target pair 442 // Next, create crates for each package, target pair
427 for pkg in cargo.packages() { 443 for pkg in cargo.packages() {
444 let mut cfg_options = &cfg_options;
445 let mut replaced_cfg_options;
446 if let Some(overrides) = override_cfg.get(&cargo[pkg].name) {
447 // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
448 // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
449 // working on rust-lang/rust as that's the only time it appears outside sysroot).
450 //
451 // A more ideal solution might be to reanalyze crates based on where the cursor is and
452 // figure out the set of cfgs that would have to apply to make it active.
453
454 replaced_cfg_options = cfg_options.clone();
455 replaced_cfg_options.apply_diff(overrides.clone());
456 cfg_options = &replaced_cfg_options;
457 };
458
428 has_private |= cargo[pkg].metadata.rustc_private; 459 has_private |= cargo[pkg].metadata.rustc_private;
429 let mut lib_tgt = None; 460 let mut lib_tgt = None;
430 for &tgt in cargo[pkg].targets.iter() { 461 for &tgt in cargo[pkg].targets.iter() {
@@ -550,6 +581,7 @@ fn detached_files_to_crate_graph(
550 Edition::Edition2018, 581 Edition::Edition2018,
551 display_name, 582 display_name,
552 cfg_options.clone(), 583 cfg_options.clone(),
584 cfg_options.clone(),
553 Env::default(), 585 Env::default(),
554 Vec::new(), 586 Vec::new(),
555 ); 587 );
@@ -689,11 +721,19 @@ fn add_target_crate_root(
689 .unwrap_or_default(); 721 .unwrap_or_default();
690 722
691 let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string()); 723 let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
724 let mut potential_cfg_options = cfg_options.clone();
725 potential_cfg_options.extend(
726 pkg.features
727 .iter()
728 .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
729 );
730
692 let crate_id = crate_graph.add_crate_root( 731 let crate_id = crate_graph.add_crate_root(
693 file_id, 732 file_id,
694 edition, 733 edition,
695 Some(display_name), 734 Some(display_name),
696 cfg_options, 735 cfg_options,
736 potential_cfg_options,
697 env, 737 env,
698 proc_macro, 738 proc_macro,
699 ); 739 );
@@ -723,6 +763,7 @@ fn sysroot_to_crate_graph(
723 Edition::Edition2018, 763 Edition::Edition2018,
724 Some(display_name), 764 Some(display_name),
725 cfg_options.clone(), 765 cfg_options.clone(),
766 cfg_options.clone(),
726 env, 767 env,
727 proc_macro, 768 proc_macro,
728 ); 769 );
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 16c295639..b9aa6f0aa 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -10,7 +10,10 @@
10use std::{ffi::OsString, iter, path::PathBuf}; 10use std::{ffi::OsString, iter, path::PathBuf};
11 11
12use flycheck::FlycheckConfig; 12use flycheck::FlycheckConfig;
13use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; 13use ide::{
14 AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, HoverDocFormat,
15 InlayHintsConfig,
16};
14use ide_db::helpers::{ 17use ide_db::helpers::{
15 insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, 18 insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
16 SnippetCap, 19 SnippetCap,
@@ -32,6 +35,9 @@ use crate::{
32// 35//
33// However, editor specific config, which the server doesn't know about, should 36// However, editor specific config, which the server doesn't know about, should
34// be specified directly in `package.json`. 37// be specified directly in `package.json`.
38//
39// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep
40// parsing the old name.
35config_data! { 41config_data! {
36 struct ConfigData { 42 struct ConfigData {
37 /// How imports should be grouped into use statements. 43 /// How imports should be grouped into use statements.
@@ -55,6 +61,8 @@ config_data! {
55 cargo_autoreload: bool = "true", 61 cargo_autoreload: bool = "true",
56 /// Activate all available features (`--all-features`). 62 /// Activate all available features (`--all-features`).
57 cargo_allFeatures: bool = "false", 63 cargo_allFeatures: bool = "false",
64 /// Unsets `#[cfg(test)]` for the specified crates.
65 cargo_unsetTest: Vec<String> = "[\"core\"]",
58 /// List of features to activate. 66 /// List of features to activate.
59 cargo_features: Vec<String> = "[]", 67 cargo_features: Vec<String> = "[]",
60 /// Run build scripts (`build.rs`) for more precise code analysis. 68 /// Run build scripts (`build.rs`) for more precise code analysis.
@@ -144,6 +152,12 @@ config_data! {
144 /// their contents. 152 /// their contents.
145 highlighting_strings: bool = "true", 153 highlighting_strings: bool = "true",
146 154
155 /// Whether to show documentation on hover.
156 hover_documentation: bool = "true",
157 /// Use markdown syntax for links in hover.
158 hover_linksInHover |
159 hoverActions_linksInHover: bool = "true",
160
147 /// Whether to show `Debug` action. Only applies when 161 /// Whether to show `Debug` action. Only applies when
148 /// `#rust-analyzer.hoverActions.enable#` is set. 162 /// `#rust-analyzer.hoverActions.enable#` is set.
149 hoverActions_debug: bool = "true", 163 hoverActions_debug: bool = "true",
@@ -161,8 +175,6 @@ config_data! {
161 /// Whether to show `Run` action. Only applies when 175 /// Whether to show `Run` action. Only applies when
162 /// `#rust-analyzer.hoverActions.enable#` is set. 176 /// `#rust-analyzer.hoverActions.enable#` is set.
163 hoverActions_run: bool = "true", 177 hoverActions_run: bool = "true",
164 /// Use markdown syntax for links in hover.
165 hoverActions_linksInHover: bool = "true",
166 178
167 /// Whether to show inlay type hints for method chains. 179 /// Whether to show inlay type hints for method chains.
168 inlayHints_chainingHints: bool = "true", 180 inlayHints_chainingHints: bool = "true",
@@ -303,6 +315,37 @@ impl LensConfig {
303 } 315 }
304} 316}
305 317
318#[derive(Clone, Debug, PartialEq, Eq)]
319pub struct HoverActionsConfig {
320 pub implementations: bool,
321 pub references: bool,
322 pub run: bool,
323 pub debug: bool,
324 pub goto_type_def: bool,
325}
326
327impl HoverActionsConfig {
328 pub const NO_ACTIONS: Self = Self {
329 implementations: false,
330 references: false,
331 run: false,
332 debug: false,
333 goto_type_def: false,
334 };
335
336 pub fn any(&self) -> bool {
337 self.implementations || self.references || self.runnable() || self.goto_type_def
338 }
339
340 pub fn none(&self) -> bool {
341 !self.any()
342 }
343
344 pub fn runnable(&self) -> bool {
345 self.run || self.debug
346 }
347}
348
306#[derive(Debug, Clone)] 349#[derive(Debug, Clone)]
307pub struct FilesConfig { 350pub struct FilesConfig {
308 pub watcher: FilesWatcher, 351 pub watcher: FilesWatcher,
@@ -521,7 +564,7 @@ impl Config {
521 pub fn code_action_group(&self) -> bool { 564 pub fn code_action_group(&self) -> bool {
522 self.experimental("codeActionGroup") 565 self.experimental("codeActionGroup")
523 } 566 }
524 pub fn hover_actions(&self) -> bool { 567 pub fn experimental_hover_actions(&self) -> bool {
525 self.experimental("hoverActions") 568 self.experimental("hoverActions")
526 } 569 }
527 pub fn server_status_notification(&self) -> bool { 570 pub fn server_status_notification(&self) -> bool {
@@ -595,8 +638,10 @@ impl Config {
595 target: self.data.cargo_target.clone(), 638 target: self.data.cargo_target.clone(),
596 rustc_source, 639 rustc_source,
597 no_sysroot: self.data.cargo_noSysroot, 640 no_sysroot: self.data.cargo_noSysroot,
641 unset_test_crates: self.data.cargo_unsetTest.clone(),
598 } 642 }
599 } 643 }
644
600 pub fn rustfmt(&self) -> RustfmtConfig { 645 pub fn rustfmt(&self) -> RustfmtConfig {
601 match &self.data.rustfmt_overrideCommand { 646 match &self.data.rustfmt_overrideCommand {
602 Some(args) if !args.is_empty() => { 647 Some(args) if !args.is_empty() => {
@@ -719,30 +764,41 @@ impl Config {
719 refs: self.data.lens_enable && self.data.lens_references, 764 refs: self.data.lens_enable && self.data.lens_references,
720 } 765 }
721 } 766 }
722 pub fn highlighting_strings(&self) -> bool { 767 pub fn hover_actions(&self) -> HoverActionsConfig {
723 self.data.highlighting_strings 768 HoverActionsConfig {
724 }
725 pub fn hover(&self) -> HoverConfig {
726 HoverConfig {
727 implementations: self.data.hoverActions_enable 769 implementations: self.data.hoverActions_enable
728 && self.data.hoverActions_implementations, 770 && self.data.hoverActions_implementations,
729 references: self.data.hoverActions_enable && self.data.hoverActions_references, 771 references: self.data.hoverActions_enable && self.data.hoverActions_references,
730 run: self.data.hoverActions_enable && self.data.hoverActions_run, 772 run: self.data.hoverActions_enable && self.data.hoverActions_run,
731 debug: self.data.hoverActions_enable && self.data.hoverActions_debug, 773 debug: self.data.hoverActions_enable && self.data.hoverActions_debug,
732 goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, 774 goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef,
733 links_in_hover: self.data.hoverActions_linksInHover, 775 }
734 markdown: try_or!( 776 }
735 self.caps 777 pub fn highlighting_strings(&self) -> bool {
736 .text_document 778 self.data.highlighting_strings
737 .as_ref()? 779 }
738 .hover 780 pub fn hover(&self) -> HoverConfig {
739 .as_ref()? 781 HoverConfig {
740 .content_format 782 links_in_hover: self.data.hover_linksInHover,
741 .as_ref()? 783 documentation: self.data.hover_documentation.then(|| {
742 .as_slice(), 784 let is_markdown = try_or!(
743 &[] 785 self.caps
744 ) 786 .text_document
745 .contains(&MarkupKind::Markdown), 787 .as_ref()?
788 .hover
789 .as_ref()?
790 .content_format
791 .as_ref()?
792 .as_slice(),
793 &[]
794 )
795 .contains(&MarkupKind::Markdown);
796 if is_markdown {
797 HoverDocFormat::Markdown
798 } else {
799 HoverDocFormat::PlainText
800 }
801 }),
746 } 802 }
747 } 803 }
748 804
@@ -852,6 +908,7 @@ macro_rules! _config_data {
852 $({ 908 $({
853 let field = stringify!($field); 909 let field = stringify!($field);
854 let ty = stringify!($ty); 910 let ty = stringify!($ty);
911
855 (field, ty, &[$($doc),*], $default) 912 (field, ty, &[$($doc),*], $default)
856 },)* 913 },)*
857 ]) 914 ])
@@ -863,6 +920,7 @@ macro_rules! _config_data {
863 $({ 920 $({
864 let field = stringify!($field); 921 let field = stringify!($field);
865 let ty = stringify!($ty); 922 let ty = stringify!($ty);
923
866 (field, ty, &[$($doc),*], $default) 924 (field, ty, &[$($doc),*], $default)
867 },)* 925 },)*
868 ]) 926 ])
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index ccf66294f..dcead5f5c 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -861,12 +861,10 @@ pub(crate) fn handle_hover(
861) -> Result<Option<lsp_ext::Hover>> { 861) -> Result<Option<lsp_ext::Hover>> {
862 let _p = profile::span("handle_hover"); 862 let _p = profile::span("handle_hover");
863 let position = from_proto::file_position(&snap, params.text_document_position_params)?; 863 let position = from_proto::file_position(&snap, params.text_document_position_params)?;
864 let hover_config = snap.config.hover(); 864 let info = match snap.analysis.hover(position, &snap.config.hover())? {
865 let info = 865 None => return Ok(None),
866 match snap.analysis.hover(position, hover_config.links_in_hover, hover_config.markdown)? { 866 Some(info) => info,
867 None => return Ok(None), 867 };
868 Some(info) => info,
869 };
870 let line_index = snap.file_line_index(position.file_id)?; 868 let line_index = snap.file_line_index(position.file_id)?;
871 let range = to_proto::range(&line_index, info.range); 869 let range = to_proto::range(&line_index, info.range);
872 let hover = lsp_ext::Hover { 870 let hover = lsp_ext::Hover {
@@ -1483,7 +1481,7 @@ fn show_impl_command_link(
1483 snap: &GlobalStateSnapshot, 1481 snap: &GlobalStateSnapshot,
1484 position: &FilePosition, 1482 position: &FilePosition,
1485) -> Option<lsp_ext::CommandLinkGroup> { 1483) -> Option<lsp_ext::CommandLinkGroup> {
1486 if snap.config.hover().implementations { 1484 if snap.config.hover_actions().implementations {
1487 if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { 1485 if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
1488 let uri = to_proto::url(snap, position.file_id); 1486 let uri = to_proto::url(snap, position.file_id);
1489 let line_index = snap.file_line_index(position.file_id).ok()?; 1487 let line_index = snap.file_line_index(position.file_id).ok()?;
@@ -1509,7 +1507,7 @@ fn show_ref_command_link(
1509 snap: &GlobalStateSnapshot, 1507 snap: &GlobalStateSnapshot,
1510 position: &FilePosition, 1508 position: &FilePosition,
1511) -> Option<lsp_ext::CommandLinkGroup> { 1509) -> Option<lsp_ext::CommandLinkGroup> {
1512 if snap.config.hover().references { 1510 if snap.config.hover_actions().references {
1513 if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) { 1511 if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) {
1514 let uri = to_proto::url(snap, position.file_id); 1512 let uri = to_proto::url(snap, position.file_id);
1515 let line_index = snap.file_line_index(position.file_id).ok()?; 1513 let line_index = snap.file_line_index(position.file_id).ok()?;
@@ -1540,8 +1538,8 @@ fn runnable_action_links(
1540 runnable: Runnable, 1538 runnable: Runnable,
1541) -> Option<lsp_ext::CommandLinkGroup> { 1539) -> Option<lsp_ext::CommandLinkGroup> {
1542 let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?; 1540 let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
1543 let hover_config = snap.config.hover(); 1541 let hover_actions_config = snap.config.hover_actions();
1544 if !hover_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) { 1542 if !hover_actions_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) {
1545 return None; 1543 return None;
1546 } 1544 }
1547 1545
@@ -1549,12 +1547,12 @@ fn runnable_action_links(
1549 to_proto::runnable(snap, runnable).ok().map(|r| { 1547 to_proto::runnable(snap, runnable).ok().map(|r| {
1550 let mut group = lsp_ext::CommandLinkGroup::default(); 1548 let mut group = lsp_ext::CommandLinkGroup::default();
1551 1549
1552 if hover_config.run { 1550 if hover_actions_config.run {
1553 let run_command = to_proto::command::run_single(&r, action.run_title); 1551 let run_command = to_proto::command::run_single(&r, action.run_title);
1554 group.commands.push(to_command_link(run_command, r.label.clone())); 1552 group.commands.push(to_command_link(run_command, r.label.clone()));
1555 } 1553 }
1556 1554
1557 if hover_config.debug { 1555 if hover_actions_config.debug {
1558 let dbg_command = to_proto::command::debug_single(&r); 1556 let dbg_command = to_proto::command::debug_single(&r);
1559 group.commands.push(to_command_link(dbg_command, r.label)); 1557 group.commands.push(to_command_link(dbg_command, r.label));
1560 } 1558 }
@@ -1567,7 +1565,7 @@ fn goto_type_action_links(
1567 snap: &GlobalStateSnapshot, 1565 snap: &GlobalStateSnapshot,
1568 nav_targets: &[HoverGotoTypeData], 1566 nav_targets: &[HoverGotoTypeData],
1569) -> Option<lsp_ext::CommandLinkGroup> { 1567) -> Option<lsp_ext::CommandLinkGroup> {
1570 if !snap.config.hover().goto_type_def || nav_targets.is_empty() { 1568 if !snap.config.hover_actions().goto_type_def || nav_targets.is_empty() {
1571 return None; 1569 return None;
1572 } 1570 }
1573 1571
@@ -1587,7 +1585,7 @@ fn prepare_hover_actions(
1587 snap: &GlobalStateSnapshot, 1585 snap: &GlobalStateSnapshot,
1588 actions: &[HoverAction], 1586 actions: &[HoverAction],
1589) -> Vec<lsp_ext::CommandLinkGroup> { 1587) -> Vec<lsp_ext::CommandLinkGroup> {
1590 if snap.config.hover().none() || !snap.config.hover_actions() { 1588 if snap.config.hover_actions().none() || !snap.config.experimental_hover_actions() {
1591 return Vec::new(); 1589 return Vec::new();
1592 } 1590 }
1593 1591
diff --git a/crates/syntax/src/ptr.rs b/crates/syntax/src/ptr.rs
index 195d2251b..32aa69979 100644
--- a/crates/syntax/src/ptr.rs
+++ b/crates/syntax/src/ptr.rs
@@ -35,7 +35,7 @@ impl SyntaxNodePtr {
35 pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode { 35 pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode {
36 assert!(root.parent().is_none()); 36 assert!(root.parent().is_none());
37 successors(Some(root.clone()), |node| { 37 successors(Some(root.clone()), |node| {
38 node.children().find(|it| it.text_range().contains_range(self.range)) 38 node.child_or_token_at_range(self.range).and_then(|it| it.into_node())
39 }) 39 })
40 .find(|it| it.text_range() == self.range && it.kind() == self.kind) 40 .find(|it| it.text_range() == self.range && it.kind() == self.kind)
41 .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self)) 41 .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index d55bae62a..d9c22c180 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -11,6 +11,7 @@ mod fixture;
11mod assert_linear; 11mod assert_linear;
12 12
13use std::{ 13use std::{
14 collections::BTreeMap,
14 convert::{TryFrom, TryInto}, 15 convert::{TryFrom, TryInto},
15 env, fs, 16 env, fs,
16 path::{Path, PathBuf}, 17 path::{Path, PathBuf},
@@ -205,14 +206,25 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
205/// 206///
206/// // ^^^ first line 207/// // ^^^ first line
207/// // | second line 208/// // | second line
209///
210/// Annotations point to the last line that actually was long enough for the
211/// range, not counting annotations themselves. So overlapping annotations are
212/// possible:
213/// ```no_run
214/// // stuff other stuff
215/// // ^^ 'st'
216/// // ^^^^^ 'stuff'
217/// // ^^^^^^^^^^^ 'other stuff'
218/// ```
208pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { 219pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
209 let mut res = Vec::new(); 220 let mut res = Vec::new();
210 let mut prev_line_start: Option<TextSize> = Some(0.into()); 221 // map from line length to beginning of last line that had that length
222 let mut line_start_map = BTreeMap::new();
211 let mut line_start: TextSize = 0.into(); 223 let mut line_start: TextSize = 0.into();
212 let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); 224 let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new();
213 for line in text.split_inclusive('\n') { 225 for line in text.split_inclusive('\n') {
214 let mut this_line_annotations = Vec::new(); 226 let mut this_line_annotations = Vec::new();
215 if let Some(idx) = line.find("//") { 227 let line_length = if let Some(idx) = line.find("//") {
216 let annotation_offset = TextSize::of(&line[..idx + "//".len()]); 228 let annotation_offset = TextSize::of(&line[..idx + "//".len()]);
217 for annotation in extract_line_annotations(&line[idx + "//".len()..]) { 229 for annotation in extract_line_annotations(&line[idx + "//".len()..]) {
218 match annotation { 230 match annotation {
@@ -222,7 +234,9 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
222 let range = if file { 234 let range = if file {
223 TextRange::up_to(TextSize::of(text)) 235 TextRange::up_to(TextSize::of(text))
224 } else { 236 } else {
225 range + prev_line_start.unwrap() 237 let line_start = line_start_map.range(range.end()..).next().unwrap();
238
239 range + line_start.1
226 }; 240 };
227 res.push((range, content)) 241 res.push((range, content))
228 } 242 }
@@ -238,9 +252,14 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
238 } 252 }
239 } 253 }
240 } 254 }
241 } 255 idx.try_into().unwrap()
256 } else {
257 TextSize::of(line)
258 };
259
260 line_start_map = line_start_map.split_off(&line_length);
261 line_start_map.insert(line_length, line_start);
242 262
243 prev_line_start = Some(line_start);
244 line_start += TextSize::of(line); 263 line_start += TextSize::of(line);
245 264
246 prev_line_annotations = this_line_annotations; 265 prev_line_annotations = this_line_annotations;
@@ -296,7 +315,7 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
296} 315}
297 316
298#[test] 317#[test]
299fn test_extract_annotations() { 318fn test_extract_annotations_1() {
300 let text = stdx::trim_indent( 319 let text = stdx::trim_indent(
301 r#" 320 r#"
302fn main() { 321fn main() {
@@ -321,6 +340,25 @@ fn main() {
321 assert_eq!(res[3].0.len(), 115); 340 assert_eq!(res[3].0.len(), 115);
322} 341}
323 342
343#[test]
344fn test_extract_annotations_2() {
345 let text = stdx::trim_indent(
346 r#"
347fn main() {
348 (x, y);
349 //^ a
350 // ^ b
351 //^^^^^^^^ c
352}"#,
353 );
354 let res = extract_annotations(&text)
355 .into_iter()
356 .map(|(range, ann)| (&text[range], ann))
357 .collect::<Vec<_>>();
358
359 assert_eq!(res, [("x", "a".into()), ("y", "b".into()), ("(x, y)", "c".into())]);
360}
361
324/// Returns `false` if slow tests should not run, otherwise returns `true` and 362/// Returns `false` if slow tests should not run, otherwise returns `true` and
325/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag 363/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag
326/// that slow tests did run. 364/// that slow tests did run.