aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/code_model.rs10
-rw-r--r--crates/ra_hir/src/semantics.rs42
-rw-r--r--crates/ra_hir_ty/src/lib.rs3
-rw-r--r--crates/ra_hir_ty/src/lower.rs143
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs272
-rw-r--r--crates/ra_ide/src/display/function_signature.rs40
-rw-r--r--crates/ra_ide/src/hover.rs25
-rw-r--r--crates/ra_syntax/src/ast/generated/nodes.rs1
-rw-r--r--crates/ra_syntax/src/validation.rs39
-rw-r--r--crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast76
-rw-r--r--crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs4
-rw-r--r--docs/user/features.md4
-rw-r--r--docs/user/readme.adoc6
-rw-r--r--xtask/src/ast_src.rs2
14 files changed, 594 insertions, 73 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 3fb419571..af59aa1b6 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -953,6 +953,16 @@ impl TypeParam {
953 pub fn module(self, db: &dyn HirDatabase) -> Module { 953 pub fn module(self, db: &dyn HirDatabase) -> Module {
954 self.id.parent.module(db.upcast()).into() 954 self.id.parent.module(db.upcast()).into()
955 } 955 }
956
957 pub fn ty(self, db: &dyn HirDatabase) -> Type {
958 let resolver = self.id.parent.resolver(db.upcast());
959 let environment = TraitEnvironment::lower(db, &resolver);
960 let ty = Ty::Placeholder(self.id);
961 Type {
962 krate: self.id.parent.module(db.upcast()).krate,
963 ty: InEnvironment { value: ty, environment },
964 }
965 }
956} 966}
957 967
958// FIXME: rename from `ImplDef` to `Impl` 968// FIXME: rename from `ImplDef` to `Impl`
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 86bfb416c..a0a0f234b 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -9,6 +9,7 @@ use hir_def::{
9 AsMacroCall, TraitId, 9 AsMacroCall, TraitId,
10}; 10};
11use hir_expand::ExpansionInfo; 11use hir_expand::ExpansionInfo;
12use hir_ty::associated_type_shorthand_candidates;
12use itertools::Itertools; 13use itertools::Itertools;
13use ra_db::{FileId, FileRange}; 14use ra_db::{FileId, FileRange};
14use ra_prof::profile; 15use ra_prof::profile;
@@ -24,8 +25,9 @@ use crate::{
24 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
25 source_analyzer::{resolve_hir_path, SourceAnalyzer}, 26 source_analyzer::{resolve_hir_path, SourceAnalyzer},
26 AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, 27 AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef,
27 Name, Origin, Path, ScopeDef, Trait, Type, TypeParam, 28 Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
28}; 29};
30use resolver::TypeNs;
29 31
30#[derive(Debug, Clone, PartialEq, Eq)] 32#[derive(Debug, Clone, PartialEq, Eq)]
31pub enum PathResolution { 33pub enum PathResolution {
@@ -40,6 +42,44 @@ pub enum PathResolution {
40 AssocItem(AssocItem), 42 AssocItem(AssocItem),
41} 43}
42 44
45impl PathResolution {
46 fn in_type_ns(&self) -> Option<TypeNs> {
47 match self {
48 PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())),
49 PathResolution::Def(ModuleDef::BuiltinType(builtin)) => {
50 Some(TypeNs::BuiltinType(*builtin))
51 }
52 PathResolution::Def(ModuleDef::Const(_))
53 | PathResolution::Def(ModuleDef::EnumVariant(_))
54 | PathResolution::Def(ModuleDef::Function(_))
55 | PathResolution::Def(ModuleDef::Module(_))
56 | PathResolution::Def(ModuleDef::Static(_))
57 | PathResolution::Def(ModuleDef::Trait(_)) => None,
58 PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
59 Some(TypeNs::TypeAliasId((*alias).into()))
60 }
61 PathResolution::Local(_) | PathResolution::Macro(_) => None,
62 PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
63 PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
64 PathResolution::AssocItem(AssocItem::Const(_))
65 | PathResolution::AssocItem(AssocItem::Function(_)) => None,
66 PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => {
67 Some(TypeNs::TypeAliasId((*alias).into()))
68 }
69 }
70 }
71
72 /// Returns an iterator over associated types that may be specified after this path (using
73 /// `Ty::Assoc` syntax).
74 pub fn assoc_type_shorthand_candidates<R>(
75 &self,
76 db: &dyn HirDatabase,
77 mut cb: impl FnMut(TypeAlias) -> Option<R>,
78 ) -> Option<R> {
79 associated_type_shorthand_candidates(db, self.in_type_ns()?, |_, _, id| cb(id.into()))
80 }
81}
82
43/// Primary API to get semantic information, like types, from syntax trees. 83/// Primary API to get semantic information, like types, from syntax trees.
44pub struct Semantics<'db, DB> { 84pub struct Semantics<'db, DB> {
45 pub db: &'db DB, 85 pub db: &'db DB,
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index a8ef32ec5..a6f56c661 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -66,7 +66,8 @@ pub use autoderef::autoderef;
66pub use infer::{InferTy, InferenceResult}; 66pub use infer::{InferTy, InferenceResult};
67pub use lower::CallableDef; 67pub use lower::CallableDef;
68pub use lower::{ 68pub use lower::{
69 callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId, 69 associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId,
70 TyLoweringContext, ValueTyDefId,
70}; 71};
71pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 72pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
72 73
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index a6f893037..9ad6dbe07 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -17,9 +17,9 @@ use hir_def::{
17 path::{GenericArg, Path, PathSegment, PathSegments}, 17 path::{GenericArg, Path, PathSegment, PathSegments},
18 resolver::{HasResolver, Resolver, TypeNs}, 18 resolver::{HasResolver, Resolver, TypeNs},
19 type_ref::{TypeBound, TypeRef}, 19 type_ref::{TypeBound, TypeRef},
20 AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, 20 AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId,
21 ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, 21 HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
22 VariantId, 22 UnionId, VariantId,
23}; 23};
24use ra_arena::map::ArenaMap; 24use ra_arena::map::ArenaMap;
25use ra_db::CrateId; 25use ra_db::CrateId;
@@ -34,6 +34,7 @@ use crate::{
34 Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, 34 Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate,
35 ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, 35 ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
36}; 36};
37use hir_expand::name::Name;
37 38
38#[derive(Debug)] 39#[derive(Debug)]
39pub struct TyLoweringContext<'a> { 40pub struct TyLoweringContext<'a> {
@@ -383,61 +384,38 @@ impl Ty {
383 res: Option<TypeNs>, 384 res: Option<TypeNs>,
384 segment: PathSegment<'_>, 385 segment: PathSegment<'_>,
385 ) -> Ty { 386 ) -> Ty {
386 let traits_from_env: Vec<_> = match res { 387 if let Some(res) = res {
387 Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) { 388 let ty =
388 None => return Ty::Unknown, 389 associated_type_shorthand_candidates(ctx.db, res, move |name, t, associated_ty| {
389 Some(trait_ref) => vec![trait_ref.value], 390 if name == segment.name {
390 }, 391 let substs = match ctx.type_param_mode {
391 Some(TypeNs::GenericParam(param_id)) => { 392 TypeParamLoweringMode::Placeholder => {
392 let predicates = ctx.db.generic_predicates_for_param(param_id); 393 // if we're lowering to placeholders, we have to put
393 let mut traits_: Vec<_> = predicates 394 // them in now
394 .iter() 395 let s = Substs::type_params(
395 .filter_map(|pred| match &pred.value { 396 ctx.db,
396 GenericPredicate::Implemented(tr) => Some(tr.clone()), 397 ctx.resolver.generic_def().expect(
397 _ => None, 398 "there should be generics if there's a generic param",
398 }) 399 ),
399 .collect(); 400 );
400 // Handle `Self::Type` referring to own associated type in trait definitions 401 t.substs.clone().subst_bound_vars(&s)
401 if let GenericDefId::TraitId(trait_id) = param_id.parent { 402 }
402 let generics = generics(ctx.db.upcast(), trait_id.into()); 403 TypeParamLoweringMode::Variable => t.substs.clone(),
403 if generics.params.types[param_id.local_id].provenance
404 == TypeParamProvenance::TraitSelf
405 {
406 let trait_ref = TraitRef {
407 trait_: trait_id,
408 substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
409 }; 404 };
410 traits_.push(trait_ref); 405 // FIXME handle type parameters on the segment
406 return Some(Ty::Projection(ProjectionTy {
407 associated_ty,
408 parameters: substs,
409 }));
411 } 410 }
412 } 411
413 traits_ 412 None
414 } 413 });
415 _ => return Ty::Unknown, 414
416 }; 415 ty.unwrap_or(Ty::Unknown)
417 let traits = traits_from_env.into_iter().flat_map(|t| all_super_trait_refs(ctx.db, t)); 416 } else {
418 for t in traits { 417 Ty::Unknown
419 if let Some(associated_ty) =
420 ctx.db.trait_data(t.trait_).associated_type_by_name(&segment.name)
421 {
422 let substs = match ctx.type_param_mode {
423 TypeParamLoweringMode::Placeholder => {
424 // if we're lowering to placeholders, we have to put
425 // them in now
426 let s = Substs::type_params(
427 ctx.db,
428 ctx.resolver
429 .generic_def()
430 .expect("there should be generics if there's a generic param"),
431 );
432 t.substs.subst_bound_vars(&s)
433 }
434 TypeParamLoweringMode::Variable => t.substs,
435 };
436 // FIXME handle (forbid) type parameters on the segment
437 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
438 }
439 } 418 }
440 Ty::Unknown
441 } 419 }
442 420
443 fn from_hir_path_inner( 421 fn from_hir_path_inner(
@@ -694,6 +672,61 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig {
694 } 672 }
695} 673}
696 674
675pub fn associated_type_shorthand_candidates<R>(
676 db: &dyn HirDatabase,
677 res: TypeNs,
678 mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
679) -> Option<R> {
680 let traits_from_env: Vec<_> = match res {
681 TypeNs::SelfType(impl_id) => match db.impl_trait(impl_id) {
682 None => vec![],
683 Some(trait_ref) => vec![trait_ref.value],
684 },
685 TypeNs::GenericParam(param_id) => {
686 let predicates = db.generic_predicates_for_param(param_id);
687 let mut traits_: Vec<_> = predicates
688 .iter()
689 .filter_map(|pred| match &pred.value {
690 GenericPredicate::Implemented(tr) => Some(tr.clone()),
691 _ => None,
692 })
693 .collect();
694 // Handle `Self::Type` referring to own associated type in trait definitions
695 if let GenericDefId::TraitId(trait_id) = param_id.parent {
696 let generics = generics(db.upcast(), trait_id.into());
697 if generics.params.types[param_id.local_id].provenance
698 == TypeParamProvenance::TraitSelf
699 {
700 let trait_ref = TraitRef {
701 trait_: trait_id,
702 substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
703 };
704 traits_.push(trait_ref);
705 }
706 }
707 traits_
708 }
709 _ => vec![],
710 };
711
712 for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) {
713 let data = db.trait_data(t.trait_);
714
715 for (name, assoc_id) in &data.items {
716 match assoc_id {
717 AssocItemId::TypeAliasId(alias) => {
718 if let Some(result) = cb(name, &t, *alias) {
719 return Some(result);
720 }
721 }
722 AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => {}
723 }
724 }
725 }
726
727 None
728}
729
697/// Build the type of all specific fields of a struct or enum variant. 730/// Build the type of all specific fields of a struct or enum variant.
698pub(crate) fn field_types_query( 731pub(crate) fn field_types_query(
699 db: &dyn HirDatabase, 732 db: &dyn HirDatabase,
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs
index dd10f74e6..aa56a5cd8 100644
--- a/crates/ra_ide/src/completion/complete_qualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_qualified_path.rs
@@ -5,19 +5,29 @@ use ra_syntax::AstNode;
5use test_utils::tested_by; 5use test_utils::tested_by;
6 6
7use crate::completion::{CompletionContext, Completions}; 7use crate::completion::{CompletionContext, Completions};
8use rustc_hash::FxHashSet;
8 9
9pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
10 let path = match &ctx.path_prefix { 11 let path = match &ctx.path_prefix {
11 Some(path) => path.clone(), 12 Some(path) => path.clone(),
12 _ => return, 13 _ => return,
13 }; 14 };
14 let def = match ctx.scope().resolve_hir_path(&path) { 15 let scope = ctx.scope();
15 Some(PathResolution::Def(def)) => def, 16 let context_module = scope.module();
16 _ => return, 17
18 let res = match scope.resolve_hir_path(&path) {
19 Some(res) => res,
20 None => return,
17 }; 21 };
18 let context_module = ctx.scope().module(); 22
19 match def { 23 // Add associated types on type parameters and `Self`.
20 hir::ModuleDef::Module(module) => { 24 res.assoc_type_shorthand_candidates(ctx.db, |alias| {
25 acc.add_type_alias(ctx, alias);
26 None::<()>
27 });
28
29 match res {
30 PathResolution::Def(hir::ModuleDef::Module(module)) => {
21 let module_scope = module.scope(ctx.db, context_module); 31 let module_scope = module.scope(ctx.db, context_module);
22 for (name, def) in module_scope { 32 for (name, def) in module_scope {
23 if ctx.use_item_syntax.is_some() { 33 if ctx.use_item_syntax.is_some() {
@@ -35,7 +45,8 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
35 acc.add_resolution(ctx, name.to_string(), &def); 45 acc.add_resolution(ctx, name.to_string(), &def);
36 } 46 }
37 } 47 }
38 hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => { 48 PathResolution::Def(def @ hir::ModuleDef::Adt(_))
49 | PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) => {
39 if let hir::ModuleDef::Adt(Adt::Enum(e)) = def { 50 if let hir::ModuleDef::Adt(Adt::Enum(e)) = def {
40 for variant in e.variants(ctx.db) { 51 for variant in e.variants(ctx.db) {
41 acc.add_enum_variant(ctx, variant, None); 52 acc.add_enum_variant(ctx, variant, None);
@@ -46,8 +57,10 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
46 hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), 57 hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
47 _ => unreachable!(), 58 _ => unreachable!(),
48 }; 59 };
49 // Iterate assoc types separately 60
50 // FIXME: complete T::AssocType 61 // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
62 // (where AssocType is defined on a trait, not an inherent impl)
63
51 let krate = ctx.krate; 64 let krate = ctx.krate;
52 if let Some(krate) = krate { 65 if let Some(krate) = krate {
53 let traits_in_scope = ctx.scope().traits_in_scope(); 66 let traits_in_scope = ctx.scope().traits_in_scope();
@@ -65,6 +78,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
65 None::<()> 78 None::<()>
66 }); 79 });
67 80
81 // Iterate assoc types separately
68 ty.iterate_impl_items(ctx.db, krate, |item| { 82 ty.iterate_impl_items(ctx.db, krate, |item| {
69 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 83 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
70 return None; 84 return None;
@@ -77,7 +91,8 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
77 }); 91 });
78 } 92 }
79 } 93 }
80 hir::ModuleDef::Trait(t) => { 94 PathResolution::Def(hir::ModuleDef::Trait(t)) => {
95 // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
81 for item in t.items(ctx.db) { 96 for item in t.items(ctx.db) {
82 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 97 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
83 continue; 98 continue;
@@ -91,8 +106,38 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
91 } 106 }
92 } 107 }
93 } 108 }
109 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => {
110 if let Some(krate) = ctx.krate {
111 let ty = match res {
112 PathResolution::TypeParam(param) => param.ty(ctx.db),
113 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db),
114 _ => return,
115 };
116
117 let traits_in_scope = ctx.scope().traits_in_scope();
118 let mut seen = FxHashSet::default();
119 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
120 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
121 return None;
122 }
123
124 // We might iterate candidates of a trait multiple times here, so deduplicate
125 // them.
126 if seen.insert(item) {
127 match item {
128 hir::AssocItem::Function(func) => {
129 acc.add_function(ctx, func, None);
130 }
131 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
132 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
133 }
134 }
135 None::<()>
136 });
137 }
138 }
94 _ => {} 139 _ => {}
95 }; 140 }
96} 141}
97 142
98#[cfg(test)] 143#[cfg(test)]
@@ -844,6 +889,211 @@ mod tests {
844 } 889 }
845 890
846 #[test] 891 #[test]
892 fn completes_ty_param_assoc_ty() {
893 assert_debug_snapshot!(
894 do_reference_completion(
895 "
896 //- /lib.rs
897 trait Super {
898 type Ty;
899 const CONST: u8;
900 fn func() {}
901 fn method(&self) {}
902 }
903
904 trait Sub: Super {
905 type SubTy;
906 const C2: ();
907 fn subfunc() {}
908 fn submethod(&self) {}
909 }
910
911 fn foo<T: Sub>() {
912 T::<|>
913 }
914 "
915 ),
916 @r###"
917 [
918 CompletionItem {
919 label: "C2",
920 source_range: 219..219,
921 delete: 219..219,
922 insert: "C2",
923 kind: Const,
924 detail: "const C2: ();",
925 },
926 CompletionItem {
927 label: "CONST",
928 source_range: 219..219,
929 delete: 219..219,
930 insert: "CONST",
931 kind: Const,
932 detail: "const CONST: u8;",
933 },
934 CompletionItem {
935 label: "SubTy",
936 source_range: 219..219,
937 delete: 219..219,
938 insert: "SubTy",
939 kind: TypeAlias,
940 detail: "type SubTy;",
941 },
942 CompletionItem {
943 label: "Ty",
944 source_range: 219..219,
945 delete: 219..219,
946 insert: "Ty",
947 kind: TypeAlias,
948 detail: "type Ty;",
949 },
950 CompletionItem {
951 label: "func()",
952 source_range: 219..219,
953 delete: 219..219,
954 insert: "func()$0",
955 kind: Function,
956 lookup: "func",
957 detail: "fn func()",
958 },
959 CompletionItem {
960 label: "method()",
961 source_range: 219..219,
962 delete: 219..219,
963 insert: "method()$0",
964 kind: Method,
965 lookup: "method",
966 detail: "fn method(&self)",
967 },
968 CompletionItem {
969 label: "subfunc()",
970 source_range: 219..219,
971 delete: 219..219,
972 insert: "subfunc()$0",
973 kind: Function,
974 lookup: "subfunc",
975 detail: "fn subfunc()",
976 },
977 CompletionItem {
978 label: "submethod()",
979 source_range: 219..219,
980 delete: 219..219,
981 insert: "submethod()$0",
982 kind: Method,
983 lookup: "submethod",
984 detail: "fn submethod(&self)",
985 },
986 ]
987 "###
988 );
989 }
990
991 #[test]
992 fn completes_self_param_assoc_ty() {
993 assert_debug_snapshot!(
994 do_reference_completion(
995 "
996 //- /lib.rs
997 trait Super {
998 type Ty;
999 const CONST: u8 = 0;
1000 fn func() {}
1001 fn method(&self) {}
1002 }
1003
1004 trait Sub: Super {
1005 type SubTy;
1006 const C2: () = ();
1007 fn subfunc() {}
1008 fn submethod(&self) {}
1009 }
1010
1011 struct Wrap<T>(T);
1012 impl<T> Super for Wrap<T> {}
1013 impl<T> Sub for Wrap<T> {
1014 fn subfunc() {
1015 // Should be able to assume `Self: Sub + Super`
1016 Self::<|>
1017 }
1018 }
1019 "
1020 ),
1021 @r###"
1022 [
1023 CompletionItem {
1024 label: "C2",
1025 source_range: 365..365,
1026 delete: 365..365,
1027 insert: "C2",
1028 kind: Const,
1029 detail: "const C2: () = ();",
1030 },
1031 CompletionItem {
1032 label: "CONST",
1033 source_range: 365..365,
1034 delete: 365..365,
1035 insert: "CONST",
1036 kind: Const,
1037 detail: "const CONST: u8 = 0;",
1038 },
1039 CompletionItem {
1040 label: "SubTy",
1041 source_range: 365..365,
1042 delete: 365..365,
1043 insert: "SubTy",
1044 kind: TypeAlias,
1045 detail: "type SubTy;",
1046 },
1047 CompletionItem {
1048 label: "Ty",
1049 source_range: 365..365,
1050 delete: 365..365,
1051 insert: "Ty",
1052 kind: TypeAlias,
1053 detail: "type Ty;",
1054 },
1055 CompletionItem {
1056 label: "func()",
1057 source_range: 365..365,
1058 delete: 365..365,
1059 insert: "func()$0",
1060 kind: Function,
1061 lookup: "func",
1062 detail: "fn func()",
1063 },
1064 CompletionItem {
1065 label: "method()",
1066 source_range: 365..365,
1067 delete: 365..365,
1068 insert: "method()$0",
1069 kind: Method,
1070 lookup: "method",
1071 detail: "fn method(&self)",
1072 },
1073 CompletionItem {
1074 label: "subfunc()",
1075 source_range: 365..365,
1076 delete: 365..365,
1077 insert: "subfunc()$0",
1078 kind: Function,
1079 lookup: "subfunc",
1080 detail: "fn subfunc()",
1081 },
1082 CompletionItem {
1083 label: "submethod()",
1084 source_range: 365..365,
1085 delete: 365..365,
1086 insert: "submethod()$0",
1087 kind: Method,
1088 lookup: "submethod",
1089 detail: "fn submethod(&self)",
1090 },
1091 ]
1092 "###
1093 );
1094 }
1095
1096 #[test]
847 fn completes_type_alias() { 1097 fn completes_type_alias() {
848 assert_debug_snapshot!( 1098 assert_debug_snapshot!(
849 do_reference_completion( 1099 do_reference_completion(
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
index b5e2785fe..db3907fe6 100644
--- a/crates/ra_ide/src/display/function_signature.rs
+++ b/crates/ra_ide/src/display/function_signature.rs
@@ -26,6 +26,8 @@ pub struct FunctionSignature {
26 pub kind: CallableKind, 26 pub kind: CallableKind,
27 /// Optional visibility 27 /// Optional visibility
28 pub visibility: Option<String>, 28 pub visibility: Option<String>,
29 /// Qualifiers like `async`, `unsafe`, ...
30 pub qualifier: FunctionQualifier,
29 /// Name of the function 31 /// Name of the function
30 pub name: Option<String>, 32 pub name: Option<String>,
31 /// Documentation for the function 33 /// Documentation for the function
@@ -46,6 +48,16 @@ pub struct FunctionSignature {
46 pub has_self_param: bool, 48 pub has_self_param: bool,
47} 49}
48 50
51#[derive(Debug, Default)]
52pub struct FunctionQualifier {
53 // `async` and `const` are mutually exclusive. Do we need to enforcing it here?
54 pub is_async: bool,
55 pub is_const: bool,
56 pub is_unsafe: bool,
57 /// The string `extern ".."`
58 pub extern_abi: Option<String>,
59}
60
49impl FunctionSignature { 61impl FunctionSignature {
50 pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self { 62 pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self {
51 self.doc = doc; 63 self.doc = doc;
@@ -83,6 +95,8 @@ impl FunctionSignature {
83 FunctionSignature { 95 FunctionSignature {
84 kind: CallableKind::StructConstructor, 96 kind: CallableKind::StructConstructor,
85 visibility: node.visibility().map(|n| n.syntax().text().to_string()), 97 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
98 // Do we need `const`?
99 qualifier: Default::default(),
86 name: node.name().map(|n| n.text().to_string()), 100 name: node.name().map(|n| n.text().to_string()),
87 ret_type: node.name().map(|n| n.text().to_string()), 101 ret_type: node.name().map(|n| n.text().to_string()),
88 parameters: params, 102 parameters: params,
@@ -128,6 +142,8 @@ impl FunctionSignature {
128 FunctionSignature { 142 FunctionSignature {
129 kind: CallableKind::VariantConstructor, 143 kind: CallableKind::VariantConstructor,
130 visibility: None, 144 visibility: None,
145 // Do we need `const`?
146 qualifier: Default::default(),
131 name: Some(name), 147 name: Some(name),
132 ret_type: None, 148 ret_type: None,
133 parameters: params, 149 parameters: params,
@@ -151,6 +167,7 @@ impl FunctionSignature {
151 FunctionSignature { 167 FunctionSignature {
152 kind: CallableKind::Macro, 168 kind: CallableKind::Macro,
153 visibility: None, 169 visibility: None,
170 qualifier: Default::default(),
154 name: node.name().map(|n| n.text().to_string()), 171 name: node.name().map(|n| n.text().to_string()),
155 ret_type: None, 172 ret_type: None,
156 parameters: params, 173 parameters: params,
@@ -223,6 +240,12 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
223 FunctionSignature { 240 FunctionSignature {
224 kind: CallableKind::Function, 241 kind: CallableKind::Function,
225 visibility: node.visibility().map(|n| n.syntax().text().to_string()), 242 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
243 qualifier: FunctionQualifier {
244 is_async: node.async_token().is_some(),
245 is_const: node.const_token().is_some(),
246 is_unsafe: node.unsafe_token().is_some(),
247 extern_abi: node.abi().map(|n| n.to_string()),
248 },
226 name: node.name().map(|n| n.text().to_string()), 249 name: node.name().map(|n| n.text().to_string()),
227 ret_type: node 250 ret_type: node
228 .ret_type() 251 .ret_type()
@@ -246,6 +269,23 @@ impl Display for FunctionSignature {
246 write!(f, "{} ", t)?; 269 write!(f, "{} ", t)?;
247 } 270 }
248 271
272 if self.qualifier.is_async {
273 write!(f, "async ")?;
274 }
275
276 if self.qualifier.is_const {
277 write!(f, "const ")?;
278 }
279
280 if self.qualifier.is_unsafe {
281 write!(f, "unsafe ")?;
282 }
283
284 if let Some(extern_abi) = &self.qualifier.extern_abi {
285 // Keyword `extern` is included in the string.
286 write!(f, "{} ", extern_abi)?;
287 }
288
249 if let Some(name) = &self.name { 289 if let Some(name) = &self.name {
250 match self.kind { 290 match self.kind {
251 CallableKind::Function => write!(f, "fn {}", name)?, 291 CallableKind::Function => write!(f, "fn {}", name)?,
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 58c799eca..a62f598f0 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -844,4 +844,29 @@ fn func(foo: i32) { if true { <|>foo; }; }
844 &["fn foo()\n```\n\n<- `\u{3000}` here"], 844 &["fn foo()\n```\n\n<- `\u{3000}` here"],
845 ); 845 );
846 } 846 }
847
848 #[test]
849 fn test_hover_function_show_qualifiers() {
850 check_hover_result(
851 "
852 //- /lib.rs
853 async fn foo<|>() {}
854 ",
855 &["async fn foo()"],
856 );
857 check_hover_result(
858 "
859 //- /lib.rs
860 pub const unsafe fn foo<|>() {}
861 ",
862 &["pub const unsafe fn foo()"],
863 );
864 check_hover_result(
865 r#"
866 //- /lib.rs
867 pub(crate) async unsafe extern "C" fn foo<|>() {}
868 "#,
869 &[r#"pub(crate) async unsafe extern "C" fn foo()"#],
870 );
871 }
847} 872}
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs
index 2cb3ad011..3b5e05af9 100644
--- a/crates/ra_syntax/src/ast/generated/nodes.rs
+++ b/crates/ra_syntax/src/ast/generated/nodes.rs
@@ -1249,6 +1249,7 @@ pub struct PathSegment {
1249} 1249}
1250impl PathSegment { 1250impl PathSegment {
1251 pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } 1251 pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
1252 pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
1252 pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } 1253 pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
1253 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } 1254 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
1254 pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) } 1255 pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) }
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index 5e93895ec..a30bc97bb 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -96,6 +96,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
96 ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors), 96 ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors),
97 ast::Visibility(it) => validate_visibility(it, &mut errors), 97 ast::Visibility(it) => validate_visibility(it, &mut errors),
98 ast::RangeExpr(it) => validate_range_expr(it, &mut errors), 98 ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
99 ast::PathSegment(it) => validate_crate_keyword_in_path_segment(it, &mut errors),
99 _ => (), 100 _ => (),
100 } 101 }
101 } 102 }
@@ -222,3 +223,41 @@ fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) {
222 )); 223 ));
223 } 224 }
224} 225}
226
227fn validate_crate_keyword_in_path_segment(
228 segment: ast::PathSegment,
229 errors: &mut Vec<SyntaxError>,
230) {
231 const ERR_MSG: &str = "The `crate` keyword is only allowed as the first segment of a path";
232
233 let crate_token = match segment.crate_token() {
234 None => return,
235 Some(it) => it,
236 };
237
238 // Disallow both ::crate and foo::crate
239 let path = segment.parent_path();
240 if segment.coloncolon_token().is_some() || path.qualifier().is_some() {
241 errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range()));
242 return;
243 }
244
245 // We now know that the path variable describes a complete path.
246 // For expressions and types, validation is complete, but we still have
247 // to handle UseItems like this:
248 // use foo:{crate};
249 // so we crawl upwards looking for any preceding paths on `UseTree`s
250 for node in path.syntax().ancestors().skip(1) {
251 match_ast! {
252 match node {
253 ast::UseTree(it) => if let Some(tree_path) = it.path() {
254 if tree_path != path {
255 errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range()));
256 }
257 },
258 ast::UseTreeList(_it) => continue,
259 _ => return,
260 }
261 };
262 }
263}
diff --git a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
new file mode 100644
index 000000000..8306f7361
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
@@ -0,0 +1,76 @@
1[email protected]
2 [email protected]
3 [email protected] "use"
4 [email protected] " "
5 [email protected]
6 [email protected]
7 [email protected]
8 [email protected] "::"
9 [email protected] "crate"
10 [email protected] ";"
11 [email protected] "\n"
12 [email protected]
13 [email protected] "use"
14 [email protected] " "
15 [email protected]
16 [email protected]
17 [email protected] "{"
18 [email protected]
19 [email protected]
20 [email protected]
21 [email protected] "crate"
22 [email protected] ","
23 [email protected] " "
24 [email protected]
25 [email protected]
26 [email protected]
27 [email protected]
28 [email protected] "foo"
29 [email protected] "::"
30 [email protected]
31 [email protected] "{"
32 [email protected]
33 [email protected]
34 [email protected]
35 [email protected] "crate"
36 [email protected] "}"
37 [email protected] "}"
38 [email protected] ";"
39 [email protected] "\n"
40 [email protected]
41 [email protected] "use"
42 [email protected] " "
43 [email protected]
44 [email protected]
45 [email protected]
46 [email protected]
47 [email protected]
48 [email protected] "hello"
49 [email protected] "::"
50 [email protected]
51 [email protected] "crate"
52 [email protected] ";"
53 [email protected] "\n"
54 [email protected]
55 [email protected] "use"
56 [email protected] " "
57 [email protected]
58 [email protected]
59 [email protected]
60 [email protected]
61 [email protected]
62 [email protected]
63 [email protected] "hello"
64 [email protected] "::"
65 [email protected]
66 [email protected] "crate"
67 [email protected] "::"
68 [email protected]
69 [email protected]
70 [email protected] "there"
71 [email protected] ";"
72 [email protected] "\n"
73error 6..11: The `crate` keyword is only allowed as the first segment of a path
74error 31..36: The `crate` keyword is only allowed as the first segment of a path
75error 51..56: The `crate` keyword is only allowed as the first segment of a path
76error 69..74: The `crate` keyword is only allowed as the first segment of a path
diff --git a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs
new file mode 100644
index 000000000..bead4c0b6
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs
@@ -0,0 +1,4 @@
1use ::crate;
2use {crate, foo::{crate}};
3use hello::crate;
4use hello::crate::there;
diff --git a/docs/user/features.md b/docs/user/features.md
index 56d2969fd..b9a365fc1 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -140,8 +140,8 @@ space or `;` depending on the return type of the function.
140When completing a function call, `()` are automatically inserted. If a function 140When completing a function call, `()` are automatically inserted. If a function
141takes arguments, the cursor is positioned inside the parenthesis. 141takes arguments, the cursor is positioned inside the parenthesis.
142 142
143There are postifx completions, which can be triggerd by typing something like 143There are postfix completions, which can be triggered by typing something like
144`foo().if`. The word after `.` determines postifx completion. Possible variants are: 144`foo().if`. The word after `.` determines postfix completion. Possible variants are:
145 145
146- `expr.if` -> `if expr {}` 146- `expr.if` -> `if expr {}`
147- `expr.match` -> `match expr {}` 147- `expr.match` -> `match expr {}`
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc
index 8b80a7df7..54342026b 100644
--- a/docs/user/readme.adoc
+++ b/docs/user/readme.adoc
@@ -169,13 +169,15 @@ The are several LSP client implementations for vim:
169 169
1701. Install coc.nvim by following the instructions at 1701. Install coc.nvim by following the instructions at
171 https://github.com/neoclide/coc.nvim[coc.nvim] 171 https://github.com/neoclide/coc.nvim[coc.nvim]
172 (nodejs required) 172 (Node.js required)
1732. Run `:CocInstall coc-rust-analyzer` to install 1732. Run `:CocInstall coc-rust-analyzer` to install
174 https://github.com/fannheyward/coc-rust-analyzer[coc-rust-analyzer], 174 https://github.com/fannheyward/coc-rust-analyzer[coc-rust-analyzer],
175 this extension implements _most_ of the features supported in the VSCode extension: 175 this extension implements _most_ of the features supported in the VSCode extension:
176 * automatically install and upgrade stable/nightly releases
176 * same configurations as VSCode extension, `rust-analyzer.serverPath`, `rust-analyzer.cargo.features` etc. 177 * same configurations as VSCode extension, `rust-analyzer.serverPath`, `rust-analyzer.cargo.features` etc.
177 * same commands too, `rust-analyzer.analyzerStatus`, `rust-analyzer.ssr` etc. 178 * same commands too, `rust-analyzer.analyzerStatus`, `rust-analyzer.ssr` etc.
178 * highlighting and inlay_hints are not implemented yet 179 * inlay hints for method chaining support, _Neovim Only_
180 * semantic highlighting is not implemented yet
179 181
180==== LanguageClient-neovim 182==== LanguageClient-neovim
181 183
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 9c02f7c6f..98c8644e4 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -595,7 +595,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
595 qualifier: Path, 595 qualifier: Path,
596 } 596 }
597 struct PathSegment { 597 struct PathSegment {
598 T![::], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>] 598 T![::], T![crate], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>]
599 } 599 }
600 struct TypeArgList { 600 struct TypeArgList {
601 T![::], 601 T![::],