diff options
57 files changed, 694 insertions, 430 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7549e998b..ae9dccce9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -108,9 +108,6 @@ jobs: | |||
108 | with: | 108 | with: |
109 | node-version: 12.x | 109 | node-version: 12.x |
110 | 110 | ||
111 | - name: Print current revision | ||
112 | run: git describe --tags | ||
113 | |||
114 | - name: Dist | 111 | - name: Dist |
115 | if: github.ref == 'refs/heads/release' | 112 | if: github.ref == 'refs/heads/release' |
116 | run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER | 113 | run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER |
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index d0def2181..e9e8dfc2e 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -410,7 +410,7 @@ impl CrateId { | |||
410 | 410 | ||
411 | impl CrateData { | 411 | impl CrateData { |
412 | fn add_dep(&mut self, name: CrateName, crate_id: CrateId) { | 412 | fn add_dep(&mut self, name: CrateName, crate_id: CrateId) { |
413 | self.dependencies.push(Dependency { name, crate_id }) | 413 | self.dependencies.push(Dependency { crate_id, name }) |
414 | } | 414 | } |
415 | } | 415 | } |
416 | 416 | ||
diff --git a/crates/cfg/src/dnf.rs b/crates/cfg/src/dnf.rs index 30f4bcdf7..75ded9aa1 100644 --- a/crates/cfg/src/dnf.rs +++ b/crates/cfg/src/dnf.rs | |||
@@ -255,9 +255,9 @@ impl Builder { | |||
255 | fn make_dnf(expr: CfgExpr) -> CfgExpr { | 255 | fn make_dnf(expr: CfgExpr) -> CfgExpr { |
256 | match expr { | 256 | match expr { |
257 | CfgExpr::Invalid | CfgExpr::Atom(_) | CfgExpr::Not(_) => expr, | 257 | CfgExpr::Invalid | CfgExpr::Atom(_) | CfgExpr::Not(_) => expr, |
258 | CfgExpr::Any(e) => CfgExpr::Any(e.into_iter().map(|expr| make_dnf(expr)).collect()), | 258 | CfgExpr::Any(e) => CfgExpr::Any(e.into_iter().map(make_dnf).collect()), |
259 | CfgExpr::All(e) => { | 259 | CfgExpr::All(e) => { |
260 | let e = e.into_iter().map(|expr| make_nnf(expr)).collect::<Vec<_>>(); | 260 | let e = e.into_iter().map(make_nnf).collect::<Vec<_>>(); |
261 | 261 | ||
262 | CfgExpr::Any(distribute_conj(&e)) | 262 | CfgExpr::Any(distribute_conj(&e)) |
263 | } | 263 | } |
@@ -300,8 +300,8 @@ fn distribute_conj(conj: &[CfgExpr]) -> Vec<CfgExpr> { | |||
300 | fn make_nnf(expr: CfgExpr) -> CfgExpr { | 300 | fn make_nnf(expr: CfgExpr) -> CfgExpr { |
301 | match expr { | 301 | match expr { |
302 | CfgExpr::Invalid | CfgExpr::Atom(_) => expr, | 302 | CfgExpr::Invalid | CfgExpr::Atom(_) => expr, |
303 | CfgExpr::Any(expr) => CfgExpr::Any(expr.into_iter().map(|expr| make_nnf(expr)).collect()), | 303 | CfgExpr::Any(expr) => CfgExpr::Any(expr.into_iter().map(make_nnf).collect()), |
304 | CfgExpr::All(expr) => CfgExpr::All(expr.into_iter().map(|expr| make_nnf(expr)).collect()), | 304 | CfgExpr::All(expr) => CfgExpr::All(expr.into_iter().map(make_nnf).collect()), |
305 | CfgExpr::Not(operand) => match *operand { | 305 | CfgExpr::Not(operand) => match *operand { |
306 | CfgExpr::Invalid | CfgExpr::Atom(_) => CfgExpr::Not(operand.clone()), // Original negated expr | 306 | CfgExpr::Invalid | CfgExpr::Atom(_) => CfgExpr::Not(operand.clone()), // Original negated expr |
307 | CfgExpr::Not(expr) => { | 307 | CfgExpr::Not(expr) => { |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index e34be7e42..e3ac37e4c 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -213,7 +213,7 @@ impl Crate { | |||
213 | Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text), | 213 | Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text), |
214 | _ => None | 214 | _ => None |
215 | } | 215 | } |
216 | }).flat_map(|t| t).next(); | 216 | }).flatten().next(); |
217 | 217 | ||
218 | doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") | 218 | doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") |
219 | } | 219 | } |
@@ -2068,7 +2068,10 @@ impl Type { | |||
2068 | match pred { | 2068 | match pred { |
2069 | WhereClause::Implemented(trait_ref) => { | 2069 | WhereClause::Implemented(trait_ref) => { |
2070 | cb(type_.clone()); | 2070 | cb(type_.clone()); |
2071 | walk_substs(db, type_, &trait_ref.substitution, cb); | 2071 | // skip the self type. it's likely the type we just got the bounds from |
2072 | for ty in trait_ref.substitution.iter().skip(1) { | ||
2073 | walk_type(db, &type_.derived(ty.clone()), cb); | ||
2074 | } | ||
2072 | } | 2075 | } |
2073 | _ => (), | 2076 | _ => (), |
2074 | } | 2077 | } |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 2c10f46d8..52a2bce9b 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -638,7 +638,7 @@ fn collect_attrs( | |||
638 | owner: &dyn ast::AttrsOwner, | 638 | owner: &dyn ast::AttrsOwner, |
639 | ) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> { | 639 | ) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> { |
640 | let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) | 640 | let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) |
641 | .map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs)))); | 641 | .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs))); |
642 | 642 | ||
643 | let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); | 643 | let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); |
644 | let attrs = outer_attrs | 644 | let attrs = outer_attrs |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 46a3c60cd..28b73c3a1 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -1467,12 +1467,13 @@ impl ModCollector<'_, '_> { | |||
1467 | }, | 1467 | }, |
1468 | ) { | 1468 | ) { |
1469 | Ok(Ok(macro_call_id)) => { | 1469 | Ok(Ok(macro_call_id)) => { |
1470 | self.def_collector.unexpanded_macros.push(MacroDirective { | 1470 | // Legacy macros need to be expanded immediately, so that any macros they produce |
1471 | module_id: self.module_id, | 1471 | // are in scope. |
1472 | ast_id, | 1472 | self.def_collector.collect_macro_expansion( |
1473 | legacy: Some(macro_call_id), | 1473 | self.module_id, |
1474 | depth: self.macro_depth + 1, | 1474 | macro_call_id, |
1475 | }); | 1475 | self.macro_depth + 1, |
1476 | ); | ||
1476 | 1477 | ||
1477 | return; | 1478 | return; |
1478 | } | 1479 | } |
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index d59d3c0db..6d3cb8d7a 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -713,6 +713,27 @@ b! { static = #[] ();} | |||
713 | } | 713 | } |
714 | 714 | ||
715 | #[test] | 715 | #[test] |
716 | fn macros_defining_macros() { | ||
717 | check( | ||
718 | r#" | ||
719 | macro_rules! item { | ||
720 | ($item:item) => { $item } | ||
721 | } | ||
722 | |||
723 | item! { | ||
724 | macro_rules! indirect_macro { () => { struct S {} } } | ||
725 | } | ||
726 | |||
727 | indirect_macro!(); | ||
728 | "#, | ||
729 | expect![[r#" | ||
730 | crate | ||
731 | S: t | ||
732 | "#]], | ||
733 | ); | ||
734 | } | ||
735 | |||
736 | #[test] | ||
716 | fn resolves_proc_macros() { | 737 | fn resolves_proc_macros() { |
717 | check( | 738 | check( |
718 | r" | 739 | r" |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index 4a2d1c087..04ea9c5d7 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -472,7 +472,7 @@ impl Scope { | |||
472 | } | 472 | } |
473 | Scope::ExprScope(scope) => { | 473 | Scope::ExprScope(scope) => { |
474 | if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { | 474 | if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { |
475 | f(name.clone(), ScopeDef::Label(label)) | 475 | f(name, ScopeDef::Label(label)) |
476 | } | 476 | } |
477 | scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { | 477 | scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { |
478 | f(e.name().clone(), ScopeDef::Local(e.pat())); | 478 | f(e.name().clone(), ScopeDef::Local(e.pat())); |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 2748e25cf..fc73e435b 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -173,7 +173,7 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { | |||
173 | }; | 173 | }; |
174 | let loc = db.lookup_intern_macro(id); | 174 | let loc = db.lookup_intern_macro(id); |
175 | let arg = loc.kind.arg(db)?; | 175 | let arg = loc.kind.arg(db)?; |
176 | Some(arg.green().to_owned()) | 176 | Some(arg.green()) |
177 | } | 177 | } |
178 | 178 | ||
179 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { | 179 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { |
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index 43de9edd6..0aeea48d5 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -48,9 +48,8 @@ impl Name { | |||
48 | 48 | ||
49 | /// Resolve a name from the text of token. | 49 | /// Resolve a name from the text of token. |
50 | fn resolve(raw_text: &str) -> Name { | 50 | fn resolve(raw_text: &str) -> Name { |
51 | let raw_start = "r#"; | 51 | if let Some(text) = raw_text.strip_prefix("r#") { |
52 | if raw_text.starts_with(raw_start) { | 52 | Name::new_text(SmolStr::new(text)) |
53 | Name::new_text(SmolStr::new(&raw_text[raw_start.len()..])) | ||
54 | } else { | 53 | } else { |
55 | Name::new_text(raw_text.into()) | 54 | Name::new_text(raw_text.into()) |
56 | } | 55 | } |
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 3845009ae..9d3b79be3 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -571,13 +571,22 @@ impl HirDisplay for Ty { | |||
571 | write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? | 571 | write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? |
572 | } | 572 | } |
573 | TypeParamProvenance::ArgumentImplTrait => { | 573 | TypeParamProvenance::ArgumentImplTrait => { |
574 | let bounds = f.db.generic_predicates_for_param(id); | ||
575 | let substs = Substitution::type_params_for_generics(f.db, &generics); | 574 | let substs = Substitution::type_params_for_generics(f.db, &generics); |
576 | write_bounds_like_dyn_trait_with_prefix( | 575 | let bounds = f |
577 | "impl", | 576 | .db |
578 | &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(), | 577 | .generic_predicates(id.parent) |
579 | f, | 578 | .into_iter() |
580 | )?; | 579 | .map(|pred| pred.clone().subst(&substs)) |
580 | .filter(|wc| match &wc { | ||
581 | WhereClause::Implemented(tr) => tr.self_type_parameter() == self, | ||
582 | WhereClause::AliasEq(AliasEq { | ||
583 | alias: AliasTy::Projection(proj), | ||
584 | ty: _, | ||
585 | }) => proj.self_type_parameter() == self, | ||
586 | _ => false, | ||
587 | }) | ||
588 | .collect::<Vec<_>>(); | ||
589 | write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?; | ||
581 | } | 590 | } |
582 | } | 591 | } |
583 | } | 592 | } |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index befa0d69b..ec491648f 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -38,7 +38,7 @@ impl<'a> InferenceContext<'a> { | |||
38 | let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); | 38 | let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); |
39 | let (pre, post) = match ellipsis { | 39 | let (pre, post) = match ellipsis { |
40 | Some(idx) => subpats.split_at(idx), | 40 | Some(idx) => subpats.split_at(idx), |
41 | None => (&subpats[..], &[][..]), | 41 | None => (subpats, &[][..]), |
42 | }; | 42 | }; |
43 | let post_idx_offset = field_tys.iter().count() - post.len(); | 43 | let post_idx_offset = field_tys.iter().count() - post.len(); |
44 | 44 | ||
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index c46529879..ad908f957 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -106,6 +106,10 @@ impl ProjectionTy { | |||
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | pub fn self_type_parameter(&self) -> &Ty { | ||
110 | &self.substitution[0] | ||
111 | } | ||
112 | |||
109 | fn trait_(&self, db: &dyn HirDatabase) -> TraitId { | 113 | fn trait_(&self, db: &dyn HirDatabase) -> TraitId { |
110 | match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container { | 114 | match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container { |
111 | AssocContainerId::TraitId(it) => it, | 115 | AssocContainerId::TraitId(it) => it, |
@@ -936,10 +940,19 @@ impl Ty { | |||
936 | let param_data = &generic_params.types[id.local_id]; | 940 | let param_data = &generic_params.types[id.local_id]; |
937 | match param_data.provenance { | 941 | match param_data.provenance { |
938 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { | 942 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { |
943 | let substs = Substitution::type_params(db, id.parent); | ||
939 | let predicates = db | 944 | let predicates = db |
940 | .generic_predicates_for_param(id) | 945 | .generic_predicates(id.parent) |
941 | .into_iter() | 946 | .into_iter() |
942 | .map(|pred| pred.value.clone()) | 947 | .map(|pred| pred.clone().subst(&substs)) |
948 | .filter(|wc| match &wc { | ||
949 | WhereClause::Implemented(tr) => tr.self_type_parameter() == self, | ||
950 | WhereClause::AliasEq(AliasEq { | ||
951 | alias: AliasTy::Projection(proj), | ||
952 | ty: _, | ||
953 | }) => proj.self_type_parameter() == self, | ||
954 | _ => false, | ||
955 | }) | ||
943 | .collect_vec(); | 956 | .collect_vec(); |
944 | 957 | ||
945 | Some(predicates) | 958 | Some(predicates) |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index cbbb535e5..fd451a823 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -189,7 +189,10 @@ impl<'a> TyLoweringContext<'a> { | |||
189 | let self_ty = | 189 | let self_ty = |
190 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); | 190 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); |
191 | let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { | 191 | let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { |
192 | bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone())).collect() | 192 | bounds |
193 | .iter() | ||
194 | .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)) | ||
195 | .collect() | ||
193 | }); | 196 | }); |
194 | TyKind::Dyn(predicates).intern(&Interner) | 197 | TyKind::Dyn(predicates).intern(&Interner) |
195 | } | 198 | } |
@@ -666,6 +669,7 @@ impl<'a> TyLoweringContext<'a> { | |||
666 | pub(crate) fn lower_where_predicate( | 669 | pub(crate) fn lower_where_predicate( |
667 | &'a self, | 670 | &'a self, |
668 | where_predicate: &'a WherePredicate, | 671 | where_predicate: &'a WherePredicate, |
672 | ignore_bindings: bool, | ||
669 | ) -> impl Iterator<Item = WhereClause> + 'a { | 673 | ) -> impl Iterator<Item = WhereClause> + 'a { |
670 | match where_predicate { | 674 | match where_predicate { |
671 | WherePredicate::ForLifetime { target, bound, .. } | 675 | WherePredicate::ForLifetime { target, bound, .. } |
@@ -688,7 +692,9 @@ impl<'a> TyLoweringContext<'a> { | |||
688 | .intern(&Interner) | 692 | .intern(&Interner) |
689 | } | 693 | } |
690 | }; | 694 | }; |
691 | self.lower_type_bound(bound, self_ty).collect::<Vec<_>>().into_iter() | 695 | self.lower_type_bound(bound, self_ty, ignore_bindings) |
696 | .collect::<Vec<_>>() | ||
697 | .into_iter() | ||
692 | } | 698 | } |
693 | WherePredicate::Lifetime { .. } => vec![].into_iter(), | 699 | WherePredicate::Lifetime { .. } => vec![].into_iter(), |
694 | } | 700 | } |
@@ -698,6 +704,7 @@ impl<'a> TyLoweringContext<'a> { | |||
698 | &'a self, | 704 | &'a self, |
699 | bound: &'a TypeBound, | 705 | bound: &'a TypeBound, |
700 | self_ty: Ty, | 706 | self_ty: Ty, |
707 | ignore_bindings: bool, | ||
701 | ) -> impl Iterator<Item = WhereClause> + 'a { | 708 | ) -> impl Iterator<Item = WhereClause> + 'a { |
702 | let mut bindings = None; | 709 | let mut bindings = None; |
703 | let trait_ref = match bound { | 710 | let trait_ref = match bound { |
@@ -711,6 +718,7 @@ impl<'a> TyLoweringContext<'a> { | |||
711 | trait_ref.into_iter().chain( | 718 | trait_ref.into_iter().chain( |
712 | bindings | 719 | bindings |
713 | .into_iter() | 720 | .into_iter() |
721 | .filter(move |_| !ignore_bindings) | ||
714 | .flat_map(move |tr| self.assoc_type_bindings_from_type_bound(bound, tr)), | 722 | .flat_map(move |tr| self.assoc_type_bindings_from_type_bound(bound, tr)), |
715 | ) | 723 | ) |
716 | } | 724 | } |
@@ -755,6 +763,7 @@ impl<'a> TyLoweringContext<'a> { | |||
755 | preds.extend(self.lower_type_bound( | 763 | preds.extend(self.lower_type_bound( |
756 | bound, | 764 | bound, |
757 | TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(&Interner), | 765 | TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(&Interner), |
766 | false, | ||
758 | )); | 767 | )); |
759 | } | 768 | } |
760 | preds | 769 | preds |
@@ -766,7 +775,7 @@ impl<'a> TyLoweringContext<'a> { | |||
766 | let self_ty = | 775 | let self_ty = |
767 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); | 776 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); |
768 | let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { | 777 | let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { |
769 | bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone())).collect() | 778 | bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)).collect() |
770 | }); | 779 | }); |
771 | ReturnTypeImplTrait { bounds: Binders::new(1, predicates) } | 780 | ReturnTypeImplTrait { bounds: Binders::new(1, predicates) } |
772 | } | 781 | } |
@@ -896,7 +905,9 @@ pub(crate) fn generic_predicates_for_param_query( | |||
896 | }, | 905 | }, |
897 | WherePredicate::Lifetime { .. } => false, | 906 | WherePredicate::Lifetime { .. } => false, |
898 | }) | 907 | }) |
899 | .flat_map(|pred| ctx.lower_where_predicate(pred).map(|p| Binders::new(generics.len(), p))) | 908 | .flat_map(|pred| { |
909 | ctx.lower_where_predicate(pred, true).map(|p| Binders::new(generics.len(), p)) | ||
910 | }) | ||
900 | .collect() | 911 | .collect() |
901 | } | 912 | } |
902 | 913 | ||
@@ -918,7 +929,7 @@ pub(crate) fn trait_environment_query( | |||
918 | let mut traits_in_scope = Vec::new(); | 929 | let mut traits_in_scope = Vec::new(); |
919 | let mut clauses = Vec::new(); | 930 | let mut clauses = Vec::new(); |
920 | for pred in resolver.where_predicates_in_scope() { | 931 | for pred in resolver.where_predicates_in_scope() { |
921 | for pred in ctx.lower_where_predicate(pred) { | 932 | for pred in ctx.lower_where_predicate(pred, false) { |
922 | if let WhereClause::Implemented(tr) = &pred { | 933 | if let WhereClause::Implemented(tr) = &pred { |
923 | traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id())); | 934 | traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id())); |
924 | } | 935 | } |
@@ -946,8 +957,7 @@ pub(crate) fn trait_environment_query( | |||
946 | let substs = Substitution::type_params(db, trait_id); | 957 | let substs = Substitution::type_params(db, trait_id); |
947 | let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; | 958 | let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; |
948 | let pred = WhereClause::Implemented(trait_ref); | 959 | let pred = WhereClause::Implemented(trait_ref); |
949 | let program_clause: chalk_ir::ProgramClause<Interner> = | 960 | let program_clause: chalk_ir::ProgramClause<Interner> = pred.to_chalk(db).cast(&Interner); |
950 | pred.clone().to_chalk(db).cast(&Interner); | ||
951 | clauses.push(program_clause.into_from_env_clause(&Interner)); | 961 | clauses.push(program_clause.into_from_env_clause(&Interner)); |
952 | } | 962 | } |
953 | 963 | ||
@@ -967,7 +977,9 @@ pub(crate) fn generic_predicates_query( | |||
967 | let generics = generics(db.upcast(), def); | 977 | let generics = generics(db.upcast(), def); |
968 | resolver | 978 | resolver |
969 | .where_predicates_in_scope() | 979 | .where_predicates_in_scope() |
970 | .flat_map(|pred| ctx.lower_where_predicate(pred).map(|p| Binders::new(generics.len(), p))) | 980 | .flat_map(|pred| { |
981 | ctx.lower_where_predicate(pred, false).map(|p| Binders::new(generics.len(), p)) | ||
982 | }) | ||
971 | .collect() | 983 | .collect() |
972 | } | 984 | } |
973 | 985 | ||
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index 0a4141e69..ad283c1e0 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -369,3 +369,72 @@ fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) { | |||
369 | actual.push('\n'); | 369 | actual.push('\n'); |
370 | expect.assert_eq(&actual); | 370 | expect.assert_eq(&actual); |
371 | } | 371 | } |
372 | |||
373 | #[test] | ||
374 | fn salsa_bug() { | ||
375 | let (mut db, pos) = TestDB::with_position( | ||
376 | " | ||
377 | //- /lib.rs | ||
378 | trait Index { | ||
379 | type Output; | ||
380 | } | ||
381 | |||
382 | type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key; | ||
383 | |||
384 | pub trait UnificationStoreBase: Index<Output = Key<Self>> { | ||
385 | type Key; | ||
386 | |||
387 | fn len(&self) -> usize; | ||
388 | } | ||
389 | |||
390 | pub trait UnificationStoreMut: UnificationStoreBase { | ||
391 | fn push(&mut self, value: Self::Key); | ||
392 | } | ||
393 | |||
394 | fn main() { | ||
395 | let x = 1; | ||
396 | x.push(1);$0 | ||
397 | } | ||
398 | ", | ||
399 | ); | ||
400 | |||
401 | let module = db.module_for_file(pos.file_id); | ||
402 | let crate_def_map = module.def_map(&db); | ||
403 | visit_module(&db, &crate_def_map, module.local_id, &mut |def| { | ||
404 | db.infer(def); | ||
405 | }); | ||
406 | |||
407 | let new_text = " | ||
408 | //- /lib.rs | ||
409 | trait Index { | ||
410 | type Output; | ||
411 | } | ||
412 | |||
413 | type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key; | ||
414 | |||
415 | pub trait UnificationStoreBase: Index<Output = Key<Self>> { | ||
416 | type Key; | ||
417 | |||
418 | fn len(&self) -> usize; | ||
419 | } | ||
420 | |||
421 | pub trait UnificationStoreMut: UnificationStoreBase { | ||
422 | fn push(&mut self, value: Self::Key); | ||
423 | } | ||
424 | |||
425 | fn main() { | ||
426 | |||
427 | let x = 1; | ||
428 | x.push(1); | ||
429 | } | ||
430 | " | ||
431 | .to_string(); | ||
432 | |||
433 | db.set_file_text(pos.file_id, Arc::new(new_text)); | ||
434 | |||
435 | let module = db.module_for_file(pos.file_id); | ||
436 | let crate_def_map = module.def_map(&db); | ||
437 | visit_module(&db, &crate_def_map, module.local_id, &mut |def| { | ||
438 | db.infer(def); | ||
439 | }); | ||
440 | } | ||
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 8f2bdffc0..37cd04c6f 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -2272,6 +2272,56 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | |||
2272 | } | 2272 | } |
2273 | 2273 | ||
2274 | #[test] | 2274 | #[test] |
2275 | fn unselected_projection_in_trait_env_cycle_3() { | ||
2276 | // this is a cycle for rustc; we currently accept it | ||
2277 | check_types( | ||
2278 | r#" | ||
2279 | //- /main.rs | ||
2280 | trait Trait { | ||
2281 | type Item; | ||
2282 | type OtherItem; | ||
2283 | } | ||
2284 | |||
2285 | fn test<T>() where T: Trait<OtherItem = T::Item> { | ||
2286 | let x: T::Item = no_matter; | ||
2287 | } //^ Trait::Item<T> | ||
2288 | "#, | ||
2289 | ); | ||
2290 | } | ||
2291 | |||
2292 | #[test] | ||
2293 | fn unselected_projection_in_trait_env_no_cycle() { | ||
2294 | // this is not a cycle | ||
2295 | check_types( | ||
2296 | r#" | ||
2297 | //- /main.rs | ||
2298 | trait Index { | ||
2299 | type Output; | ||
2300 | } | ||
2301 | |||
2302 | type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key; | ||
2303 | |||
2304 | pub trait UnificationStoreBase: Index<Output = Key<Self>> { | ||
2305 | type Key; | ||
2306 | |||
2307 | fn len(&self) -> usize; | ||
2308 | } | ||
2309 | |||
2310 | pub trait UnificationStoreMut: UnificationStoreBase { | ||
2311 | fn push(&mut self, value: Self::Key); | ||
2312 | } | ||
2313 | |||
2314 | fn test<T>(t: T) where T: UnificationStoreMut { | ||
2315 | let x; | ||
2316 | t.push(x); | ||
2317 | let y: Key<T>; | ||
2318 | (x, y); | ||
2319 | } //^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>) | ||
2320 | "#, | ||
2321 | ); | ||
2322 | } | ||
2323 | |||
2324 | #[test] | ||
2275 | fn inline_assoc_type_bounds_1() { | 2325 | fn inline_assoc_type_bounds_1() { |
2276 | check_types( | 2326 | check_types( |
2277 | r#" | 2327 | r#" |
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs index 734679414..944145603 100644 --- a/crates/hir_ty/src/traits/chalk.rs +++ b/crates/hir_ty/src/traits/chalk.rs | |||
@@ -395,7 +395,7 @@ pub(crate) fn associated_ty_data_query( | |||
395 | let bounds = type_alias_data | 395 | let bounds = type_alias_data |
396 | .bounds | 396 | .bounds |
397 | .iter() | 397 | .iter() |
398 | .flat_map(|bound| ctx.lower_type_bound(bound, self_ty.clone())) | 398 | .flat_map(|bound| ctx.lower_type_bound(bound, self_ty.clone(), false)) |
399 | .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) | 399 | .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) |
400 | .map(|bound| make_binders(bound.shifted_in(&Interner), 0)) | 400 | .map(|bound| make_binders(bound.shifted_in(&Interner), 0)) |
401 | .collect(); | 401 | .collect(); |
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index e187243cb..5201ce587 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs | |||
@@ -263,11 +263,10 @@ fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> { | |||
263 | ) -> Option<SyntaxToken> { | 263 | ) -> Option<SyntaxToken> { |
264 | node.siblings_with_tokens(dir) | 264 | node.siblings_with_tokens(dir) |
265 | .skip(1) | 265 | .skip(1) |
266 | .skip_while(|node| match node { | 266 | .find(|node| match node { |
267 | NodeOrToken::Node(_) => false, | 267 | NodeOrToken::Node(_) => true, |
268 | NodeOrToken::Token(it) => is_single_line_ws(it), | 268 | NodeOrToken::Token(it) => !is_single_line_ws(it), |
269 | }) | 269 | }) |
270 | .next() | ||
271 | .and_then(|it| it.into_token()) | 270 | .and_then(|it| it.into_token()) |
272 | .filter(|node| node.kind() == delimiter_kind) | 271 | .filter(|node| node.kind() == delimiter_kind) |
273 | } | 272 | } |
diff --git a/crates/ide_assists/src/handlers/convert_comment_block.rs b/crates/ide_assists/src/handlers/convert_comment_block.rs index cdc45fc42..9dc3ee28f 100644 --- a/crates/ide_assists/src/handlers/convert_comment_block.rs +++ b/crates/ide_assists/src/handlers/convert_comment_block.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | use itertools::Itertools; | 1 | use itertools::Itertools; |
2 | use std::convert::identity; | ||
3 | use syntax::{ | 2 | use syntax::{ |
4 | ast::{ | 3 | ast::{ |
5 | self, | 4 | self, |
@@ -140,7 +139,7 @@ fn relevant_line_comments(comment: &ast::Comment) -> Vec<Comment> { | |||
140 | .filter(|s| !skippable(s)) | 139 | .filter(|s| !skippable(s)) |
141 | .map(|not| not.into_token().and_then(Comment::cast).filter(same_prefix)) | 140 | .map(|not| not.into_token().and_then(Comment::cast).filter(same_prefix)) |
142 | .take_while(|opt_com| opt_com.is_some()) | 141 | .take_while(|opt_com| opt_com.is_some()) |
143 | .filter_map(identity) | 142 | .flatten() |
144 | .skip(1); // skip the first element so we don't duplicate it in next_comments | 143 | .skip(1); // skip the first element so we don't duplicate it in next_comments |
145 | 144 | ||
146 | let next_comments = comment | 145 | let next_comments = comment |
@@ -149,7 +148,7 @@ fn relevant_line_comments(comment: &ast::Comment) -> Vec<Comment> { | |||
149 | .filter(|s| !skippable(s)) | 148 | .filter(|s| !skippable(s)) |
150 | .map(|not| not.into_token().and_then(Comment::cast).filter(same_prefix)) | 149 | .map(|not| not.into_token().and_then(Comment::cast).filter(same_prefix)) |
151 | .take_while(|opt_com| opt_com.is_some()) | 150 | .take_while(|opt_com| opt_com.is_some()) |
152 | .filter_map(identity); | 151 | .flatten(); |
153 | 152 | ||
154 | let mut comments: Vec<_> = prev_comments.collect(); | 153 | let mut comments: Vec<_> = prev_comments.collect(); |
155 | comments.reverse(); | 154 | comments.reverse(); |
diff --git a/crates/ide_assists/src/handlers/expand_glob_import.rs b/crates/ide_assists/src/handlers/expand_glob_import.rs index 83aa11d52..98389e4f7 100644 --- a/crates/ide_assists/src/handlers/expand_glob_import.rs +++ b/crates/ide_assists/src/handlers/expand_glob_import.rs | |||
@@ -136,18 +136,13 @@ impl Refs { | |||
136 | .into_iter() | 136 | .into_iter() |
137 | .filter(|r| { | 137 | .filter(|r| { |
138 | if let Def::ModuleDef(ModuleDef::Trait(tr)) = r.def { | 138 | if let Def::ModuleDef(ModuleDef::Trait(tr)) = r.def { |
139 | if tr | 139 | if tr.items(ctx.db()).into_iter().any(|ai| { |
140 | .items(ctx.db()) | 140 | if let AssocItem::Function(f) = ai { |
141 | .into_iter() | 141 | Def::ModuleDef(ModuleDef::Function(f)).is_referenced_in(ctx) |
142 | .find(|ai| { | 142 | } else { |
143 | if let AssocItem::Function(f) = *ai { | 143 | false |
144 | Def::ModuleDef(ModuleDef::Function(f)).is_referenced_in(ctx) | 144 | } |
145 | } else { | 145 | }) { |
146 | false | ||
147 | } | ||
148 | }) | ||
149 | .is_some() | ||
150 | { | ||
151 | return true; | 146 | return true; |
152 | } | 147 | } |
153 | } | 148 | } |
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs index e7444f7db..f91770a76 100644 --- a/crates/ide_assists/src/handlers/qualify_path.rs +++ b/crates/ide_assists/src/handlers/qualify_path.rs | |||
@@ -536,6 +536,7 @@ fn main() { | |||
536 | } | 536 | } |
537 | 537 | ||
538 | #[test] | 538 | #[test] |
539 | #[ignore = "FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details"] | ||
539 | fn associated_struct_const_unqualified() { | 540 | fn associated_struct_const_unqualified() { |
540 | check_assist( | 541 | check_assist( |
541 | qualify_path, | 542 | qualify_path, |
diff --git a/crates/ide_assists/src/handlers/reorder_impl.rs b/crates/ide_assists/src/handlers/reorder_impl.rs index edf4b0bfe..f976e73ad 100644 --- a/crates/ide_assists/src/handlers/reorder_impl.rs +++ b/crates/ide_assists/src/handlers/reorder_impl.rs | |||
@@ -95,7 +95,7 @@ fn compute_method_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashM | |||
95 | _ => None, | 95 | _ => None, |
96 | }) | 96 | }) |
97 | .enumerate() | 97 | .enumerate() |
98 | .map(|(idx, func)| ((func.name(ctx.db()).to_string(), idx))) | 98 | .map(|(idx, func)| (func.name(ctx.db()).to_string(), idx)) |
99 | .collect(), | 99 | .collect(), |
100 | ) | 100 | ) |
101 | } | 101 | } |
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs index 88fe2fe90..4f0ef52ca 100644 --- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use hir::ModuleDef; | 1 | use hir::ModuleDef; |
2 | use ide_db::helpers::mod_path_to_ast; | 2 | use ide_db::helpers::{import_assets::NameToImport, mod_path_to_ast}; |
3 | use ide_db::items_locator; | 3 | use ide_db::items_locator; |
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use syntax::{ | 5 | use syntax::{ |
@@ -65,20 +65,24 @@ pub(crate) fn replace_derive_with_manual_impl( | |||
65 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; | 65 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; |
66 | let current_crate = current_module.krate(); | 66 | let current_crate = current_module.krate(); |
67 | 67 | ||
68 | let found_traits = | 68 | let found_traits = items_locator::items_with_name( |
69 | items_locator::with_exact_name(&ctx.sema, current_crate, trait_token.text().to_string()) | 69 | &ctx.sema, |
70 | .into_iter() | 70 | current_crate, |
71 | .filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) { | 71 | NameToImport::Exact(trait_token.text().to_string()), |
72 | ModuleDef::Trait(trait_) => Some(trait_), | 72 | items_locator::AssocItemSearch::Exclude, |
73 | _ => None, | 73 | Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT), |
74 | }) | 74 | ) |
75 | .flat_map(|trait_| { | 75 | .filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) { |
76 | current_module | 76 | ModuleDef::Trait(trait_) => Some(trait_), |
77 | .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) | 77 | _ => None, |
78 | .as_ref() | 78 | }) |
79 | .map(mod_path_to_ast) | 79 | .flat_map(|trait_| { |
80 | .zip(Some(trait_)) | 80 | current_module |
81 | }); | 81 | .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) |
82 | .as_ref() | ||
83 | .map(mod_path_to_ast) | ||
84 | .zip(Some(trait_)) | ||
85 | }); | ||
82 | 86 | ||
83 | let mut no_traits_found = true; | 87 | let mut no_traits_found = true; |
84 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { | 88 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 08df2df3f..1ad017198 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -1,8 +1,10 @@ | |||
1 | //! Feature: completion with imports-on-the-fly | 1 | //! Feature: completion with imports-on-the-fly |
2 | //! | 2 | //! |
3 | //! When completing names in the current scope, proposes additional imports from other modules or crates, | 3 | //! When completing names in the current scope, proposes additional imports from other modules or crates, |
4 | //! if they can be qualified in the scope and their name contains all symbols from the completion input | 4 | //! if they can be qualified in the scope and their name contains all symbols from the completion input. |
5 | //! (case-insensitive, in any order or places). | 5 | //! |
6 | //! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent. | ||
7 | //! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the contaning is checked case-insensitively. | ||
6 | //! | 8 | //! |
7 | //! ``` | 9 | //! ``` |
8 | //! fn main() { | 10 | //! fn main() { |
@@ -942,9 +944,94 @@ mod foo { | |||
942 | } | 944 | } |
943 | 945 | ||
944 | fn main() { | 946 | fn main() { |
945 | bar::Ass$0 | 947 | bar::ASS$0 |
946 | }"#, | 948 | }"#, |
947 | expect![[]], | 949 | expect![[]], |
948 | ) | 950 | ) |
949 | } | 951 | } |
952 | |||
953 | #[test] | ||
954 | fn unqualified_assoc_items_are_omitted() { | ||
955 | check( | ||
956 | r#" | ||
957 | mod something { | ||
958 | pub trait BaseTrait { | ||
959 | fn test_function() -> i32; | ||
960 | } | ||
961 | |||
962 | pub struct Item1; | ||
963 | pub struct Item2; | ||
964 | |||
965 | impl BaseTrait for Item1 { | ||
966 | fn test_function() -> i32 { | ||
967 | 1 | ||
968 | } | ||
969 | } | ||
970 | |||
971 | impl BaseTrait for Item2 { | ||
972 | fn test_function() -> i32 { | ||
973 | 2 | ||
974 | } | ||
975 | } | ||
976 | } | ||
977 | |||
978 | fn main() { | ||
979 | test_f$0 | ||
980 | }"#, | ||
981 | expect![[]], | ||
982 | ) | ||
983 | } | ||
984 | |||
985 | #[test] | ||
986 | fn case_matters() { | ||
987 | check( | ||
988 | r#" | ||
989 | mod foo { | ||
990 | pub const TEST_CONST: usize = 3; | ||
991 | pub fn test_function() -> i32 { | ||
992 | 4 | ||
993 | } | ||
994 | } | ||
995 | |||
996 | fn main() { | ||
997 | TE$0 | ||
998 | }"#, | ||
999 | expect![[r#" | ||
1000 | ct foo::TEST_CONST | ||
1001 | "#]], | ||
1002 | ); | ||
1003 | |||
1004 | check( | ||
1005 | r#" | ||
1006 | mod foo { | ||
1007 | pub const TEST_CONST: usize = 3; | ||
1008 | pub fn test_function() -> i32 { | ||
1009 | 4 | ||
1010 | } | ||
1011 | } | ||
1012 | |||
1013 | fn main() { | ||
1014 | te$0 | ||
1015 | }"#, | ||
1016 | expect![[r#" | ||
1017 | ct foo::TEST_CONST | ||
1018 | fn test_function() (foo::test_function) fn() -> i32 | ||
1019 | "#]], | ||
1020 | ); | ||
1021 | |||
1022 | check( | ||
1023 | r#" | ||
1024 | mod foo { | ||
1025 | pub const TEST_CONST: usize = 3; | ||
1026 | pub fn test_function() -> i32 { | ||
1027 | 4 | ||
1028 | } | ||
1029 | } | ||
1030 | |||
1031 | fn main() { | ||
1032 | Te$0 | ||
1033 | }"#, | ||
1034 | expect![[]], | ||
1035 | ); | ||
1036 | } | ||
950 | } | 1037 | } |
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs index 628c1fb9b..5eeddf7a4 100644 --- a/crates/ide_completion/src/completions/lifetime.rs +++ b/crates/ide_completion/src/completions/lifetime.rs | |||
@@ -70,6 +70,16 @@ fn func<'lifetime>(foo: &'li$0) {} | |||
70 | fn func<'lifetime>(foo: &'lifetime) {} | 70 | fn func<'lifetime>(foo: &'lifetime) {} |
71 | "#, | 71 | "#, |
72 | ); | 72 | ); |
73 | cov_mark::check!(completes_if_lifetime_without_idents); | ||
74 | check_edit( | ||
75 | "'lifetime", | ||
76 | r#" | ||
77 | fn func<'lifetime>(foo: &'$0) {} | ||
78 | "#, | ||
79 | r#" | ||
80 | fn func<'lifetime>(foo: &'lifetime) {} | ||
81 | "#, | ||
82 | ); | ||
73 | } | 83 | } |
74 | 84 | ||
75 | #[test] | 85 | #[test] |
@@ -192,6 +202,27 @@ fn foo<'footime, 'lifetime: 'a$0>() {} | |||
192 | } | 202 | } |
193 | 203 | ||
194 | #[test] | 204 | #[test] |
205 | fn check_label_edit() { | ||
206 | check_edit( | ||
207 | "'label", | ||
208 | r#" | ||
209 | fn foo() { | ||
210 | 'label: loop { | ||
211 | break '$0 | ||
212 | } | ||
213 | } | ||
214 | "#, | ||
215 | r#" | ||
216 | fn foo() { | ||
217 | 'label: loop { | ||
218 | break 'label | ||
219 | } | ||
220 | } | ||
221 | "#, | ||
222 | ); | ||
223 | } | ||
224 | |||
225 | #[test] | ||
195 | fn complete_label_in_loop() { | 226 | fn complete_label_in_loop() { |
196 | check( | 227 | check( |
197 | r#" | 228 | r#" |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 67e2d6f6c..32f81aec1 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -255,6 +255,10 @@ impl<'a> CompletionContext<'a> { | |||
255 | if kind == IDENT || kind == LIFETIME_IDENT || kind == UNDERSCORE || kind.is_keyword() { | 255 | if kind == IDENT || kind == LIFETIME_IDENT || kind == UNDERSCORE || kind.is_keyword() { |
256 | cov_mark::hit!(completes_if_prefix_is_keyword); | 256 | cov_mark::hit!(completes_if_prefix_is_keyword); |
257 | self.original_token.text_range() | 257 | self.original_token.text_range() |
258 | } else if kind == CHAR { | ||
259 | // assume we are completing a lifetime but the user has only typed the ' | ||
260 | cov_mark::hit!(completes_if_lifetime_without_idents); | ||
261 | TextRange::at(self.original_token.text_range().start(), TextSize::from(1)) | ||
258 | } else { | 262 | } else { |
259 | TextRange::empty(self.position.offset) | 263 | TextRange::empty(self.position.offset) |
260 | } | 264 | } |
@@ -471,7 +475,7 @@ impl<'a> CompletionContext<'a> { | |||
471 | self.lifetime_syntax = | 475 | self.lifetime_syntax = |
472 | find_node_at_offset(original_file, lifetime.syntax().text_range().start()); | 476 | find_node_at_offset(original_file, lifetime.syntax().text_range().start()); |
473 | if let Some(parent) = lifetime.syntax().parent() { | 477 | if let Some(parent) = lifetime.syntax().parent() { |
474 | if parent.kind() == syntax::SyntaxKind::ERROR { | 478 | if parent.kind() == ERROR { |
475 | return; | 479 | return; |
476 | } | 480 | } |
477 | 481 | ||
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index 995970fca..5ac1cb48d 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs | |||
@@ -14,7 +14,10 @@ mod completions; | |||
14 | use completions::flyimport::position_for_import; | 14 | use completions::flyimport::position_for_import; |
15 | use ide_db::{ | 15 | use ide_db::{ |
16 | base_db::FilePosition, | 16 | base_db::FilePosition, |
17 | helpers::{import_assets::LocatedImport, insert_use::ImportScope}, | 17 | helpers::{ |
18 | import_assets::{LocatedImport, NameToImport}, | ||
19 | insert_use::ImportScope, | ||
20 | }, | ||
18 | items_locator, RootDatabase, | 21 | items_locator, RootDatabase, |
19 | }; | 22 | }; |
20 | use text_edit::TextEdit; | 23 | use text_edit::TextEdit; |
@@ -151,15 +154,19 @@ pub fn resolve_completion_edits( | |||
151 | let current_module = ctx.sema.scope(position_for_import).module()?; | 154 | let current_module = ctx.sema.scope(position_for_import).module()?; |
152 | let current_crate = current_module.krate(); | 155 | let current_crate = current_module.krate(); |
153 | 156 | ||
154 | let (import_path, item_to_import) = | 157 | let (import_path, item_to_import) = items_locator::items_with_name( |
155 | items_locator::with_exact_name(&ctx.sema, current_crate, imported_name) | 158 | &ctx.sema, |
156 | .into_iter() | 159 | current_crate, |
157 | .filter_map(|candidate| { | 160 | NameToImport::Exact(imported_name), |
158 | current_module | 161 | items_locator::AssocItemSearch::Include, |
159 | .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind) | 162 | Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT), |
160 | .zip(Some(candidate)) | 163 | ) |
161 | }) | 164 | .filter_map(|candidate| { |
162 | .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?; | 165 | current_module |
166 | .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind) | ||
167 | .zip(Some(candidate)) | ||
168 | }) | ||
169 | .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?; | ||
163 | let import = | 170 | let import = |
164 | LocatedImport::new(import_path.clone(), item_to_import, item_to_import, Some(import_path)); | 171 | LocatedImport::new(import_path.clone(), item_to_import, item_to_import, Some(import_path)); |
165 | 172 | ||
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index cf5ef07b7..d82564381 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -71,7 +71,7 @@ fn test_has_block_expr_parent() { | |||
71 | } | 71 | } |
72 | 72 | ||
73 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { | 73 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { |
74 | element.ancestors().find(|it| it.kind() == IDENT_PAT).is_some() | 74 | element.ancestors().any(|it| it.kind() == IDENT_PAT) |
75 | } | 75 | } |
76 | #[test] | 76 | #[test] |
77 | fn test_has_bind_pat_parent() { | 77 | fn test_has_bind_pat_parent() { |
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index 7c8844e95..1881c746f 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -61,7 +61,7 @@ pub struct FirstSegmentUnresolved { | |||
61 | } | 61 | } |
62 | 62 | ||
63 | /// A name that will be used during item lookups. | 63 | /// A name that will be used during item lookups. |
64 | #[derive(Debug)] | 64 | #[derive(Debug, Clone)] |
65 | pub enum NameToImport { | 65 | pub enum NameToImport { |
66 | /// Requires items with names that exactly match the given string, case-sensitive. | 66 | /// Requires items with names that exactly match the given string, case-sensitive. |
67 | Exact(String), | 67 | Exact(String), |
@@ -201,129 +201,101 @@ impl ImportAssets { | |||
201 | sema: &Semantics<RootDatabase>, | 201 | sema: &Semantics<RootDatabase>, |
202 | prefixed: Option<PrefixKind>, | 202 | prefixed: Option<PrefixKind>, |
203 | ) -> Vec<LocatedImport> { | 203 | ) -> Vec<LocatedImport> { |
204 | let items_with_candidate_name = match self.name_to_import() { | 204 | let _p = profile::span("import_assets::search_for"); |
205 | NameToImport::Exact(exact_name) => items_locator::with_exact_name( | ||
206 | sema, | ||
207 | self.module_with_candidate.krate(), | ||
208 | exact_name.clone(), | ||
209 | ), | ||
210 | // FIXME: ideally, we should avoid using `fst` for seacrhing trait imports for assoc items: | ||
211 | // instead, we need to look up all trait impls for a certain struct and search through them only | ||
212 | // see https://github.com/rust-analyzer/rust-analyzer/pull/7293#issuecomment-761585032 | ||
213 | // and https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Blanket.20trait.20impls.20lookup | ||
214 | // for the details | ||
215 | NameToImport::Fuzzy(fuzzy_name) => { | ||
216 | let (assoc_item_search, limit) = if self.import_candidate.is_trait_candidate() { | ||
217 | (AssocItemSearch::AssocItemsOnly, None) | ||
218 | } else { | ||
219 | (AssocItemSearch::Include, Some(DEFAULT_QUERY_SEARCH_LIMIT)) | ||
220 | }; | ||
221 | |||
222 | items_locator::with_similar_name( | ||
223 | sema, | ||
224 | self.module_with_candidate.krate(), | ||
225 | fuzzy_name.clone(), | ||
226 | assoc_item_search, | ||
227 | limit, | ||
228 | ) | ||
229 | } | ||
230 | }; | ||
231 | 205 | ||
232 | let scope_definitions = self.scope_definitions(sema); | 206 | let scope_definitions = self.scope_definitions(sema); |
233 | self.applicable_defs(sema.db, prefixed, items_with_candidate_name) | ||
234 | .into_iter() | ||
235 | .filter(|import| import.import_path.len() > 1) | ||
236 | .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import))) | ||
237 | .sorted_by_key(|import| import.import_path.clone()) | ||
238 | .collect() | ||
239 | } | ||
240 | |||
241 | fn scope_definitions(&self, sema: &Semantics<RootDatabase>) -> FxHashSet<ScopeDef> { | ||
242 | let mut scope_definitions = FxHashSet::default(); | ||
243 | sema.scope(&self.candidate_node).process_all_names(&mut |_, scope_def| { | ||
244 | scope_definitions.insert(scope_def); | ||
245 | }); | ||
246 | scope_definitions | ||
247 | } | ||
248 | |||
249 | fn name_to_import(&self) -> &NameToImport { | ||
250 | match &self.import_candidate { | ||
251 | ImportCandidate::Path(candidate) => &candidate.name, | ||
252 | ImportCandidate::TraitAssocItem(candidate) | ||
253 | | ImportCandidate::TraitMethod(candidate) => &candidate.assoc_item_name, | ||
254 | } | ||
255 | } | ||
256 | |||
257 | fn applicable_defs( | ||
258 | &self, | ||
259 | db: &RootDatabase, | ||
260 | prefixed: Option<PrefixKind>, | ||
261 | items_with_candidate_name: FxHashSet<ItemInNs>, | ||
262 | ) -> FxHashSet<LocatedImport> { | ||
263 | let _p = profile::span("import_assets::applicable_defs"); | ||
264 | let current_crate = self.module_with_candidate.krate(); | 207 | let current_crate = self.module_with_candidate.krate(); |
265 | |||
266 | let mod_path = |item| { | 208 | let mod_path = |item| { |
267 | get_mod_path(db, item_for_path_search(db, item)?, &self.module_with_candidate, prefixed) | 209 | get_mod_path( |
210 | sema.db, | ||
211 | item_for_path_search(sema.db, item)?, | ||
212 | &self.module_with_candidate, | ||
213 | prefixed, | ||
214 | ) | ||
268 | }; | 215 | }; |
269 | 216 | ||
270 | match &self.import_candidate { | 217 | match &self.import_candidate { |
271 | ImportCandidate::Path(path_candidate) => { | 218 | ImportCandidate::Path(path_candidate) => { |
272 | path_applicable_imports(db, path_candidate, mod_path, items_with_candidate_name) | 219 | path_applicable_imports(sema, current_crate, path_candidate, mod_path) |
220 | } | ||
221 | ImportCandidate::TraitAssocItem(trait_candidate) => { | ||
222 | trait_applicable_items(sema, current_crate, trait_candidate, true, mod_path) | ||
223 | } | ||
224 | ImportCandidate::TraitMethod(trait_candidate) => { | ||
225 | trait_applicable_items(sema, current_crate, trait_candidate, false, mod_path) | ||
273 | } | 226 | } |
274 | ImportCandidate::TraitAssocItem(trait_candidate) => trait_applicable_items( | ||
275 | db, | ||
276 | current_crate, | ||
277 | trait_candidate, | ||
278 | true, | ||
279 | mod_path, | ||
280 | items_with_candidate_name, | ||
281 | ), | ||
282 | ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items( | ||
283 | db, | ||
284 | current_crate, | ||
285 | trait_candidate, | ||
286 | false, | ||
287 | mod_path, | ||
288 | items_with_candidate_name, | ||
289 | ), | ||
290 | } | 227 | } |
228 | .into_iter() | ||
229 | .filter(|import| import.import_path.len() > 1) | ||
230 | .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import))) | ||
231 | .sorted_by_key(|import| import.import_path.clone()) | ||
232 | .collect() | ||
233 | } | ||
234 | |||
235 | fn scope_definitions(&self, sema: &Semantics<RootDatabase>) -> FxHashSet<ScopeDef> { | ||
236 | let _p = profile::span("import_assets::scope_definitions"); | ||
237 | let mut scope_definitions = FxHashSet::default(); | ||
238 | sema.scope(&self.candidate_node).process_all_names(&mut |_, scope_def| { | ||
239 | scope_definitions.insert(scope_def); | ||
240 | }); | ||
241 | scope_definitions | ||
291 | } | 242 | } |
292 | } | 243 | } |
293 | 244 | ||
294 | fn path_applicable_imports( | 245 | fn path_applicable_imports( |
295 | db: &RootDatabase, | 246 | sema: &Semantics<RootDatabase>, |
247 | current_crate: Crate, | ||
296 | path_candidate: &PathImportCandidate, | 248 | path_candidate: &PathImportCandidate, |
297 | mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy, | 249 | mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy, |
298 | items_with_candidate_name: FxHashSet<ItemInNs>, | ||
299 | ) -> FxHashSet<LocatedImport> { | 250 | ) -> FxHashSet<LocatedImport> { |
300 | let _p = profile::span("import_assets::path_applicable_imports"); | 251 | let _p = profile::span("import_assets::path_applicable_imports"); |
301 | 252 | ||
302 | let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier { | 253 | match &path_candidate.qualifier { |
303 | None => { | 254 | None => { |
304 | return items_with_candidate_name | 255 | items_locator::items_with_name( |
305 | .into_iter() | 256 | sema, |
306 | .filter_map(|item| { | 257 | current_crate, |
307 | let mut mod_path = mod_path(item)?; | 258 | path_candidate.name.clone(), |
308 | if let Some(assoc_item) = item_as_assoc(db, item) { | 259 | // FIXME: we could look up assoc items by the input and propose those in completion, |
309 | mod_path.push_segment(assoc_item.name(db)?); | 260 | // but that requries more preparation first: |
310 | } | 261 | // * store non-trait assoc items in import_map to fully enable this lookup |
311 | Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path))) | 262 | // * ensure that does not degrade the performance (bencmark it) |
312 | }) | 263 | // * write more logic to check for corresponding trait presence requirement (we're unable to flyimport multiple item right now) |
313 | .collect(); | 264 | // * improve the associated completion item matching and/or scoring to ensure no noisy completions appear |
265 | // | ||
266 | // see also an ignored test under FIXME comment in the qualify_path.rs module | ||
267 | AssocItemSearch::Exclude, | ||
268 | Some(DEFAULT_QUERY_SEARCH_LIMIT), | ||
269 | ) | ||
270 | .filter_map(|item| { | ||
271 | let mod_path = mod_path(item)?; | ||
272 | Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path))) | ||
273 | }) | ||
274 | .collect() | ||
314 | } | 275 | } |
315 | Some(first_segment_unresolved) => ( | 276 | Some(first_segment_unresolved) => { |
316 | first_segment_unresolved.fist_segment.to_string(), | 277 | let unresolved_qualifier = |
317 | path_to_string_stripping_turbo_fish(&first_segment_unresolved.full_qualifier), | 278 | path_to_string_stripping_turbo_fish(&first_segment_unresolved.full_qualifier); |
318 | ), | 279 | let unresolved_first_segment = first_segment_unresolved.fist_segment.text(); |
319 | }; | 280 | items_locator::items_with_name( |
320 | 281 | sema, | |
321 | items_with_candidate_name | 282 | current_crate, |
322 | .into_iter() | 283 | path_candidate.name.clone(), |
323 | .filter_map(|item| { | 284 | AssocItemSearch::Include, |
324 | import_for_item(db, mod_path, &unresolved_first_segment, &unresolved_qualifier, item) | 285 | Some(DEFAULT_QUERY_SEARCH_LIMIT), |
325 | }) | 286 | ) |
326 | .collect() | 287 | .filter_map(|item| { |
288 | import_for_item( | ||
289 | sema.db, | ||
290 | mod_path, | ||
291 | unresolved_first_segment, | ||
292 | &unresolved_qualifier, | ||
293 | item, | ||
294 | ) | ||
295 | }) | ||
296 | .collect() | ||
297 | } | ||
298 | } | ||
327 | } | 299 | } |
328 | 300 | ||
329 | fn import_for_item( | 301 | fn import_for_item( |
@@ -438,25 +410,31 @@ fn module_with_segment_name( | |||
438 | } | 410 | } |
439 | 411 | ||
440 | fn trait_applicable_items( | 412 | fn trait_applicable_items( |
441 | db: &RootDatabase, | 413 | sema: &Semantics<RootDatabase>, |
442 | current_crate: Crate, | 414 | current_crate: Crate, |
443 | trait_candidate: &TraitImportCandidate, | 415 | trait_candidate: &TraitImportCandidate, |
444 | trait_assoc_item: bool, | 416 | trait_assoc_item: bool, |
445 | mod_path: impl Fn(ItemInNs) -> Option<ModPath>, | 417 | mod_path: impl Fn(ItemInNs) -> Option<ModPath>, |
446 | items_with_candidate_name: FxHashSet<ItemInNs>, | ||
447 | ) -> FxHashSet<LocatedImport> { | 418 | ) -> FxHashSet<LocatedImport> { |
448 | let _p = profile::span("import_assets::trait_applicable_items"); | 419 | let _p = profile::span("import_assets::trait_applicable_items"); |
449 | let mut required_assoc_items = FxHashSet::default(); | ||
450 | 420 | ||
451 | let trait_candidates = items_with_candidate_name | 421 | let db = sema.db; |
452 | .into_iter() | 422 | |
453 | .filter_map(|input| item_as_assoc(db, input)) | 423 | let mut required_assoc_items = FxHashSet::default(); |
454 | .filter_map(|assoc| { | 424 | let trait_candidates = items_locator::items_with_name( |
455 | let assoc_item_trait = assoc.containing_trait(db)?; | 425 | sema, |
456 | required_assoc_items.insert(assoc); | 426 | current_crate, |
457 | Some(assoc_item_trait.into()) | 427 | trait_candidate.assoc_item_name.clone(), |
458 | }) | 428 | AssocItemSearch::AssocItemsOnly, |
459 | .collect(); | 429 | Some(DEFAULT_QUERY_SEARCH_LIMIT), |
430 | ) | ||
431 | .filter_map(|input| item_as_assoc(db, input)) | ||
432 | .filter_map(|assoc| { | ||
433 | let assoc_item_trait = assoc.containing_trait(db)?; | ||
434 | required_assoc_items.insert(assoc); | ||
435 | Some(assoc_item_trait.into()) | ||
436 | }) | ||
437 | .collect(); | ||
460 | 438 | ||
461 | let mut located_imports = FxHashSet::default(); | 439 | let mut located_imports = FxHashSet::default(); |
462 | 440 | ||
@@ -565,10 +543,6 @@ impl ImportCandidate { | |||
565 | ) -> Option<Self> { | 543 | ) -> Option<Self> { |
566 | path_import_candidate(sema, qualifier, NameToImport::Fuzzy(fuzzy_name)) | 544 | path_import_candidate(sema, qualifier, NameToImport::Fuzzy(fuzzy_name)) |
567 | } | 545 | } |
568 | |||
569 | fn is_trait_candidate(&self) -> bool { | ||
570 | matches!(self, ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_)) | ||
571 | } | ||
572 | } | 546 | } |
573 | 547 | ||
574 | fn path_import_candidate( | 548 | fn path_import_candidate( |
diff --git a/crates/ide_db/src/items_locator.rs b/crates/ide_db/src/items_locator.rs index 8a7f02935..ef796b6f7 100644 --- a/crates/ide_db/src/items_locator.rs +++ b/crates/ide_db/src/items_locator.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! This module contains an import search functionality that is provided to the assists module. | 1 | //! This module has the functionality to search the project and its dependencies for a certain item, |
2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. | 2 | //! by its name and a few criteria. |
3 | 3 | //! The main reason for this module to exist is the fact that project's items and dependencies' items | |
4 | //! are located in different caches, with different APIs. | ||
4 | use either::Either; | 5 | use either::Either; |
5 | use hir::{ | 6 | use hir::{ |
6 | import_map::{self, ImportKind}, | 7 | import_map::{self, ImportKind}, |
@@ -10,122 +11,121 @@ use syntax::{ast, AstNode, SyntaxKind::NAME}; | |||
10 | 11 | ||
11 | use crate::{ | 12 | use crate::{ |
12 | defs::{Definition, NameClass}, | 13 | defs::{Definition, NameClass}, |
14 | helpers::import_assets::NameToImport, | ||
13 | symbol_index::{self, FileSymbol}, | 15 | symbol_index::{self, FileSymbol}, |
14 | RootDatabase, | 16 | RootDatabase, |
15 | }; | 17 | }; |
16 | use rustc_hash::FxHashSet; | ||
17 | |||
18 | pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; | ||
19 | 18 | ||
20 | pub fn with_exact_name( | 19 | /// A value to use, when uncertain which limit to pick. |
21 | sema: &Semantics<'_, RootDatabase>, | 20 | pub const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; |
22 | krate: Crate, | ||
23 | exact_name: String, | ||
24 | ) -> FxHashSet<ItemInNs> { | ||
25 | let _p = profile::span("find_exact_imports"); | ||
26 | find_items( | ||
27 | sema, | ||
28 | krate, | ||
29 | { | ||
30 | let mut local_query = symbol_index::Query::new(exact_name.clone()); | ||
31 | local_query.exact(); | ||
32 | local_query.limit(DEFAULT_QUERY_SEARCH_LIMIT); | ||
33 | local_query | ||
34 | }, | ||
35 | import_map::Query::new(exact_name) | ||
36 | .limit(DEFAULT_QUERY_SEARCH_LIMIT) | ||
37 | .name_only() | ||
38 | .search_mode(import_map::SearchMode::Equals) | ||
39 | .case_sensitive(), | ||
40 | ) | ||
41 | } | ||
42 | 21 | ||
43 | #[derive(Debug)] | 22 | /// Three possible ways to search for the name in associated and/or other items. |
23 | #[derive(Debug, Clone, Copy)] | ||
44 | pub enum AssocItemSearch { | 24 | pub enum AssocItemSearch { |
25 | /// Search for the name in both associated and other items. | ||
45 | Include, | 26 | Include, |
27 | /// Search for the name in other items only. | ||
46 | Exclude, | 28 | Exclude, |
29 | /// Search for the name in the associated items only. | ||
47 | AssocItemsOnly, | 30 | AssocItemsOnly, |
48 | } | 31 | } |
49 | 32 | ||
50 | pub fn with_similar_name( | 33 | /// Searches for importable items with the given name in the crate and its dependencies. |
51 | sema: &Semantics<'_, RootDatabase>, | 34 | pub fn items_with_name<'a>( |
35 | sema: &'a Semantics<'_, RootDatabase>, | ||
52 | krate: Crate, | 36 | krate: Crate, |
53 | fuzzy_search_string: String, | 37 | name: NameToImport, |
54 | assoc_item_search: AssocItemSearch, | 38 | assoc_item_search: AssocItemSearch, |
55 | limit: Option<usize>, | 39 | limit: Option<usize>, |
56 | ) -> FxHashSet<ItemInNs> { | 40 | ) -> impl Iterator<Item = ItemInNs> + 'a { |
57 | let _p = profile::span("find_similar_imports"); | 41 | let _p = profile::span("items_with_name").detail(|| { |
42 | format!( | ||
43 | "Name: {}, crate: {:?}, assoc items: {:?}, limit: {:?}", | ||
44 | name.text(), | ||
45 | assoc_item_search, | ||
46 | krate.display_name(sema.db).map(|name| name.to_string()), | ||
47 | limit, | ||
48 | ) | ||
49 | }); | ||
50 | |||
51 | let (mut local_query, mut external_query) = match name { | ||
52 | NameToImport::Exact(exact_name) => { | ||
53 | let mut local_query = symbol_index::Query::new(exact_name.clone()); | ||
54 | local_query.exact(); | ||
58 | 55 | ||
59 | let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) | 56 | let external_query = import_map::Query::new(exact_name) |
60 | .search_mode(import_map::SearchMode::Fuzzy) | 57 | .name_only() |
61 | .name_only(); | 58 | .search_mode(import_map::SearchMode::Equals) |
59 | .case_sensitive(); | ||
62 | 60 | ||
63 | match assoc_item_search { | 61 | (local_query, external_query) |
64 | AssocItemSearch::Include => {} | ||
65 | AssocItemSearch::Exclude => { | ||
66 | external_query = external_query.exclude_import_kind(ImportKind::AssociatedItem); | ||
67 | } | 62 | } |
68 | AssocItemSearch::AssocItemsOnly => { | 63 | NameToImport::Fuzzy(fuzzy_search_string) => { |
69 | external_query = external_query.assoc_items_only(); | 64 | let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone()); |
65 | |||
66 | let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) | ||
67 | .search_mode(import_map::SearchMode::Fuzzy) | ||
68 | .name_only(); | ||
69 | match assoc_item_search { | ||
70 | AssocItemSearch::Include => {} | ||
71 | AssocItemSearch::Exclude => { | ||
72 | external_query = external_query.exclude_import_kind(ImportKind::AssociatedItem); | ||
73 | } | ||
74 | AssocItemSearch::AssocItemsOnly => { | ||
75 | external_query = external_query.assoc_items_only(); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | if fuzzy_search_string.to_lowercase() != fuzzy_search_string { | ||
80 | local_query.case_sensitive(); | ||
81 | external_query = external_query.case_sensitive(); | ||
82 | } | ||
83 | |||
84 | (local_query, external_query) | ||
70 | } | 85 | } |
71 | } | 86 | }; |
72 | |||
73 | let mut local_query = symbol_index::Query::new(fuzzy_search_string); | ||
74 | 87 | ||
75 | if let Some(limit) = limit { | 88 | if let Some(limit) = limit { |
76 | external_query = external_query.limit(limit); | 89 | external_query = external_query.limit(limit); |
77 | local_query.limit(limit); | 90 | local_query.limit(limit); |
78 | } | 91 | } |
79 | 92 | ||
80 | find_items(sema, krate, local_query, external_query) | 93 | find_items(sema, krate, assoc_item_search, local_query, external_query) |
81 | .into_iter() | ||
82 | .filter(move |&item| match assoc_item_search { | ||
83 | AssocItemSearch::Include => true, | ||
84 | AssocItemSearch::Exclude => !is_assoc_item(item, sema.db), | ||
85 | AssocItemSearch::AssocItemsOnly => is_assoc_item(item, sema.db), | ||
86 | }) | ||
87 | .collect() | ||
88 | } | 94 | } |
89 | 95 | ||
90 | fn is_assoc_item(item: ItemInNs, db: &RootDatabase) -> bool { | 96 | fn find_items<'a>( |
91 | item.as_module_def_id() | 97 | sema: &'a Semantics<'_, RootDatabase>, |
92 | .and_then(|module_def_id| ModuleDef::from(module_def_id).as_assoc_item(db)) | ||
93 | .is_some() | ||
94 | } | ||
95 | |||
96 | fn find_items( | ||
97 | sema: &Semantics<'_, RootDatabase>, | ||
98 | krate: Crate, | 98 | krate: Crate, |
99 | assoc_item_search: AssocItemSearch, | ||
99 | local_query: symbol_index::Query, | 100 | local_query: symbol_index::Query, |
100 | external_query: import_map::Query, | 101 | external_query: import_map::Query, |
101 | ) -> FxHashSet<ItemInNs> { | 102 | ) -> impl Iterator<Item = ItemInNs> + 'a { |
102 | let _p = profile::span("find_similar_imports"); | 103 | let _p = profile::span("find_items"); |
103 | let db = sema.db; | 104 | let db = sema.db; |
104 | 105 | ||
105 | // Query dependencies first. | 106 | let external_importables = |
106 | let mut candidates = krate | 107 | krate.query_external_importables(db, external_query).map(|external_importable| { |
107 | .query_external_importables(db, external_query) | 108 | match external_importable { |
108 | .map(|external_importable| match external_importable { | 109 | Either::Left(module_def) => ItemInNs::from(module_def), |
109 | Either::Left(module_def) => ItemInNs::from(module_def), | 110 | Either::Right(macro_def) => ItemInNs::from(macro_def), |
110 | Either::Right(macro_def) => ItemInNs::from(macro_def), | 111 | } |
111 | }) | 112 | }); |
112 | .collect::<FxHashSet<_>>(); | ||
113 | 113 | ||
114 | // Query the local crate using the symbol index. | 114 | // Query the local crate using the symbol index. |
115 | let local_results = symbol_index::crate_symbols(db, krate.into(), local_query); | 115 | let local_results = symbol_index::crate_symbols(db, krate.into(), local_query) |
116 | 116 | .into_iter() | |
117 | candidates.extend( | 117 | .filter_map(move |local_candidate| get_name_definition(sema, &local_candidate)) |
118 | local_results | 118 | .filter_map(|name_definition_to_import| match name_definition_to_import { |
119 | .into_iter() | 119 | Definition::ModuleDef(module_def) => Some(ItemInNs::from(module_def)), |
120 | .filter_map(|local_candidate| get_name_definition(sema, &local_candidate)) | 120 | Definition::Macro(macro_def) => Some(ItemInNs::from(macro_def)), |
121 | .filter_map(|name_definition_to_import| match name_definition_to_import { | 121 | _ => None, |
122 | Definition::ModuleDef(module_def) => Some(ItemInNs::from(module_def)), | 122 | }); |
123 | Definition::Macro(macro_def) => Some(ItemInNs::from(macro_def)), | 123 | |
124 | _ => None, | 124 | external_importables.chain(local_results).filter(move |&item| match assoc_item_search { |
125 | }), | 125 | AssocItemSearch::Include => true, |
126 | ); | 126 | AssocItemSearch::Exclude => !is_assoc_item(item, sema.db), |
127 | 127 | AssocItemSearch::AssocItemsOnly => is_assoc_item(item, sema.db), | |
128 | candidates | 128 | }) |
129 | } | 129 | } |
130 | 130 | ||
131 | fn get_name_definition( | 131 | fn get_name_definition( |
@@ -144,3 +144,9 @@ fn get_name_definition( | |||
144 | let name = ast::Name::cast(candidate_name_node)?; | 144 | let name = ast::Name::cast(candidate_name_node)?; |
145 | NameClass::classify(sema, &name)?.defined(sema.db) | 145 | NameClass::classify(sema, &name)?.defined(sema.db) |
146 | } | 146 | } |
147 | |||
148 | fn is_assoc_item(item: ItemInNs, db: &RootDatabase) -> bool { | ||
149 | item.as_module_def_id() | ||
150 | .and_then(|module_def_id| ModuleDef::from(module_def_id).as_assoc_item(db)) | ||
151 | .is_some() | ||
152 | } | ||
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs index 9ed9568ce..35e382b5c 100644 --- a/crates/ide_db/src/symbol_index.rs +++ b/crates/ide_db/src/symbol_index.rs | |||
@@ -52,6 +52,7 @@ pub struct Query { | |||
52 | only_types: bool, | 52 | only_types: bool, |
53 | libs: bool, | 53 | libs: bool, |
54 | exact: bool, | 54 | exact: bool, |
55 | case_sensitive: bool, | ||
55 | limit: usize, | 56 | limit: usize, |
56 | } | 57 | } |
57 | 58 | ||
@@ -64,6 +65,7 @@ impl Query { | |||
64 | only_types: false, | 65 | only_types: false, |
65 | libs: false, | 66 | libs: false, |
66 | exact: false, | 67 | exact: false, |
68 | case_sensitive: false, | ||
67 | limit: usize::max_value(), | 69 | limit: usize::max_value(), |
68 | } | 70 | } |
69 | } | 71 | } |
@@ -80,6 +82,10 @@ impl Query { | |||
80 | self.exact = true; | 82 | self.exact = true; |
81 | } | 83 | } |
82 | 84 | ||
85 | pub fn case_sensitive(&mut self) { | ||
86 | self.case_sensitive = true; | ||
87 | } | ||
88 | |||
83 | pub fn limit(&mut self, limit: usize) { | 89 | pub fn limit(&mut self, limit: usize) { |
84 | self.limit = limit | 90 | self.limit = limit |
85 | } | 91 | } |
@@ -326,8 +332,14 @@ impl Query { | |||
326 | if self.only_types && !symbol.kind.is_type() { | 332 | if self.only_types && !symbol.kind.is_type() { |
327 | continue; | 333 | continue; |
328 | } | 334 | } |
329 | if self.exact && symbol.name != self.query { | 335 | if self.exact { |
330 | continue; | 336 | if symbol.name != self.query { |
337 | continue; | ||
338 | } | ||
339 | } else if self.case_sensitive { | ||
340 | if self.query.chars().any(|c| !symbol.name.contains(c)) { | ||
341 | continue; | ||
342 | } | ||
331 | } | 343 | } |
332 | 344 | ||
333 | res.push(symbol.clone()); | 345 | res.push(symbol.clone()); |
diff --git a/crates/ide_ssr/src/parsing.rs b/crates/ide_ssr/src/parsing.rs index 5ff25cb6d..5e757e701 100644 --- a/crates/ide_ssr/src/parsing.rs +++ b/crates/ide_ssr/src/parsing.rs | |||
@@ -67,7 +67,7 @@ impl ParsedRule { | |||
67 | ) -> Result<Vec<ParsedRule>, SsrError> { | 67 | ) -> Result<Vec<ParsedRule>, SsrError> { |
68 | let raw_pattern = pattern.as_rust_code(); | 68 | let raw_pattern = pattern.as_rust_code(); |
69 | let raw_template = template.map(|t| t.as_rust_code()); | 69 | let raw_template = template.map(|t| t.as_rust_code()); |
70 | let raw_template = raw_template.as_ref().map(|s| s.as_str()); | 70 | let raw_template = raw_template.as_deref(); |
71 | let mut builder = RuleBuilder { | 71 | let mut builder = RuleBuilder { |
72 | placeholders_by_stand_in: pattern.placeholders_by_stand_in(), | 72 | placeholders_by_stand_in: pattern.placeholders_by_stand_in(), |
73 | rules: Vec::new(), | 73 | rules: Vec::new(), |
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index 1682b21b0..75d2f2eed 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs | |||
@@ -304,7 +304,7 @@ impl BindingsBuilder { | |||
304 | link_nodes: &'a Vec<LinkNode<Rc<BindingKind>>>, | 304 | link_nodes: &'a Vec<LinkNode<Rc<BindingKind>>>, |
305 | nodes: &mut Vec<&'a Rc<BindingKind>>, | 305 | nodes: &mut Vec<&'a Rc<BindingKind>>, |
306 | ) { | 306 | ) { |
307 | link_nodes.into_iter().for_each(|it| match it { | 307 | link_nodes.iter().for_each(|it| match it { |
308 | LinkNode::Node(it) => nodes.push(it), | 308 | LinkNode::Node(it) => nodes.push(it), |
309 | LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes), | 309 | LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes), |
310 | }); | 310 | }); |
@@ -713,10 +713,9 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen | |||
713 | .map(|ident| Some(tt::Leaf::from(ident.clone()).into())) | 713 | .map(|ident| Some(tt::Leaf::from(ident.clone()).into())) |
714 | .map_err(|()| err!("expected ident")), | 714 | .map_err(|()| err!("expected ident")), |
715 | "tt" => input.expect_tt().map(Some).map_err(|()| err!()), | 715 | "tt" => input.expect_tt().map(Some).map_err(|()| err!()), |
716 | "lifetime" => input | 716 | "lifetime" => { |
717 | .expect_lifetime() | 717 | input.expect_lifetime().map(Some).map_err(|()| err!("expected lifetime")) |
718 | .map(|tt| Some(tt)) | 718 | } |
719 | .map_err(|()| err!("expected lifetime")), | ||
720 | "literal" => { | 719 | "literal" => { |
721 | let neg = input.eat_char('-'); | 720 | let neg = input.eat_char('-'); |
722 | input | 721 | input |
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 33b85e23d..e74f8cf3f 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs | |||
@@ -356,6 +356,6 @@ impl<T> ExpandResult<T> { | |||
356 | 356 | ||
357 | impl<T: Default> From<Result<T, ExpandError>> for ExpandResult<T> { | 357 | impl<T: Default> From<Result<T, ExpandError>> for ExpandResult<T> { |
358 | fn from(result: Result<T, ExpandError>) -> Self { | 358 | fn from(result: Result<T, ExpandError>) -> Self { |
359 | result.map_or_else(|e| Self::only_err(e), |it| Self::ok(it)) | 359 | result.map_or_else(Self::only_err, Self::ok) |
360 | } | 360 | } |
361 | } | 361 | } |
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index c88387653..61b2a4955 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs | |||
@@ -57,7 +57,7 @@ impl<'a> Iterator for OpDelimitedIter<'a> { | |||
57 | 57 | ||
58 | fn size_hint(&self) -> (usize, Option<usize>) { | 58 | fn size_hint(&self) -> (usize, Option<usize>) { |
59 | let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 }; | 59 | let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 }; |
60 | let remain = len.checked_sub(self.idx).unwrap_or(0); | 60 | let remain = len.saturating_sub(self.idx); |
61 | (remain, Some(remain)) | 61 | (remain, Some(remain)) |
62 | } | 62 | } |
63 | } | 63 | } |
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 8bba3d3d5..9d433b3b0 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs | |||
@@ -362,7 +362,7 @@ trait TokenConvertor { | |||
362 | if let Some((kind, closed)) = delim { | 362 | if let Some((kind, closed)) = delim { |
363 | let mut subtree = tt::Subtree::default(); | 363 | let mut subtree = tt::Subtree::default(); |
364 | let (id, idx) = self.id_alloc().open_delim(range); | 364 | let (id, idx) = self.id_alloc().open_delim(range); |
365 | subtree.delimiter = Some(tt::Delimiter { kind, id }); | 365 | subtree.delimiter = Some(tt::Delimiter { id, kind }); |
366 | 366 | ||
367 | while self.peek().map(|it| it.kind() != closed).unwrap_or(false) { | 367 | while self.peek().map(|it| it.kind() != closed).unwrap_or(false) { |
368 | self.collect_leaf(&mut subtree.token_trees); | 368 | self.collect_leaf(&mut subtree.token_trees); |
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs index 2cce62781..8951f3813 100644 --- a/crates/mbe/src/tests/expand.rs +++ b/crates/mbe/src/tests/expand.rs | |||
@@ -1225,8 +1225,7 @@ macro_rules! m { | |||
1225 | ) | 1225 | ) |
1226 | .expand_statements(r#"m!(C("0"))"#) | 1226 | .expand_statements(r#"m!(C("0"))"#) |
1227 | .descendants() | 1227 | .descendants() |
1228 | .find(|token| token.kind() == ERROR) | 1228 | .any(|token| token.kind() == ERROR)); |
1229 | .is_some()); | ||
1230 | } | 1229 | } |
1231 | 1230 | ||
1232 | #[test] | 1231 | #[test] |
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs index 728a258ea..f7050be4e 100644 --- a/crates/project_model/src/build_data.rs +++ b/crates/project_model/src/build_data.rs | |||
@@ -137,60 +137,53 @@ fn collect_from_workspace( | |||
137 | let stdout = BufReader::new(child_stdout); | 137 | let stdout = BufReader::new(child_stdout); |
138 | 138 | ||
139 | let mut res = BuildDataMap::default(); | 139 | let mut res = BuildDataMap::default(); |
140 | for message in cargo_metadata::Message::parse_stream(stdout) { | 140 | for message in cargo_metadata::Message::parse_stream(stdout).flatten() { |
141 | if let Ok(message) = message { | 141 | match message { |
142 | match message { | 142 | Message::BuildScriptExecuted(BuildScript { |
143 | Message::BuildScriptExecuted(BuildScript { | 143 | package_id, out_dir, cfgs, env, .. |
144 | package_id, | 144 | }) => { |
145 | out_dir, | 145 | let cfgs = { |
146 | cfgs, | 146 | let mut acc = Vec::new(); |
147 | env, | 147 | for cfg in cfgs { |
148 | .. | 148 | match cfg.parse::<CfgFlag>() { |
149 | }) => { | 149 | Ok(it) => acc.push(it), |
150 | let cfgs = { | 150 | Err(err) => { |
151 | let mut acc = Vec::new(); | 151 | anyhow::bail!("invalid cfg from cargo-metadata: {}", err) |
152 | for cfg in cfgs { | 152 | } |
153 | match cfg.parse::<CfgFlag>() { | 153 | }; |
154 | Ok(it) => acc.push(it), | ||
155 | Err(err) => { | ||
156 | anyhow::bail!("invalid cfg from cargo-metadata: {}", err) | ||
157 | } | ||
158 | }; | ||
159 | } | ||
160 | acc | ||
161 | }; | ||
162 | let res = res.entry(package_id.repr.clone()).or_default(); | ||
163 | // cargo_metadata crate returns default (empty) path for | ||
164 | // older cargos, which is not absolute, so work around that. | ||
165 | if !out_dir.as_str().is_empty() { | ||
166 | let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string())); | ||
167 | res.out_dir = Some(out_dir); | ||
168 | res.cfgs = cfgs; | ||
169 | } | 154 | } |
170 | 155 | acc | |
171 | res.envs = env; | 156 | }; |
157 | let res = res.entry(package_id.repr.clone()).or_default(); | ||
158 | // cargo_metadata crate returns default (empty) path for | ||
159 | // older cargos, which is not absolute, so work around that. | ||
160 | if !out_dir.as_str().is_empty() { | ||
161 | let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string())); | ||
162 | res.out_dir = Some(out_dir); | ||
163 | res.cfgs = cfgs; | ||
172 | } | 164 | } |
173 | Message::CompilerArtifact(message) => { | 165 | |
174 | progress(format!("metadata {}", message.target.name)); | 166 | res.envs = env; |
175 | 167 | } | |
176 | if message.target.kind.contains(&"proc-macro".to_string()) { | 168 | Message::CompilerArtifact(message) => { |
177 | let package_id = message.package_id; | 169 | progress(format!("metadata {}", message.target.name)); |
178 | // Skip rmeta file | 170 | |
179 | if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) | 171 | if message.target.kind.contains(&"proc-macro".to_string()) { |
180 | { | 172 | let package_id = message.package_id; |
181 | let filename = AbsPathBuf::assert(PathBuf::from(&filename)); | 173 | // Skip rmeta file |
182 | let res = res.entry(package_id.repr.clone()).or_default(); | 174 | if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) { |
183 | res.proc_macro_dylib_path = Some(filename); | 175 | let filename = AbsPathBuf::assert(PathBuf::from(&filename)); |
184 | } | 176 | let res = res.entry(package_id.repr.clone()).or_default(); |
177 | res.proc_macro_dylib_path = Some(filename); | ||
185 | } | 178 | } |
186 | } | 179 | } |
187 | Message::CompilerMessage(message) => { | ||
188 | progress(message.target.name.clone()); | ||
189 | } | ||
190 | Message::BuildFinished(_) => {} | ||
191 | Message::TextLine(_) => {} | ||
192 | _ => {} | ||
193 | } | 180 | } |
181 | Message::CompilerMessage(message) => { | ||
182 | progress(message.target.name.clone()); | ||
183 | } | ||
184 | Message::BuildFinished(_) => {} | ||
185 | Message::TextLine(_) => {} | ||
186 | _ => {} | ||
194 | } | 187 | } |
195 | } | 188 | } |
196 | 189 | ||
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index aa48c455c..7a5bcb8c7 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -33,7 +33,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
33 | hover_provider: Some(HoverProviderCapability::Simple(true)), | 33 | hover_provider: Some(HoverProviderCapability::Simple(true)), |
34 | completion_provider: Some(CompletionOptions { | 34 | completion_provider: Some(CompletionOptions { |
35 | resolve_provider: completions_resolve_provider(client_caps), | 35 | resolve_provider: completions_resolve_provider(client_caps), |
36 | trigger_characters: Some(vec![":".to_string(), ".".to_string()]), | 36 | trigger_characters: Some(vec![":".to_string(), ".".to_string(), "'".to_string()]), |
37 | all_commit_characters: None, | 37 | all_commit_characters: None, |
38 | completion_item: None, | 38 | completion_item: None, |
39 | work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, | 39 | work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 984790d35..c63a0eaea 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -242,11 +242,8 @@ impl GlobalState { | |||
242 | } | 242 | } |
243 | BuildDataProgress::End(collector) => { | 243 | BuildDataProgress::End(collector) => { |
244 | self.fetch_build_data_completed(); | 244 | self.fetch_build_data_completed(); |
245 | let workspaces = (*self.workspaces) | 245 | let workspaces = |
246 | .clone() | 246 | (*self.workspaces).clone().into_iter().map(Ok).collect(); |
247 | .into_iter() | ||
248 | .map(|it| Ok(it)) | ||
249 | .collect(); | ||
250 | self.switch_workspaces(workspaces, Some(collector)); | 247 | self.switch_workspaces(workspaces, Some(collector)); |
251 | (Some(Progress::End), None) | 248 | (Some(Progress::End), None) |
252 | } | 249 | } |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index aa8504c3d..76fdbcddd 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -237,7 +237,7 @@ impl GlobalState { | |||
237 | None => None, | 237 | None => None, |
238 | }; | 238 | }; |
239 | 239 | ||
240 | if &*self.workspaces == &workspaces && self.workspace_build_data == workspace_build_data { | 240 | if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data { |
241 | return; | 241 | return; |
242 | } | 242 | } |
243 | 243 | ||
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs index cd0c91481..95bf26f01 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/support.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs | |||
@@ -54,7 +54,7 @@ impl<'a> Project<'a> { | |||
54 | } | 54 | } |
55 | 55 | ||
56 | pub(crate) fn server(self) -> Server { | 56 | pub(crate) fn server(self) -> Server { |
57 | let tmp_dir = self.tmp_dir.unwrap_or_else(|| TestDir::new()); | 57 | let tmp_dir = self.tmp_dir.unwrap_or_else(TestDir::new); |
58 | static INIT: Once = Once::new(); | 58 | static INIT: Once = Once::new(); |
59 | INIT.call_once(|| { | 59 | INIT.call_once(|| { |
60 | env_logger::builder().is_test(true).parse_env("RA_LOG").try_init().unwrap(); | 60 | env_logger::builder().is_test(true).parse_env("RA_LOG").try_init().unwrap(); |
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index 82ebf9037..a153a9e1c 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -567,7 +567,7 @@ impl<'a> SyntaxRewriter<'a> { | |||
567 | 567 | ||
568 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | 568 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { |
569 | match element { | 569 | match element { |
570 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().to_owned()), | 570 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green()), |
571 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()), | 571 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()), |
572 | } | 572 | } |
573 | } | 573 | } |
@@ -625,7 +625,7 @@ fn position_of_child(parent: &SyntaxNode, child: SyntaxElement) -> usize { | |||
625 | 625 | ||
626 | fn to_green_element(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | 626 | fn to_green_element(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { |
627 | match element { | 627 | match element { |
628 | NodeOrToken::Node(it) => it.green().to_owned().into(), | 628 | NodeOrToken::Node(it) => it.green().into(), |
629 | NodeOrToken::Token(it) => it.green().to_owned().into(), | 629 | NodeOrToken::Token(it) => it.green().to_owned().into(), |
630 | } | 630 | } |
631 | } | 631 | } |
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 64fac13a7..347862b8a 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs | |||
@@ -333,8 +333,7 @@ impl ast::Use { | |||
333 | .and_then(ast::Whitespace::cast); | 333 | .and_then(ast::Whitespace::cast); |
334 | if let Some(next_ws) = next_ws { | 334 | if let Some(next_ws) = next_ws { |
335 | let ws_text = next_ws.syntax().text(); | 335 | let ws_text = next_ws.syntax().text(); |
336 | if ws_text.starts_with('\n') { | 336 | if let Some(rest) = ws_text.strip_prefix('\n') { |
337 | let rest = &ws_text[1..]; | ||
338 | if rest.is_empty() { | 337 | if rest.is_empty() { |
339 | res.delete(next_ws.syntax()) | 338 | res.delete(next_ws.syntax()) |
340 | } else { | 339 | } else { |
@@ -462,8 +461,7 @@ impl ast::MatchArmList { | |||
462 | let end = if let Some(comma) = start | 461 | let end = if let Some(comma) = start |
463 | .siblings_with_tokens(Direction::Next) | 462 | .siblings_with_tokens(Direction::Next) |
464 | .skip(1) | 463 | .skip(1) |
465 | .skip_while(|it| it.kind().is_trivia()) | 464 | .find(|it| !it.kind().is_trivia()) |
466 | .next() | ||
467 | .filter(|it| it.kind() == T![,]) | 465 | .filter(|it| it.kind() == T![,]) |
468 | { | 466 | { |
469 | comma | 467 | comma |
@@ -597,7 +595,7 @@ impl IndentLevel { | |||
597 | pub fn from_node(node: &SyntaxNode) -> IndentLevel { | 595 | pub fn from_node(node: &SyntaxNode) -> IndentLevel { |
598 | match node.first_token() { | 596 | match node.first_token() { |
599 | Some(it) => Self::from_token(&it), | 597 | Some(it) => Self::from_token(&it), |
600 | None => return IndentLevel(0), | 598 | None => IndentLevel(0), |
601 | } | 599 | } |
602 | } | 600 | } |
603 | 601 | ||
diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs index 636ce166d..6317d84ba 100644 --- a/crates/syntax/src/ast/expr_ext.rs +++ b/crates/syntax/src/ast/expr_ext.rs | |||
@@ -11,16 +11,16 @@ impl ast::AttrsOwner for ast::Expr {} | |||
11 | 11 | ||
12 | impl ast::Expr { | 12 | impl ast::Expr { |
13 | pub fn is_block_like(&self) -> bool { | 13 | pub fn is_block_like(&self) -> bool { |
14 | match self { | 14 | matches!( |
15 | self, | ||
15 | ast::Expr::IfExpr(_) | 16 | ast::Expr::IfExpr(_) |
16 | | ast::Expr::LoopExpr(_) | 17 | | ast::Expr::LoopExpr(_) |
17 | | ast::Expr::ForExpr(_) | 18 | | ast::Expr::ForExpr(_) |
18 | | ast::Expr::WhileExpr(_) | 19 | | ast::Expr::WhileExpr(_) |
19 | | ast::Expr::BlockExpr(_) | 20 | | ast::Expr::BlockExpr(_) |
20 | | ast::Expr::MatchExpr(_) | 21 | | ast::Expr::MatchExpr(_) |
21 | | ast::Expr::EffectExpr(_) => true, | 22 | | ast::Expr::EffectExpr(_) |
22 | _ => false, | 23 | ) |
23 | } | ||
24 | } | 24 | } |
25 | 25 | ||
26 | pub fn name_ref(&self) -> Option<ast::NameRef> { | 26 | pub fn name_ref(&self) -> Option<ast::NameRef> { |
@@ -151,20 +151,20 @@ pub enum BinOp { | |||
151 | 151 | ||
152 | impl BinOp { | 152 | impl BinOp { |
153 | pub fn is_assignment(self) -> bool { | 153 | pub fn is_assignment(self) -> bool { |
154 | match self { | 154 | matches!( |
155 | self, | ||
155 | BinOp::Assignment | 156 | BinOp::Assignment |
156 | | BinOp::AddAssign | 157 | | BinOp::AddAssign |
157 | | BinOp::DivAssign | 158 | | BinOp::DivAssign |
158 | | BinOp::MulAssign | 159 | | BinOp::MulAssign |
159 | | BinOp::RemAssign | 160 | | BinOp::RemAssign |
160 | | BinOp::ShrAssign | 161 | | BinOp::ShrAssign |
161 | | BinOp::ShlAssign | 162 | | BinOp::ShlAssign |
162 | | BinOp::SubAssign | 163 | | BinOp::SubAssign |
163 | | BinOp::BitOrAssign | 164 | | BinOp::BitOrAssign |
164 | | BinOp::BitAndAssign | 165 | | BinOp::BitAndAssign |
165 | | BinOp::BitXorAssign => true, | 166 | | BinOp::BitXorAssign |
166 | _ => false, | 167 | ) |
167 | } | ||
168 | } | 168 | } |
169 | } | 169 | } |
170 | 170 | ||
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 810c8d4c8..7049affd9 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -532,7 +532,7 @@ fn ast_from_text<N: AstNode>(text: &str) -> N { | |||
532 | } | 532 | } |
533 | 533 | ||
534 | fn unroot(n: SyntaxNode) -> SyntaxNode { | 534 | fn unroot(n: SyntaxNode) -> SyntaxNode { |
535 | SyntaxNode::new_root(n.green().to_owned()) | 535 | SyntaxNode::new_root(n.green()) |
536 | } | 536 | } |
537 | 537 | ||
538 | pub mod tokens { | 538 | pub mod tokens { |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 42a7b9c2a..bdf907a21 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -58,10 +58,7 @@ impl From<ast::MacroDef> for Macro { | |||
58 | 58 | ||
59 | impl AstNode for Macro { | 59 | impl AstNode for Macro { |
60 | fn can_cast(kind: SyntaxKind) -> bool { | 60 | fn can_cast(kind: SyntaxKind) -> bool { |
61 | match kind { | 61 | matches!(kind, SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF) |
62 | SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF => true, | ||
63 | _ => false, | ||
64 | } | ||
65 | } | 62 | } |
66 | fn cast(syntax: SyntaxNode) -> Option<Self> { | 63 | fn cast(syntax: SyntaxNode) -> Option<Self> { |
67 | let res = match syntax.kind() { | 64 | let res = match syntax.kind() { |
@@ -462,10 +459,8 @@ impl ast::FieldExpr { | |||
462 | pub fn field_access(&self) -> Option<FieldKind> { | 459 | pub fn field_access(&self) -> Option<FieldKind> { |
463 | if let Some(nr) = self.name_ref() { | 460 | if let Some(nr) = self.name_ref() { |
464 | Some(FieldKind::Name(nr)) | 461 | Some(FieldKind::Name(nr)) |
465 | } else if let Some(tok) = self.index_token() { | ||
466 | Some(FieldKind::Index(tok)) | ||
467 | } else { | 462 | } else { |
468 | None | 463 | self.index_token().map(FieldKind::Index) |
469 | } | 464 | } |
470 | } | 465 | } |
471 | } | 466 | } |
@@ -482,16 +477,10 @@ impl ast::SlicePat { | |||
482 | let prefix = args | 477 | let prefix = args |
483 | .peeking_take_while(|p| match p { | 478 | .peeking_take_while(|p| match p { |
484 | ast::Pat::RestPat(_) => false, | 479 | ast::Pat::RestPat(_) => false, |
485 | ast::Pat::IdentPat(bp) => match bp.pat() { | 480 | ast::Pat::IdentPat(bp) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))), |
486 | Some(ast::Pat::RestPat(_)) => false, | ||
487 | _ => true, | ||
488 | }, | ||
489 | ast::Pat::RefPat(rp) => match rp.pat() { | 481 | ast::Pat::RefPat(rp) => match rp.pat() { |
490 | Some(ast::Pat::RestPat(_)) => false, | 482 | Some(ast::Pat::RestPat(_)) => false, |
491 | Some(ast::Pat::IdentPat(bp)) => match bp.pat() { | 483 | Some(ast::Pat::IdentPat(bp)) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))), |
492 | Some(ast::Pat::RestPat(_)) => false, | ||
493 | _ => true, | ||
494 | }, | ||
495 | _ => true, | 484 | _ => true, |
496 | }, | 485 | }, |
497 | _ => true, | 486 | _ => true, |
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index 6c242d126..090282d28 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs | |||
@@ -494,9 +494,8 @@ pub trait HasFormatSpecifier: AstToken { | |||
494 | } | 494 | } |
495 | _ => { | 495 | _ => { |
496 | while let Some((_, Ok(next_char))) = chars.peek() { | 496 | while let Some((_, Ok(next_char))) = chars.peek() { |
497 | match next_char { | 497 | if next_char == &'{' { |
498 | '{' => break, | 498 | break; |
499 | _ => {} | ||
500 | } | 499 | } |
501 | chars.next(); | 500 | chars.next(); |
502 | } | 501 | } |
diff --git a/crates/syntax/src/fuzz.rs b/crates/syntax/src/fuzz.rs index fbb97aa27..aa84239d2 100644 --- a/crates/syntax/src/fuzz.rs +++ b/crates/syntax/src/fuzz.rs | |||
@@ -43,7 +43,7 @@ impl CheckReparse { | |||
43 | TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap()); | 43 | TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap()); |
44 | let edited_text = | 44 | let edited_text = |
45 | format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]); | 45 | format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]); |
46 | let edit = Indel { delete, insert }; | 46 | let edit = Indel { insert, delete }; |
47 | Some(CheckReparse { text, edit, edited_text }) | 47 | Some(CheckReparse { text, edit, edited_text }) |
48 | } | 48 | } |
49 | 49 | ||
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index 3e216fb70..bbe802174 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs | |||
@@ -297,7 +297,7 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxErro | |||
297 | } | 297 | } |
298 | }; | 298 | }; |
299 | } | 299 | } |
300 | return None; | 300 | None |
301 | } | 301 | } |
302 | 302 | ||
303 | fn all_supers(path: &ast::Path) -> bool { | 303 | fn all_supers(path: &ast::Path) -> bool { |
@@ -314,7 +314,7 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxErro | |||
314 | return all_supers(subpath); | 314 | return all_supers(subpath); |
315 | } | 315 | } |
316 | 316 | ||
317 | return true; | 317 | true |
318 | } | 318 | } |
319 | } | 319 | } |
320 | 320 | ||
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs index 9d9a01e30..bed44d600 100644 --- a/crates/tt/src/lib.rs +++ b/crates/tt/src/lib.rs | |||
@@ -239,9 +239,8 @@ impl Subtree { | |||
239 | 239 | ||
240 | let mut res = String::new(); | 240 | let mut res = String::new(); |
241 | res.push_str(delim.0); | 241 | res.push_str(delim.0); |
242 | let mut iter = self.token_trees.iter(); | ||
243 | let mut last = None; | 242 | let mut last = None; |
244 | while let Some(child) = iter.next() { | 243 | for child in &self.token_trees { |
245 | let s = match child { | 244 | let s = match child { |
246 | TokenTree::Leaf(it) => { | 245 | TokenTree::Leaf(it) => { |
247 | let s = match it { | 246 | let s = match it { |
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs index 158680993..c91716409 100644 --- a/xtask/src/codegen/gen_assists_docs.rs +++ b/xtask/src/codegen/gen_assists_docs.rs | |||
@@ -154,8 +154,8 @@ fn hide_hash_comments(text: &str) -> String { | |||
154 | fn reveal_hash_comments(text: &str) -> String { | 154 | fn reveal_hash_comments(text: &str) -> String { |
155 | text.split('\n') // want final newline | 155 | text.split('\n') // want final newline |
156 | .map(|it| { | 156 | .map(|it| { |
157 | if it.starts_with("# ") { | 157 | if let Some(stripped) = it.strip_prefix("# ") { |
158 | &it[2..] | 158 | stripped |
159 | } else if it == "#" { | 159 | } else if it == "#" { |
160 | "" | 160 | "" |
161 | } else { | 161 | } else { |
diff --git a/xtask/src/codegen/gen_parser_tests.rs b/xtask/src/codegen/gen_parser_tests.rs index 096590653..2fecb9b5b 100644 --- a/xtask/src/codegen/gen_parser_tests.rs +++ b/xtask/src/codegen/gen_parser_tests.rs | |||
@@ -60,12 +60,10 @@ fn collect_tests(s: &str) -> Vec<Test> { | |||
60 | let mut res = Vec::new(); | 60 | let mut res = Vec::new(); |
61 | for comment_block in extract_comment_blocks(s) { | 61 | for comment_block in extract_comment_blocks(s) { |
62 | let first_line = &comment_block[0]; | 62 | let first_line = &comment_block[0]; |
63 | let (name, ok) = if first_line.starts_with("test ") { | 63 | let (name, ok) = if let Some(name) = first_line.strip_prefix("test ") { |
64 | let name = first_line["test ".len()..].to_string(); | 64 | (name.to_string(), true) |
65 | (name, true) | 65 | } else if let Some(name) = first_line.strip_prefix("test_err ") { |
66 | } else if first_line.starts_with("test_err ") { | 66 | (name.to_string(), false) |
67 | let name = first_line["test_err ".len()..].to_string(); | ||
68 | (name, false) | ||
69 | } else { | 67 | } else { |
70 | continue; | 68 | continue; |
71 | }; | 69 | }; |
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs index 80f26e8f5..ba4b24848 100644 --- a/xtask/src/codegen/gen_syntax.rs +++ b/xtask/src/codegen/gen_syntax.rs | |||
@@ -707,7 +707,7 @@ fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str | |||
707 | let mut to_remove = Vec::new(); | 707 | let mut to_remove = Vec::new(); |
708 | for (i, field) in node.fields.iter().enumerate() { | 708 | for (i, field) in node.fields.iter().enumerate() { |
709 | let method_name = field.method_name().to_string(); | 709 | let method_name = field.method_name().to_string(); |
710 | if methods.iter().any(|&it| it == &method_name) { | 710 | if methods.iter().any(|&it| it == method_name) { |
711 | to_remove.push(i); | 711 | to_remove.push(i); |
712 | } | 712 | } |
713 | } | 713 | } |
diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 915aae71a..960927fc0 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs | |||
@@ -37,7 +37,7 @@ fn main() -> Result<()> { | |||
37 | match flags.subcommand { | 37 | match flags.subcommand { |
38 | flags::XtaskCmd::Help(_) => { | 38 | flags::XtaskCmd::Help(_) => { |
39 | println!("{}", flags::Xtask::HELP); | 39 | println!("{}", flags::Xtask::HELP); |
40 | return Ok(()); | 40 | Ok(()) |
41 | } | 41 | } |
42 | flags::XtaskCmd::Install(cmd) => cmd.run(), | 42 | flags::XtaskCmd::Install(cmd) => cmd.run(), |
43 | flags::XtaskCmd::FuzzTests(_) => run_fuzzer(), | 43 | flags::XtaskCmd::FuzzTests(_) => run_fuzzer(), |
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs index 97395738b..b0b76b8aa 100644 --- a/xtask/src/metrics.rs +++ b/xtask/src/metrics.rs | |||
@@ -167,7 +167,7 @@ impl Host { | |||
167 | 167 | ||
168 | return Ok(Host { os, cpu, mem }); | 168 | return Ok(Host { os, cpu, mem }); |
169 | 169 | ||
170 | fn read_field<'a>(path: &str, field: &str) -> Result<String> { | 170 | fn read_field(path: &str, field: &str) -> Result<String> { |
171 | let text = read_file(path)?; | 171 | let text = read_file(path)?; |
172 | 172 | ||
173 | let line = text | 173 | let line = text |
diff --git a/xtask/src/tidy.rs b/xtask/src/tidy.rs index 1352d1218..50d9efccd 100644 --- a/xtask/src/tidy.rs +++ b/xtask/src/tidy.rs | |||
@@ -193,7 +193,7 @@ https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after- | |||
193 | } | 193 | } |
194 | } | 194 | } |
195 | 195 | ||
196 | fn deny_clippy(path: &PathBuf, text: &String) { | 196 | fn deny_clippy(path: &Path, text: &str) { |
197 | let ignore = &[ | 197 | let ignore = &[ |
198 | // The documentation in string literals may contain anything for its own purposes | 198 | // The documentation in string literals may contain anything for its own purposes |
199 | "ide_completion/src/generated_lint_completions.rs", | 199 | "ide_completion/src/generated_lint_completions.rs", |