aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assists/add_import.rs6
-rw-r--r--crates/ra_hir/src/code_model.rs4
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/source_binder.rs60
-rw-r--r--crates/ra_hir_def/src/attr.rs6
-rw-r--r--crates/ra_hir_def/src/body.rs2
-rw-r--r--crates/ra_hir_def/src/body/lower.rs4
-rw-r--r--crates/ra_hir_def/src/builtin_type.rs42
-rw-r--r--crates/ra_hir_def/src/data.rs4
-rw-r--r--crates/ra_hir_def/src/generics.rs6
-rw-r--r--crates/ra_hir_def/src/nameres.rs4
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs18
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs24
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs12
-rw-r--r--crates/ra_hir_def/src/path.rs429
-rw-r--r--crates/ra_hir_def/src/path/lower.rs176
-rw-r--r--crates/ra_hir_def/src/path/lower/lower_use.rs (renamed from crates/ra_hir_def/src/path/lower_use.rs)23
-rw-r--r--crates/ra_hir_def/src/resolver.rs62
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs26
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs16
-rw-r--r--crates/ra_hir_expand/src/name.rs166
-rw-r--r--crates/ra_hir_ty/src/autoderef.rs4
-rw-r--r--crates/ra_hir_ty/src/expr.rs4
-rw-r--r--crates/ra_hir_ty/src/infer.rs67
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs5
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs25
-rw-r--r--crates/ra_hir_ty/src/lower.rs70
-rw-r--r--crates/ra_hir_ty/src/marks.rs1
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs65
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs6
-rw-r--r--crates/ra_hir_ty/src/utils.rs9
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs7
-rw-r--r--crates/ra_ide/src/goto_definition.rs46
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs43
-rw-r--r--crates/ra_ide/src/hover.rs23
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html26
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html2
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs98
-rw-r--r--crates/ra_lsp_server/src/world.rs68
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs7
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs8
-rw-r--r--crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt83
43 files changed, 1129 insertions, 635 deletions
diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs
index 363ade016..f81b4184a 100644
--- a/crates/ra_assists/src/assists/add_import.rs
+++ b/crates/ra_assists/src/assists/add_import.rs
@@ -578,7 +578,7 @@ fn apply_auto_import(
578 578
579fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { 579fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
580 let mut ps = Vec::<SmolStr>::with_capacity(10); 580 let mut ps = Vec::<SmolStr>::with_capacity(10);
581 match path.kind { 581 match path.kind() {
582 hir::PathKind::Abs => ps.push("".into()), 582 hir::PathKind::Abs => ps.push("".into()),
583 hir::PathKind::Crate => ps.push("crate".into()), 583 hir::PathKind::Crate => ps.push("crate".into()),
584 hir::PathKind::Plain => {} 584 hir::PathKind::Plain => {}
@@ -586,9 +586,7 @@ fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
586 hir::PathKind::Super => ps.push("super".into()), 586 hir::PathKind::Super => ps.push("super".into()),
587 hir::PathKind::Type(_) | hir::PathKind::DollarCrate(_) => return None, 587 hir::PathKind::Type(_) | hir::PathKind::DollarCrate(_) => return None,
588 } 588 }
589 for s in path.segments.iter() { 589 ps.extend(path.segments().iter().map(|it| it.name.to_string().into()));
590 ps.push(s.name.to_string().into());
591 }
592 Some(ps) 590 Some(ps)
593} 591}
594 592
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index c705d1630..7850ea9a7 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -17,7 +17,7 @@ use hir_def::{
17}; 17};
18use hir_expand::{ 18use hir_expand::{
19 diagnostics::DiagnosticSink, 19 diagnostics::DiagnosticSink,
20 name::{self, AsName}, 20 name::{name, AsName},
21 MacroDefId, 21 MacroDefId,
22}; 22};
23use hir_ty::{ 23use hir_ty::{
@@ -723,7 +723,7 @@ impl Local {
723 } 723 }
724 724
725 pub fn is_self(self, db: &impl HirDatabase) -> bool { 725 pub fn is_self(self, db: &impl HirDatabase) -> bool {
726 self.name(db) == Some(name::SELF_PARAM) 726 self.name(db) == Some(name![self])
727 } 727 }
728 728
729 pub fn is_mut(self, db: &impl HirDatabase) -> bool { 729 pub fn is_mut(self, db: &impl HirDatabase) -> bool {
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 8b9562722..2e52a1f5c 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -54,7 +54,7 @@ pub use hir_def::{
54 builtin_type::BuiltinType, 54 builtin_type::BuiltinType,
55 docs::Documentation, 55 docs::Documentation,
56 nameres::ModuleSource, 56 nameres::ModuleSource,
57 path::{Path, PathKind}, 57 path::{ModPath, Path, PathKind},
58 type_ref::Mutability, 58 type_ref::Mutability,
59}; 59};
60pub use hir_expand::{ 60pub use hir_expand::{
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index d3cc5c423..d326169b3 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -15,7 +15,7 @@ use hir_def::{
15 }, 15 },
16 expr::{ExprId, PatId}, 16 expr::{ExprId, PatId},
17 nameres::ModuleSource, 17 nameres::ModuleSource,
18 path::known, 18 path::path,
19 resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs}, 19 resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs},
20 AssocItemId, DefWithBodyId, 20 AssocItemId, DefWithBodyId,
21}; 21};
@@ -258,7 +258,7 @@ impl SourceAnalyzer {
258 ) -> Option<MacroDef> { 258 ) -> Option<MacroDef> {
259 let hygiene = Hygiene::new(db, macro_call.file_id); 259 let hygiene = Hygiene::new(db, macro_call.file_id);
260 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?; 260 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?;
261 self.resolver.resolve_path_as_macro(db, &path).map(|it| it.into()) 261 self.resolver.resolve_path_as_macro(db, path.mod_path()).map(|it| it.into())
262 } 262 }
263 263
264 pub fn resolve_hir_path( 264 pub fn resolve_hir_path(
@@ -266,40 +266,42 @@ impl SourceAnalyzer {
266 db: &impl HirDatabase, 266 db: &impl HirDatabase,
267 path: &crate::Path, 267 path: &crate::Path,
268 ) -> Option<PathResolution> { 268 ) -> Option<PathResolution> {
269 let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { 269 let types =
270 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), 270 self.resolver.resolve_path_in_type_ns_fully(db, path.mod_path()).map(|ty| match ty {
271 TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }), 271 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
272 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { 272 TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
273 PathResolution::Def(Adt::from(it).into()) 273 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
274 } 274 PathResolution::Def(Adt::from(it).into())
275 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
276 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
277 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
278 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
279 });
280 let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| {
281 let res = match val {
282 ValueNs::LocalBinding(pat_id) => {
283 let var = Local { parent: self.body_owner?, pat_id };
284 PathResolution::Local(var)
285 } 275 }
286 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), 276 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
287 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()), 277 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
288 ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()), 278 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
289 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), 279 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
290 ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), 280 });
291 }; 281 let values =
292 Some(res) 282 self.resolver.resolve_path_in_value_ns_fully(db, path.mod_path()).and_then(|val| {
293 }); 283 let res = match val {
284 ValueNs::LocalBinding(pat_id) => {
285 let var = Local { parent: self.body_owner?, pat_id };
286 PathResolution::Local(var)
287 }
288 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
289 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
290 ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()),
291 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
292 ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
293 };
294 Some(res)
295 });
294 296
295 let items = self 297 let items = self
296 .resolver 298 .resolver
297 .resolve_module_path_in_items(db, &path) 299 .resolve_module_path_in_items(db, path.mod_path())
298 .take_types() 300 .take_types()
299 .map(|it| PathResolution::Def(it.into())); 301 .map(|it| PathResolution::Def(it.into()));
300 types.or(values).or(items).or_else(|| { 302 types.or(values).or(items).or_else(|| {
301 self.resolver 303 self.resolver
302 .resolve_path_as_macro(db, &path) 304 .resolve_path_as_macro(db, path.mod_path())
303 .map(|def| PathResolution::Macro(def.into())) 305 .map(|def| PathResolution::Macro(def.into()))
304 }) 306 })
305 } 307 }
@@ -418,7 +420,7 @@ impl SourceAnalyzer {
418 /// Checks that particular type `ty` implements `std::future::Future`. 420 /// Checks that particular type `ty` implements `std::future::Future`.
419 /// This function is used in `.await` syntax completion. 421 /// This function is used in `.await` syntax completion.
420 pub fn impls_future(&self, db: &impl HirDatabase, ty: Type) -> bool { 422 pub fn impls_future(&self, db: &impl HirDatabase, ty: Type) -> bool {
421 let std_future_path = known::std_future_future(); 423 let std_future_path = path![std::future::Future];
422 424
423 let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) { 425 let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) {
424 Some(it) => it.into(), 426 Some(it) => it.into(),
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 5bf82e191..9efa4970c 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -12,7 +12,7 @@ use ra_syntax::{
12use tt::Subtree; 12use tt::Subtree;
13 13
14use crate::{ 14use crate::{
15 db::DefDatabase, path::Path, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup, 15 db::DefDatabase, path::ModPath, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup,
16}; 16};
17 17
18#[derive(Default, Debug, Clone, PartialEq, Eq)] 18#[derive(Default, Debug, Clone, PartialEq, Eq)]
@@ -94,7 +94,7 @@ impl Attrs {
94 94
95#[derive(Debug, Clone, PartialEq, Eq)] 95#[derive(Debug, Clone, PartialEq, Eq)]
96pub struct Attr { 96pub struct Attr {
97 pub(crate) path: Path, 97 pub(crate) path: ModPath,
98 pub(crate) input: Option<AttrInput>, 98 pub(crate) input: Option<AttrInput>,
99} 99}
100 100
@@ -106,7 +106,7 @@ pub enum AttrInput {
106 106
107impl Attr { 107impl Attr {
108 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { 108 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
109 let path = Path::from_src(ast.path()?, hygiene)?; 109 let path = ModPath::from_src(ast.path()?, hygiene)?;
110 let input = match ast.input() { 110 let input = match ast.input() {
111 None => None, 111 None => None,
112 Some(ast::AttrInput::Literal(lit)) => { 112 Some(ast::AttrInput::Literal(lit)) => {
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index b3bc336cf..7787cb87f 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -83,7 +83,7 @@ impl Expander {
83 83
84 fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> { 84 fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> {
85 self.crate_def_map 85 self.crate_def_map
86 .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other) 86 .resolve_path(db, self.module.local_id, path.mod_path(), BuiltinShadowMode::Other)
87 .0 87 .0
88 .take_macros() 88 .take_macros()
89 } 89 }
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index cc068ff94..61193b4d8 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -2,7 +2,7 @@
2//! representation. 2//! representation.
3 3
4use either::Either; 4use either::Either;
5use hir_expand::name::{self, AsName, Name}; 5use hir_expand::name::{name, AsName, Name};
6use ra_arena::Arena; 6use ra_arena::Arena;
7use ra_syntax::{ 7use ra_syntax::{
8 ast::{ 8 ast::{
@@ -68,7 +68,7 @@ where
68 let ptr = AstPtr::new(&self_param); 68 let ptr = AstPtr::new(&self_param);
69 let param_pat = self.alloc_pat( 69 let param_pat = self.alloc_pat(
70 Pat::Bind { 70 Pat::Bind {
71 name: name::SELF_PARAM, 71 name: name![self],
72 mode: BindingAnnotation::Unannotated, 72 mode: BindingAnnotation::Unannotated,
73 subpat: None, 73 subpat: None,
74 }, 74 },
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs
index 5e8157144..d14901a9b 100644
--- a/crates/ra_hir_def/src/builtin_type.rs
+++ b/crates/ra_hir_def/src/builtin_type.rs
@@ -5,7 +5,7 @@
5 5
6use std::fmt; 6use std::fmt;
7 7
8use hir_expand::name::{self, Name}; 8use hir_expand::name::{name, Name};
9 9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
11pub enum Signedness { 11pub enum Signedness {
@@ -52,26 +52,26 @@ pub enum BuiltinType {
52impl BuiltinType { 52impl BuiltinType {
53 #[rustfmt::skip] 53 #[rustfmt::skip]
54 pub const ALL: &'static [(Name, BuiltinType)] = &[ 54 pub const ALL: &'static [(Name, BuiltinType)] = &[
55 (name::CHAR, BuiltinType::Char), 55 (name![char], BuiltinType::Char),
56 (name::BOOL, BuiltinType::Bool), 56 (name![bool], BuiltinType::Bool),
57 (name::STR, BuiltinType::Str ), 57 (name![str], BuiltinType::Str),
58 58
59 (name::ISIZE, BuiltinType::Int(BuiltinInt::ISIZE)), 59 (name![isize], BuiltinType::Int(BuiltinInt::ISIZE)),
60 (name::I8, BuiltinType::Int(BuiltinInt::I8)), 60 (name![i8], BuiltinType::Int(BuiltinInt::I8)),
61 (name::I16, BuiltinType::Int(BuiltinInt::I16)), 61 (name![i16], BuiltinType::Int(BuiltinInt::I16)),
62 (name::I32, BuiltinType::Int(BuiltinInt::I32)), 62 (name![i32], BuiltinType::Int(BuiltinInt::I32)),
63 (name::I64, BuiltinType::Int(BuiltinInt::I64)), 63 (name![i64], BuiltinType::Int(BuiltinInt::I64)),
64 (name::I128, BuiltinType::Int(BuiltinInt::I128)), 64 (name![i128], BuiltinType::Int(BuiltinInt::I128)),
65 65
66 (name::USIZE, BuiltinType::Int(BuiltinInt::USIZE)), 66 (name![usize], BuiltinType::Int(BuiltinInt::USIZE)),
67 (name::U8, BuiltinType::Int(BuiltinInt::U8)), 67 (name![u8], BuiltinType::Int(BuiltinInt::U8)),
68 (name::U16, BuiltinType::Int(BuiltinInt::U16)), 68 (name![u16], BuiltinType::Int(BuiltinInt::U16)),
69 (name::U32, BuiltinType::Int(BuiltinInt::U32)), 69 (name![u32], BuiltinType::Int(BuiltinInt::U32)),
70 (name::U64, BuiltinType::Int(BuiltinInt::U64)), 70 (name![u64], BuiltinType::Int(BuiltinInt::U64)),
71 (name::U128, BuiltinType::Int(BuiltinInt::U128)), 71 (name![u128], BuiltinType::Int(BuiltinInt::U128)),
72 72
73 (name::F32, BuiltinType::Float(BuiltinFloat::F32)), 73 (name![f32], BuiltinType::Float(BuiltinFloat::F32)),
74 (name::F64, BuiltinType::Float(BuiltinFloat::F64)), 74 (name![f64], BuiltinType::Float(BuiltinFloat::F64)),
75 ]; 75 ];
76} 76}
77 77
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index b2dac183e..4f4ef57cc 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -3,7 +3,7 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_expand::{ 5use hir_expand::{
6 name::{self, AsName, Name}, 6 name::{name, AsName, Name},
7 AstId, 7 AstId,
8}; 8};
9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
@@ -37,7 +37,7 @@ impl FunctionData {
37 let self_type = if let Some(type_ref) = self_param.ascribed_type() { 37 let self_type = if let Some(type_ref) = self_param.ascribed_type() {
38 TypeRef::from_ast(type_ref) 38 TypeRef::from_ast(type_ref)
39 } else { 39 } else {
40 let self_type = TypeRef::Path(name::SELF_TYPE.into()); 40 let self_type = TypeRef::Path(name![Self].into());
41 match self_param.kind() { 41 match self_param.kind() {
42 ast::SelfParamKind::Owned => self_type, 42 ast::SelfParamKind::Owned => self_type,
43 ast::SelfParamKind::Ref => { 43 ast::SelfParamKind::Ref => {
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index e502dd798..e9c28c730 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -6,7 +6,7 @@ use std::sync::Arc;
6 6
7use either::Either; 7use either::Either;
8use hir_expand::{ 8use hir_expand::{
9 name::{self, AsName, Name}, 9 name::{name, AsName, Name},
10 InFile, 10 InFile,
11}; 11};
12use ra_arena::{map::ArenaMap, Arena}; 12use ra_arena::{map::ArenaMap, Arena};
@@ -90,11 +90,11 @@ impl GenericParams {
90 90
91 // traits get the Self type as an implicit first type parameter 91 // traits get the Self type as an implicit first type parameter
92 let self_param_id = 92 let self_param_id =
93 generics.types.alloc(TypeParamData { name: name::SELF_TYPE, default: None }); 93 generics.types.alloc(TypeParamData { name: name![Self], default: None });
94 sm.insert(self_param_id, Either::Left(src.value.clone())); 94 sm.insert(self_param_id, Either::Left(src.value.clone()));
95 // add super traits as bounds on Self 95 // add super traits as bounds on Self
96 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar 96 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
97 let self_param = TypeRef::Path(name::SELF_TYPE.into()); 97 let self_param = TypeRef::Path(name![Self].into());
98 generics.fill_bounds(&src.value, self_param); 98 generics.fill_bounds(&src.value, self_param);
99 99
100 generics.fill(&mut sm, &src.value); 100 generics.fill(&mut sm, &src.value);
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index bd237a7b3..9aae7e48e 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -74,7 +74,7 @@ use crate::{
74 builtin_type::BuiltinType, 74 builtin_type::BuiltinType,
75 db::DefDatabase, 75 db::DefDatabase,
76 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, 76 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
77 path::Path, 77 path::ModPath,
78 per_ns::PerNs, 78 per_ns::PerNs,
79 AstId, FunctionId, ImplId, LocalImportId, LocalModuleId, ModuleDefId, ModuleId, TraitId, 79 AstId, FunctionId, ImplId, LocalImportId, LocalModuleId, ModuleDefId, ModuleId, TraitId,
80}; 80};
@@ -329,7 +329,7 @@ impl CrateDefMap {
329 &self, 329 &self,
330 db: &impl DefDatabase, 330 db: &impl DefDatabase,
331 original_module: LocalModuleId, 331 original_module: LocalModuleId,
332 path: &Path, 332 path: &ModPath,
333 shadow: BuiltinShadowMode, 333 shadow: BuiltinShadowMode,
334 ) -> (PerNs, Option<usize>) { 334 ) -> (PerNs, Option<usize>) {
335 let res = 335 let res =
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 04aadead1..912a073ea 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -6,7 +6,7 @@
6use hir_expand::{ 6use hir_expand::{
7 builtin_derive::find_builtin_derive, 7 builtin_derive::find_builtin_derive,
8 builtin_macro::find_builtin_macro, 8 builtin_macro::find_builtin_macro,
9 name::{self, AsName, Name}, 9 name::{name, AsName, Name},
10 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 10 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
11}; 11};
12use ra_cfg::CfgOptions; 12use ra_cfg::CfgOptions;
@@ -22,7 +22,7 @@ use crate::{
22 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, 22 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
23 raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, Resolution, ResolveMode, 23 raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, Resolution, ResolveMode,
24 }, 24 },
25 path::{Path, PathKind}, 25 path::{ModPath, PathKind},
26 per_ns::PerNs, 26 per_ns::PerNs,
27 AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern, 27 AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
28 LocalImportId, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, 28 LocalImportId, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc,
@@ -101,7 +101,7 @@ struct ImportDirective {
101struct MacroDirective { 101struct MacroDirective {
102 module_id: LocalModuleId, 102 module_id: LocalModuleId,
103 ast_id: AstId<ast::MacroCall>, 103 ast_id: AstId<ast::MacroCall>,
104 path: Path, 104 path: ModPath,
105 legacy: Option<MacroCallId>, 105 legacy: Option<MacroCallId>,
106} 106}
107 107
@@ -113,7 +113,7 @@ struct DefCollector<'a, DB> {
113 unresolved_imports: Vec<ImportDirective>, 113 unresolved_imports: Vec<ImportDirective>,
114 resolved_imports: Vec<ImportDirective>, 114 resolved_imports: Vec<ImportDirective>,
115 unexpanded_macros: Vec<MacroDirective>, 115 unexpanded_macros: Vec<MacroDirective>,
116 unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, Path)>, 116 unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, ModPath)>,
117 mod_dirs: FxHashMap<LocalModuleId, ModDir>, 117 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
118 cfg_options: &'a CfgOptions, 118 cfg_options: &'a CfgOptions,
119} 119}
@@ -428,7 +428,7 @@ where
428 } else { 428 } else {
429 match import.path.segments.last() { 429 match import.path.segments.last() {
430 Some(last_segment) => { 430 Some(last_segment) => {
431 let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone()); 431 let name = import.alias.clone().unwrap_or_else(|| last_segment.clone());
432 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); 432 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
433 433
434 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 434 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
@@ -565,7 +565,7 @@ where
565 res 565 res
566 } 566 }
567 567
568 fn resolve_attribute_macro(&self, path: &Path) -> Option<MacroDefId> { 568 fn resolve_attribute_macro(&self, path: &ModPath) -> Option<MacroDefId> {
569 // FIXME this is currently super hacky, just enough to support the 569 // FIXME this is currently super hacky, just enough to support the
570 // built-in derives 570 // built-in derives
571 if let Some(name) = path.as_ident() { 571 if let Some(name) = path.as_ident() {
@@ -829,7 +829,7 @@ where
829 tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok 829 tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok
830 _ => continue, // anything else would be an error (which we currently ignore) 830 _ => continue, // anything else would be an error (which we currently ignore)
831 }; 831 };
832 let path = Path::from_tt_ident(ident); 832 let path = ModPath::from_tt_ident(ident);
833 833
834 let ast_id = AstId::new(self.file_id, def.kind.ast_id()); 834 let ast_id = AstId::new(self.file_id, def.kind.ast_id());
835 self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path)); 835 self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path));
@@ -917,8 +917,8 @@ where
917 } 917 }
918} 918}
919 919
920fn is_macro_rules(path: &Path) -> bool { 920fn is_macro_rules(path: &ModPath) -> bool {
921 path.as_ident() == Some(&name::MACRO_RULES) 921 path.as_ident() == Some(&name![macro_rules])
922} 922}
923 923
924#[cfg(test)] 924#[cfg(test)]
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index aab4b1dd9..4a249e7e7 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -17,7 +17,7 @@ use test_utils::tested_by;
17use crate::{ 17use crate::{
18 db::DefDatabase, 18 db::DefDatabase,
19 nameres::{BuiltinShadowMode, CrateDefMap}, 19 nameres::{BuiltinShadowMode, CrateDefMap},
20 path::{Path, PathKind}, 20 path::{ModPath, PathKind},
21 per_ns::PerNs, 21 per_ns::PerNs,
22 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, 22 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
23}; 23};
@@ -69,7 +69,7 @@ impl CrateDefMap {
69 db: &impl DefDatabase, 69 db: &impl DefDatabase,
70 mode: ResolveMode, 70 mode: ResolveMode,
71 original_module: LocalModuleId, 71 original_module: LocalModuleId,
72 path: &Path, 72 path: &ModPath,
73 shadow: BuiltinShadowMode, 73 shadow: BuiltinShadowMode,
74 ) -> ResolvePathResult { 74 ) -> ResolvePathResult {
75 // if it is not the last segment, we prefer the module to the builtin 75 // if it is not the last segment, we prefer the module to the builtin
@@ -113,7 +113,7 @@ impl CrateDefMap {
113 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 113 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
114 }; 114 };
115 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 115 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
116 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name, prefer_module(idx)) 116 self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx))
117 } 117 }
118 PathKind::Plain => { 118 PathKind::Plain => {
119 let (idx, segment) = match segments.next() { 119 let (idx, segment) = match segments.next() {
@@ -121,7 +121,7 @@ impl CrateDefMap {
121 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 121 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
122 }; 122 };
123 log::debug!("resolving {:?} in module", segment); 123 log::debug!("resolving {:?} in module", segment);
124 self.resolve_name_in_module(db, original_module, &segment.name, prefer_module(idx)) 124 self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx))
125 } 125 }
126 PathKind::Super => { 126 PathKind::Super => {
127 if let Some(p) = self.modules[original_module].parent { 127 if let Some(p) = self.modules[original_module].parent {
@@ -137,7 +137,7 @@ impl CrateDefMap {
137 Some((_, segment)) => segment, 137 Some((_, segment)) => segment,
138 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 138 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
139 }; 139 };
140 if let Some(def) = self.extern_prelude.get(&segment.name) { 140 if let Some(def) = self.extern_prelude.get(&segment) {
141 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 141 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
142 PerNs::types(*def) 142 PerNs::types(*def)
143 } else { 143 } else {
@@ -168,8 +168,10 @@ impl CrateDefMap {
168 curr_per_ns = match curr { 168 curr_per_ns = match curr {
169 ModuleDefId::ModuleId(module) => { 169 ModuleDefId::ModuleId(module) => {
170 if module.krate != self.krate { 170 if module.krate != self.krate {
171 let path = 171 let path = ModPath {
172 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; 172 segments: path.segments[i..].to_vec(),
173 kind: PathKind::Self_,
174 };
173 log::debug!("resolving {:?} in other crate", path); 175 log::debug!("resolving {:?} in other crate", path);
174 let defp_map = db.crate_def_map(module.krate); 176 let defp_map = db.crate_def_map(module.krate);
175 let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); 177 let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
@@ -182,10 +184,10 @@ impl CrateDefMap {
182 } 184 }
183 185
184 // Since it is a qualified path here, it should not contains legacy macros 186 // Since it is a qualified path here, it should not contains legacy macros
185 match self[module.local_id].scope.get(&segment.name, prefer_module(i)) { 187 match self[module.local_id].scope.get(&segment, prefer_module(i)) {
186 Some(res) => res.def, 188 Some(res) => res.def,
187 _ => { 189 _ => {
188 log::debug!("path segment {:?} not found", segment.name); 190 log::debug!("path segment {:?} not found", segment);
189 return ResolvePathResult::empty(ReachedFixedPoint::No); 191 return ResolvePathResult::empty(ReachedFixedPoint::No);
190 } 192 }
191 } 193 }
@@ -194,7 +196,7 @@ impl CrateDefMap {
194 // enum variant 196 // enum variant
195 tested_by!(can_import_enum_variant); 197 tested_by!(can_import_enum_variant);
196 let enum_data = db.enum_data(e); 198 let enum_data = db.enum_data(e);
197 match enum_data.variant(&segment.name) { 199 match enum_data.variant(&segment) {
198 Some(local_id) => { 200 Some(local_id) => {
199 let variant = EnumVariantId { parent: e, local_id }; 201 let variant = EnumVariantId { parent: e, local_id };
200 PerNs::both(variant.into(), variant.into()) 202 PerNs::both(variant.into(), variant.into())
@@ -214,7 +216,7 @@ impl CrateDefMap {
214 // (`Struct::method`), or some other kind of associated item 216 // (`Struct::method`), or some other kind of associated item
215 log::debug!( 217 log::debug!(
216 "path segment {:?} resolved to non-module {:?}, but is not last", 218 "path segment {:?} resolved to non-module {:?}, but is not last",
217 segment.name, 219 segment,
218 curr, 220 curr,
219 ); 221 );
220 222
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index a2821e1c3..ecb4d7c03 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -22,7 +22,7 @@ use ra_syntax::{
22use test_utils::tested_by; 22use test_utils::tested_by;
23 23
24use crate::{ 24use crate::{
25 attr::Attrs, db::DefDatabase, path::Path, trace::Trace, FileAstId, HirFileId, InFile, 25 attr::Attrs, db::DefDatabase, path::ModPath, trace::Trace, FileAstId, HirFileId, InFile,
26 LocalImportId, 26 LocalImportId,
27}; 27};
28 28
@@ -154,7 +154,7 @@ pub(super) enum ModuleData {
154 154
155#[derive(Debug, Clone, PartialEq, Eq)] 155#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct ImportData { 156pub struct ImportData {
157 pub(super) path: Path, 157 pub(super) path: ModPath,
158 pub(super) alias: Option<Name>, 158 pub(super) alias: Option<Name>,
159 pub(super) is_glob: bool, 159 pub(super) is_glob: bool,
160 pub(super) is_prelude: bool, 160 pub(super) is_prelude: bool,
@@ -206,7 +206,7 @@ impl_arena_id!(Macro);
206#[derive(Debug, PartialEq, Eq)] 206#[derive(Debug, PartialEq, Eq)]
207pub(super) struct MacroData { 207pub(super) struct MacroData {
208 pub(super) ast_id: FileAstId<ast::MacroCall>, 208 pub(super) ast_id: FileAstId<ast::MacroCall>,
209 pub(super) path: Path, 209 pub(super) path: ModPath,
210 pub(super) name: Option<Name>, 210 pub(super) name: Option<Name>,
211 pub(super) export: bool, 211 pub(super) export: bool,
212 pub(super) builtin: bool, 212 pub(super) builtin: bool,
@@ -327,7 +327,7 @@ impl RawItemsCollector {
327 let attrs = self.parse_attrs(&use_item); 327 let attrs = self.parse_attrs(&use_item);
328 328
329 let mut buf = Vec::new(); 329 let mut buf = Vec::new();
330 Path::expand_use_item( 330 ModPath::expand_use_item(
331 InFile { value: use_item, file_id: self.file_id }, 331 InFile { value: use_item, file_id: self.file_id },
332 &self.hygiene, 332 &self.hygiene,
333 |path, use_tree, is_glob, alias| { 333 |path, use_tree, is_glob, alias| {
@@ -353,7 +353,7 @@ impl RawItemsCollector {
353 extern_crate: ast::ExternCrateItem, 353 extern_crate: ast::ExternCrateItem,
354 ) { 354 ) {
355 if let Some(name_ref) = extern_crate.name_ref() { 355 if let Some(name_ref) = extern_crate.name_ref() {
356 let path = Path::from_name_ref(&name_ref); 356 let path = ModPath::from_name_ref(&name_ref);
357 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); 357 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
358 let attrs = self.parse_attrs(&extern_crate); 358 let attrs = self.parse_attrs(&extern_crate);
359 // FIXME: cfg_attr 359 // FIXME: cfg_attr
@@ -377,7 +377,7 @@ impl RawItemsCollector {
377 377
378 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { 378 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
379 let attrs = self.parse_attrs(&m); 379 let attrs = self.parse_attrs(&m);
380 let path = match m.path().and_then(|path| Path::from_src(path, &self.hygiene)) { 380 let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) {
381 Some(it) => it, 381 Some(it) => it,
382 _ => return, 382 _ => return,
383 }; 383 };
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 50f0cad94..20d6d98ea 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -1,31 +1,78 @@
1//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`. 1//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
2mod lower_use; 2mod lower;
3 3
4use std::{iter, sync::Arc}; 4use std::{iter, sync::Arc};
5 5
6use either::Either;
7use hir_expand::{ 6use hir_expand::{
8 hygiene::Hygiene, 7 hygiene::Hygiene,
9 name::{self, AsName, Name}, 8 name::{AsName, Name},
10}; 9};
11use ra_db::CrateId; 10use ra_db::CrateId;
12use ra_syntax::{ 11use ra_syntax::ast;
13 ast::{self, TypeAscriptionOwner},
14 AstNode,
15};
16 12
17use crate::{type_ref::TypeRef, InFile}; 13use crate::{type_ref::TypeRef, InFile};
18 14
19#[derive(Debug, Clone, PartialEq, Eq, Hash)] 15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20pub struct Path { 16pub struct ModPath {
21 pub kind: PathKind, 17 pub kind: PathKind,
22 pub segments: Vec<PathSegment>, 18 pub segments: Vec<Name>,
19}
20
21impl ModPath {
22 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
23 lower::lower_path(path, hygiene).map(|it| it.mod_path)
24 }
25
26 pub fn from_simple_segments(
27 kind: PathKind,
28 segments: impl IntoIterator<Item = Name>,
29 ) -> ModPath {
30 let segments = segments.into_iter().collect::<Vec<_>>();
31 ModPath { kind, segments }
32 }
33
34 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath {
35 name_ref.as_name().into()
36 }
37
38 /// Converts an `tt::Ident` into a single-identifier `Path`.
39 pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
40 ident.as_name().into()
41 }
42
43 /// Calls `cb` with all paths, represented by this use item.
44 pub(crate) fn expand_use_item(
45 item_src: InFile<ast::UseItem>,
46 hygiene: &Hygiene,
47 mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<Name>),
48 ) {
49 if let Some(tree) = item_src.value.use_tree() {
50 lower::lower_use_tree(None, tree, hygiene, &mut cb);
51 }
52 }
53
54 pub fn is_ident(&self) -> bool {
55 self.kind == PathKind::Plain && self.segments.len() == 1
56 }
57
58 pub fn is_self(&self) -> bool {
59 self.kind == PathKind::Self_ && self.segments.is_empty()
60 }
61
62 /// If this path is a single identifier, like `foo`, return its name.
63 pub fn as_ident(&self) -> Option<&Name> {
64 if self.kind != PathKind::Plain || self.segments.len() > 1 {
65 return None;
66 }
67 self.segments.first()
68 }
23} 69}
24 70
25#[derive(Debug, Clone, PartialEq, Eq, Hash)] 71#[derive(Debug, Clone, PartialEq, Eq, Hash)]
26pub struct PathSegment { 72pub struct Path {
27 pub name: Name, 73 mod_path: ModPath,
28 pub args_and_bindings: Option<Arc<GenericArgs>>, 74 /// Invariant: the same len as self.path.segments
75 generic_args: Vec<Option<Arc<GenericArgs>>>,
29} 76}
30 77
31/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This 78/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
@@ -65,300 +112,162 @@ pub enum PathKind {
65} 112}
66 113
67impl Path { 114impl Path {
68 /// Calls `cb` with all paths, represented by this use item.
69 pub(crate) fn expand_use_item(
70 item_src: InFile<ast::UseItem>,
71 hygiene: &Hygiene,
72 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
73 ) {
74 if let Some(tree) = item_src.value.use_tree() {
75 lower_use::lower_use_tree(None, tree, hygiene, &mut cb);
76 }
77 }
78
79 pub(crate) fn from_simple_segments(
80 kind: PathKind,
81 segments: impl IntoIterator<Item = Name>,
82 ) -> Path {
83 Path {
84 kind,
85 segments: segments
86 .into_iter()
87 .map(|name| PathSegment { name, args_and_bindings: None })
88 .collect(),
89 }
90 }
91
92 /// Converts an `ast::Path` to `Path`. Works with use trees. 115 /// Converts an `ast::Path` to `Path`. Works with use trees.
93 /// DEPRECATED: It does not handle `$crate` from macro call. 116 /// DEPRECATED: It does not handle `$crate` from macro call.
94 pub fn from_ast(path: ast::Path) -> Option<Path> { 117 pub fn from_ast(path: ast::Path) -> Option<Path> {
95 Path::from_src(path, &Hygiene::new_unhygienic()) 118 lower::lower_path(path, &Hygiene::new_unhygienic())
96 } 119 }
97 120
98 /// Converts an `ast::Path` to `Path`. Works with use trees. 121 /// Converts an `ast::Path` to `Path`. Works with use trees.
99 /// It correctly handles `$crate` based path from macro call. 122 /// It correctly handles `$crate` based path from macro call.
100 pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 123 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
101 let mut kind = PathKind::Plain; 124 lower::lower_path(path, hygiene)
102 let mut segments = Vec::new();
103 loop {
104 let segment = path.segment()?;
105
106 if segment.has_colon_colon() {
107 kind = PathKind::Abs;
108 }
109
110 match segment.kind()? {
111 ast::PathSegmentKind::Name(name_ref) => {
112 // FIXME: this should just return name
113 match hygiene.name_ref_to_name(name_ref) {
114 Either::Left(name) => {
115 let args = segment
116 .type_arg_list()
117 .and_then(GenericArgs::from_ast)
118 .or_else(|| {
119 GenericArgs::from_fn_like_path_ast(
120 segment.param_list(),
121 segment.ret_type(),
122 )
123 })
124 .map(Arc::new);
125 let segment = PathSegment { name, args_and_bindings: args };
126 segments.push(segment);
127 }
128 Either::Right(crate_id) => {
129 kind = PathKind::DollarCrate(crate_id);
130 break;
131 }
132 }
133 }
134 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
135 assert!(path.qualifier().is_none()); // this can only occur at the first segment
136
137 let self_type = TypeRef::from_ast(type_ref?);
138
139 match trait_ref {
140 // <T>::foo
141 None => {
142 kind = PathKind::Type(Box::new(self_type));
143 }
144 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
145 Some(trait_ref) => {
146 let path = Path::from_src(trait_ref.path()?, hygiene)?;
147 kind = path.kind;
148 let mut prefix_segments = path.segments;
149 prefix_segments.reverse();
150 segments.extend(prefix_segments);
151 // Insert the type reference (T in the above example) as Self parameter for the trait
152 let mut last_segment = segments.last_mut()?;
153 if last_segment.args_and_bindings.is_none() {
154 last_segment.args_and_bindings =
155 Some(Arc::new(GenericArgs::empty()));
156 };
157 let args = last_segment.args_and_bindings.as_mut().unwrap();
158 let mut args_inner = Arc::make_mut(args);
159 args_inner.has_self_type = true;
160 args_inner.args.insert(0, GenericArg::Type(self_type));
161 }
162 }
163 }
164 ast::PathSegmentKind::CrateKw => {
165 kind = PathKind::Crate;
166 break;
167 }
168 ast::PathSegmentKind::SelfKw => {
169 kind = PathKind::Self_;
170 break;
171 }
172 ast::PathSegmentKind::SuperKw => {
173 kind = PathKind::Super;
174 break;
175 }
176 }
177 path = match qualifier(&path) {
178 Some(it) => it,
179 None => break,
180 };
181 }
182 segments.reverse();
183 return Some(Path { kind, segments });
184
185 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
186 if let Some(q) = path.qualifier() {
187 return Some(q);
188 }
189 // FIXME: this bottom up traversal is not too precise.
190 // Should we handle do a top-down analysis, recording results?
191 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
192 let use_tree = use_tree_list.parent_use_tree();
193 use_tree.path()
194 }
195 } 125 }
196 126
197 /// Converts an `ast::NameRef` into a single-identifier `Path`. 127 /// Converts an `ast::NameRef` into a single-identifier `Path`.
198 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path { 128 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
199 name_ref.as_name().into() 129 Path { mod_path: name_ref.as_name().into(), generic_args: vec![None] }
200 }
201
202 /// Converts an `tt::Ident` into a single-identifier `Path`.
203 pub(crate) fn from_tt_ident(ident: &tt::Ident) -> Path {
204 ident.as_name().into()
205 }
206
207 /// `true` is this path is a single identifier, like `foo`
208 pub fn is_ident(&self) -> bool {
209 self.kind == PathKind::Plain && self.segments.len() == 1
210 } 130 }
211 131
212 /// `true` if this path is just a standalone `self` 132 /// `true` if this path is just a standalone `self`
213 pub fn is_self(&self) -> bool { 133 pub fn is_self(&self) -> bool {
214 self.kind == PathKind::Self_ && self.segments.is_empty() 134 self.mod_path.is_self()
215 } 135 }
216 136
217 /// If this path is a single identifier, like `foo`, return its name. 137 pub fn kind(&self) -> &PathKind {
218 pub fn as_ident(&self) -> Option<&Name> { 138 &self.mod_path.kind
219 if self.kind != PathKind::Plain || self.segments.len() > 1 {
220 return None;
221 }
222 self.segments.first().map(|s| &s.name)
223 } 139 }
224 140
225 pub fn expand_macro_expr(&self) -> Option<Name> { 141 pub fn segments(&self) -> PathSegments<'_> {
226 self.as_ident().and_then(|name| Some(name.clone())) 142 PathSegments {
227 } 143 segments: self.mod_path.segments.as_slice(),
228 144 generic_args: self.generic_args.as_slice(),
229 pub fn is_type_relative(&self) -> bool {
230 match self.kind {
231 PathKind::Type(_) => true,
232 _ => false,
233 } 145 }
234 } 146 }
235}
236 147
237impl GenericArgs { 148 pub fn mod_path(&self) -> &ModPath {
238 pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> { 149 &self.mod_path
239 let mut args = Vec::new();
240 for type_arg in node.type_args() {
241 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
242 args.push(GenericArg::Type(type_ref));
243 }
244 // lifetimes ignored for now
245 let mut bindings = Vec::new();
246 for assoc_type_arg in node.assoc_type_args() {
247 if let Some(name_ref) = assoc_type_arg.name_ref() {
248 let name = name_ref.as_name();
249 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
250 bindings.push((name, type_ref));
251 }
252 }
253 if args.is_empty() && bindings.is_empty() {
254 None
255 } else {
256 Some(GenericArgs { args, has_self_type: false, bindings })
257 }
258 } 150 }
259 151
260 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) 152 pub fn qualifier(&self) -> Option<Path> {
261 /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). 153 if self.mod_path.is_ident() {
262 pub(crate) fn from_fn_like_path_ast( 154 return None;
263 params: Option<ast::ParamList>,
264 ret_type: Option<ast::RetType>,
265 ) -> Option<GenericArgs> {
266 let mut args = Vec::new();
267 let mut bindings = Vec::new();
268 if let Some(params) = params {
269 let mut param_types = Vec::new();
270 for param in params.params() {
271 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
272 param_types.push(type_ref);
273 }
274 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
275 args.push(arg);
276 }
277 if let Some(ret_type) = ret_type {
278 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
279 bindings.push((name::OUTPUT_TYPE, type_ref))
280 }
281 if args.is_empty() && bindings.is_empty() {
282 None
283 } else {
284 Some(GenericArgs { args, has_self_type: false, bindings })
285 } 155 }
286 } 156 let res = Path {
287 157 mod_path: ModPath {
288 pub(crate) fn empty() -> GenericArgs { 158 kind: self.mod_path.kind.clone(),
289 GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() } 159 segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
160 },
161 generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
162 };
163 Some(res)
290 } 164 }
291} 165}
292 166
293impl From<Name> for Path { 167#[derive(Debug, Clone, PartialEq, Eq, Hash)]
294 fn from(name: Name) -> Path { 168pub struct PathSegment<'a> {
295 Path::from_simple_segments(PathKind::Plain, iter::once(name)) 169 pub name: &'a Name,
296 } 170 pub args_and_bindings: Option<&'a GenericArgs>,
297} 171}
298 172
299pub mod known { 173pub struct PathSegments<'a> {
300 use hir_expand::name; 174 segments: &'a [Name],
301 175 generic_args: &'a [Option<Arc<GenericArgs>>],
302 use super::{Path, PathKind}; 176}
303 177
304 pub fn std_iter_into_iterator() -> Path { 178impl<'a> PathSegments<'a> {
305 Path::from_simple_segments( 179 pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
306 PathKind::Abs, 180 pub fn is_empty(&self) -> bool {
307 vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE], 181 self.len() == 0
308 )
309 } 182 }
310 183 pub fn len(&self) -> usize {
311 pub fn std_ops_try() -> Path { 184 self.segments.len()
312 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE])
313 } 185 }
314 186 pub fn first(&self) -> Option<PathSegment<'a>> {
315 pub fn std_ops_range() -> Path { 187 self.get(0)
316 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_TYPE])
317 } 188 }
318 189 pub fn last(&self) -> Option<PathSegment<'a>> {
319 pub fn std_ops_range_from() -> Path { 190 self.get(self.len().checked_sub(1)?)
320 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_FROM_TYPE])
321 } 191 }
322 192 pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
323 pub fn std_ops_range_full() -> Path { 193 assert_eq!(self.segments.len(), self.generic_args.len());
324 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_FULL_TYPE]) 194 let res = PathSegment {
195 name: self.segments.get(idx)?,
196 args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
197 };
198 Some(res)
325 } 199 }
326 200 pub fn skip(&self, len: usize) -> PathSegments<'a> {
327 pub fn std_ops_range_inclusive() -> Path { 201 assert_eq!(self.segments.len(), self.generic_args.len());
328 Path::from_simple_segments( 202 PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
329 PathKind::Abs,
330 vec![name::STD, name::OPS, name::RANGE_INCLUSIVE_TYPE],
331 )
332 } 203 }
333 204 pub fn take(&self, len: usize) -> PathSegments<'a> {
334 pub fn std_ops_range_to() -> Path { 205 assert_eq!(self.segments.len(), self.generic_args.len());
335 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_TO_TYPE]) 206 PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
336 } 207 }
337 208 pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
338 pub fn std_ops_range_to_inclusive() -> Path { 209 self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
339 Path::from_simple_segments( 210 name,
340 PathKind::Abs, 211 args_and_bindings: args.as_ref().map(|it| &**it),
341 vec![name::STD, name::OPS, name::RANGE_TO_INCLUSIVE_TYPE], 212 })
342 )
343 } 213 }
214}
344 215
345 pub fn std_ops_neg() -> Path { 216impl GenericArgs {
346 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::NEG_TYPE]) 217 pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
218 lower::lower_generic_args(node)
347 } 219 }
348 220
349 pub fn std_ops_not() -> Path { 221 pub(crate) fn empty() -> GenericArgs {
350 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::NOT_TYPE]) 222 GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
351 } 223 }
224}
352 225
353 pub fn std_result_result() -> Path { 226impl From<Name> for Path {
354 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE]) 227 fn from(name: Name) -> Path {
228 Path {
229 mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
230 generic_args: vec![None],
231 }
355 } 232 }
233}
356 234
357 pub fn std_future_future() -> Path { 235impl From<Name> for ModPath {
358 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE]) 236 fn from(name: Name) -> ModPath {
237 ModPath::from_simple_segments(PathKind::Plain, iter::once(name))
359 } 238 }
239}
360 240
361 pub fn std_boxed_box() -> Path { 241pub use hir_expand::name as __name;
362 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE]) 242
363 } 243#[macro_export]
244macro_rules! __known_path {
245 (std::iter::IntoIterator) => {};
246 (std::result::Result) => {};
247 (std::ops::Range) => {};
248 (std::ops::RangeFrom) => {};
249 (std::ops::RangeFull) => {};
250 (std::ops::RangeTo) => {};
251 (std::ops::RangeToInclusive) => {};
252 (std::ops::RangeInclusive) => {};
253 (std::boxed::Box) => {};
254 (std::future::Future) => {};
255 (std::ops::Try) => {};
256 (std::ops::Neg) => {};
257 (std::ops::Not) => {};
258 ($path:path) => {
259 compile_error!("Please register your known path in the path module")
260 };
364} 261}
262
263#[macro_export]
264macro_rules! __path {
265 ($start:ident $(:: $seg:ident)*) => ({
266 $crate::__known_path!($start $(:: $seg)*);
267 $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![
268 $crate::path::__name![$start], $($crate::path::__name![$seg],)*
269 ])
270 });
271}
272
273pub use crate::__path as path;
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs
new file mode 100644
index 000000000..a2e995198
--- /dev/null
+++ b/crates/ra_hir_def/src/path/lower.rs
@@ -0,0 +1,176 @@
1//! Transforms syntax into `Path` objects, ideally with accounting for hygiene
2
3mod lower_use;
4
5use std::sync::Arc;
6
7use either::Either;
8use hir_expand::{
9 hygiene::Hygiene,
10 name::{name, AsName},
11};
12use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner};
13
14use crate::{
15 path::{GenericArg, GenericArgs, ModPath, Path, PathKind},
16 type_ref::TypeRef,
17};
18
19pub(super) use lower_use::lower_use_tree;
20
21/// Converts an `ast::Path` to `Path`. Works with use trees.
22/// It correctly handles `$crate` based path from macro call.
23pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
24 let mut kind = PathKind::Plain;
25 let mut segments = Vec::new();
26 let mut generic_args = Vec::new();
27 loop {
28 let segment = path.segment()?;
29
30 if segment.has_colon_colon() {
31 kind = PathKind::Abs;
32 }
33
34 match segment.kind()? {
35 ast::PathSegmentKind::Name(name_ref) => {
36 // FIXME: this should just return name
37 match hygiene.name_ref_to_name(name_ref) {
38 Either::Left(name) => {
39 let args = segment
40 .type_arg_list()
41 .and_then(lower_generic_args)
42 .or_else(|| {
43 lower_generic_args_from_fn_path(
44 segment.param_list(),
45 segment.ret_type(),
46 )
47 })
48 .map(Arc::new);
49 segments.push(name);
50 generic_args.push(args)
51 }
52 Either::Right(crate_id) => {
53 kind = PathKind::DollarCrate(crate_id);
54 break;
55 }
56 }
57 }
58 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
59 assert!(path.qualifier().is_none()); // this can only occur at the first segment
60
61 let self_type = TypeRef::from_ast(type_ref?);
62
63 match trait_ref {
64 // <T>::foo
65 None => {
66 kind = PathKind::Type(Box::new(self_type));
67 }
68 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
69 Some(trait_ref) => {
70 let path = Path::from_src(trait_ref.path()?, hygiene)?;
71 kind = path.mod_path.kind;
72
73 let mut prefix_segments = path.mod_path.segments;
74 prefix_segments.reverse();
75 segments.extend(prefix_segments);
76
77 let mut prefix_args = path.generic_args;
78 prefix_args.reverse();
79 generic_args.extend(prefix_args);
80
81 // Insert the type reference (T in the above example) as Self parameter for the trait
82 let last_segment = generic_args.last_mut()?;
83 if last_segment.is_none() {
84 *last_segment = Some(Arc::new(GenericArgs::empty()));
85 };
86 let args = last_segment.as_mut().unwrap();
87 let mut args_inner = Arc::make_mut(args);
88 args_inner.has_self_type = true;
89 args_inner.args.insert(0, GenericArg::Type(self_type));
90 }
91 }
92 }
93 ast::PathSegmentKind::CrateKw => {
94 kind = PathKind::Crate;
95 break;
96 }
97 ast::PathSegmentKind::SelfKw => {
98 kind = PathKind::Self_;
99 break;
100 }
101 ast::PathSegmentKind::SuperKw => {
102 kind = PathKind::Super;
103 break;
104 }
105 }
106 path = match qualifier(&path) {
107 Some(it) => it,
108 None => break,
109 };
110 }
111 segments.reverse();
112 generic_args.reverse();
113 let mod_path = ModPath { kind, segments };
114 return Some(Path { mod_path, generic_args });
115
116 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
117 if let Some(q) = path.qualifier() {
118 return Some(q);
119 }
120 // FIXME: this bottom up traversal is not too precise.
121 // Should we handle do a top-down analysis, recording results?
122 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
123 let use_tree = use_tree_list.parent_use_tree();
124 use_tree.path()
125 }
126}
127
128pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> {
129 let mut args = Vec::new();
130 for type_arg in node.type_args() {
131 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
132 args.push(GenericArg::Type(type_ref));
133 }
134 // lifetimes ignored for now
135 let mut bindings = Vec::new();
136 for assoc_type_arg in node.assoc_type_args() {
137 if let Some(name_ref) = assoc_type_arg.name_ref() {
138 let name = name_ref.as_name();
139 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
140 bindings.push((name, type_ref));
141 }
142 }
143 if args.is_empty() && bindings.is_empty() {
144 None
145 } else {
146 Some(GenericArgs { args, has_self_type: false, bindings })
147 }
148}
149
150/// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
151/// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
152fn lower_generic_args_from_fn_path(
153 params: Option<ast::ParamList>,
154 ret_type: Option<ast::RetType>,
155) -> Option<GenericArgs> {
156 let mut args = Vec::new();
157 let mut bindings = Vec::new();
158 if let Some(params) = params {
159 let mut param_types = Vec::new();
160 for param in params.params() {
161 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
162 param_types.push(type_ref);
163 }
164 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
165 args.push(arg);
166 }
167 if let Some(ret_type) = ret_type {
168 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
169 bindings.push((name![Output], type_ref))
170 }
171 if args.is_empty() && bindings.is_empty() {
172 None
173 } else {
174 Some(GenericArgs { args, has_self_type: false, bindings })
175 }
176}
diff --git a/crates/ra_hir_def/src/path/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs
index e2e1f716d..ea3fdb56c 100644
--- a/crates/ra_hir_def/src/path/lower_use.rs
+++ b/crates/ra_hir_def/src/path/lower/lower_use.rs
@@ -10,13 +10,13 @@ use hir_expand::{
10}; 10};
11use ra_syntax::ast::{self, NameOwner}; 11use ra_syntax::ast::{self, NameOwner};
12 12
13use crate::path::{Path, PathKind, PathSegment}; 13use crate::path::{ModPath, PathKind};
14 14
15pub(crate) fn lower_use_tree( 15pub(crate) fn lower_use_tree(
16 prefix: Option<Path>, 16 prefix: Option<ModPath>,
17 tree: ast::UseTree, 17 tree: ast::UseTree,
18 hygiene: &Hygiene, 18 hygiene: &Hygiene,
19 cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>), 19 cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option<Name>),
20) { 20) {
21 if let Some(use_tree_list) = tree.use_tree_list() { 21 if let Some(use_tree_list) = tree.use_tree_list() {
22 let prefix = match tree.path() { 22 let prefix = match tree.path() {
@@ -57,7 +57,7 @@ pub(crate) fn lower_use_tree(
57 } 57 }
58} 58}
59 59
60fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 60fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
61 let prefix = if let Some(qual) = path.qualifier() { 61 let prefix = if let Some(qual) = path.qualifier() {
62 Some(convert_path(prefix, qual, hygiene)?) 62 Some(convert_path(prefix, qual, hygiene)?)
63 } else { 63 } else {
@@ -70,18 +70,15 @@ fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Opt
70 match hygiene.name_ref_to_name(name_ref) { 70 match hygiene.name_ref_to_name(name_ref) {
71 Either::Left(name) => { 71 Either::Left(name) => {
72 // no type args in use 72 // no type args in use
73 let mut res = prefix.unwrap_or_else(|| Path { 73 let mut res = prefix.unwrap_or_else(|| ModPath {
74 kind: PathKind::Plain, 74 kind: PathKind::Plain,
75 segments: Vec::with_capacity(1), 75 segments: Vec::with_capacity(1),
76 }); 76 });
77 res.segments.push(PathSegment { 77 res.segments.push(name);
78 name,
79 args_and_bindings: None, // no type args in use
80 });
81 res 78 res
82 } 79 }
83 Either::Right(crate_id) => { 80 Either::Right(crate_id) => {
84 return Some(Path::from_simple_segments( 81 return Some(ModPath::from_simple_segments(
85 PathKind::DollarCrate(crate_id), 82 PathKind::DollarCrate(crate_id),
86 iter::empty(), 83 iter::empty(),
87 )) 84 ))
@@ -92,19 +89,19 @@ fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Opt
92 if prefix.is_some() { 89 if prefix.is_some() {
93 return None; 90 return None;
94 } 91 }
95 Path::from_simple_segments(PathKind::Crate, iter::empty()) 92 ModPath::from_simple_segments(PathKind::Crate, iter::empty())
96 } 93 }
97 ast::PathSegmentKind::SelfKw => { 94 ast::PathSegmentKind::SelfKw => {
98 if prefix.is_some() { 95 if prefix.is_some() {
99 return None; 96 return None;
100 } 97 }
101 Path::from_simple_segments(PathKind::Self_, iter::empty()) 98 ModPath::from_simple_segments(PathKind::Self_, iter::empty())
102 } 99 }
103 ast::PathSegmentKind::SuperKw => { 100 ast::PathSegmentKind::SuperKw => {
104 if prefix.is_some() { 101 if prefix.is_some() {
105 return None; 102 return None;
106 } 103 }
107 Path::from_simple_segments(PathKind::Super, iter::empty()) 104 ModPath::from_simple_segments(PathKind::Super, iter::empty())
108 } 105 }
109 ast::PathSegmentKind::Type { .. } => { 106 ast::PathSegmentKind::Type { .. } => {
110 // not allowed in imports 107 // not allowed in imports
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 17b2169d2..2694c0438 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -2,7 +2,7 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use hir_expand::{ 4use hir_expand::{
5 name::{self, Name}, 5 name::{name, Name},
6 MacroDefId, 6 MacroDefId,
7}; 7};
8use ra_db::CrateId; 8use ra_db::CrateId;
@@ -15,7 +15,7 @@ use crate::{
15 expr::{ExprId, PatId}, 15 expr::{ExprId, PatId},
16 generics::GenericParams, 16 generics::GenericParams,
17 nameres::{BuiltinShadowMode, CrateDefMap}, 17 nameres::{BuiltinShadowMode, CrateDefMap},
18 path::{Path, PathKind}, 18 path::{ModPath, PathKind},
19 per_ns::PerNs, 19 per_ns::PerNs,
20 AdtId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, 20 AdtId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId,
21 HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, 21 HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId,
@@ -91,7 +91,7 @@ pub enum ValueNs {
91 91
92impl Resolver { 92impl Resolver {
93 /// Resolve known trait from std, like `std::futures::Future` 93 /// Resolve known trait from std, like `std::futures::Future`
94 pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &Path) -> Option<TraitId> { 94 pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &ModPath) -> Option<TraitId> {
95 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; 95 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
96 match res { 96 match res {
97 ModuleDefId::TraitId(it) => Some(it), 97 ModuleDefId::TraitId(it) => Some(it),
@@ -100,7 +100,7 @@ impl Resolver {
100 } 100 }
101 101
102 /// Resolve known struct from std, like `std::boxed::Box` 102 /// Resolve known struct from std, like `std::boxed::Box`
103 pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &Path) -> Option<StructId> { 103 pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &ModPath) -> Option<StructId> {
104 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; 104 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
105 match res { 105 match res {
106 ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it), 106 ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it),
@@ -109,7 +109,7 @@ impl Resolver {
109 } 109 }
110 110
111 /// Resolve known enum from std, like `std::result::Result` 111 /// Resolve known enum from std, like `std::result::Result`
112 pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &Path) -> Option<EnumId> { 112 pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &ModPath) -> Option<EnumId> {
113 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; 113 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
114 match res { 114 match res {
115 ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it), 115 ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it),
@@ -120,33 +120,30 @@ impl Resolver {
120 fn resolve_module_path( 120 fn resolve_module_path(
121 &self, 121 &self,
122 db: &impl DefDatabase, 122 db: &impl DefDatabase,
123 path: &Path, 123 path: &ModPath,
124 shadow: BuiltinShadowMode, 124 shadow: BuiltinShadowMode,
125 ) -> PerNs { 125 ) -> PerNs {
126 let (item_map, module) = match self.module() { 126 let (item_map, module) = match self.module() {
127 Some(it) => it, 127 Some(it) => it,
128 None => return PerNs::none(), 128 None => return PerNs::none(),
129 }; 129 };
130 let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow); 130 let (module_res, segment_index) = item_map.resolve_path(db, module, &path, shadow);
131 if segment_index.is_some() { 131 if segment_index.is_some() {
132 return PerNs::none(); 132 return PerNs::none();
133 } 133 }
134 module_res 134 module_res
135 } 135 }
136 136
137 pub fn resolve_module_path_in_items(&self, db: &impl DefDatabase, path: &Path) -> PerNs { 137 pub fn resolve_module_path_in_items(&self, db: &impl DefDatabase, path: &ModPath) -> PerNs {
138 self.resolve_module_path(db, path, BuiltinShadowMode::Module) 138 self.resolve_module_path(db, path, BuiltinShadowMode::Module)
139 } 139 }
140 140
141 pub fn resolve_path_in_type_ns( 141 pub fn resolve_path_in_type_ns(
142 &self, 142 &self,
143 db: &impl DefDatabase, 143 db: &impl DefDatabase,
144 path: &Path, 144 path: &ModPath,
145 ) -> Option<(TypeNs, Option<usize>)> { 145 ) -> Option<(TypeNs, Option<usize>)> {
146 if path.is_type_relative() { 146 let first_name = path.segments.first()?;
147 return None;
148 }
149 let first_name = &path.segments.first()?.name;
150 let skip_to_mod = path.kind != PathKind::Plain; 147 let skip_to_mod = path.kind != PathKind::Plain;
151 for scope in self.scopes.iter().rev() { 148 for scope in self.scopes.iter().rev() {
152 match scope { 149 match scope {
@@ -163,13 +160,13 @@ impl Resolver {
163 } 160 }
164 } 161 }
165 Scope::ImplBlockScope(impl_) => { 162 Scope::ImplBlockScope(impl_) => {
166 if first_name == &name::SELF_TYPE { 163 if first_name == &name![Self] {
167 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 164 let idx = if path.segments.len() == 1 { None } else { Some(1) };
168 return Some((TypeNs::SelfType(*impl_), idx)); 165 return Some((TypeNs::SelfType(*impl_), idx));
169 } 166 }
170 } 167 }
171 Scope::AdtScope(adt) => { 168 Scope::AdtScope(adt) => {
172 if first_name == &name::SELF_TYPE { 169 if first_name == &name![Self] {
173 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 170 let idx = if path.segments.len() == 1 { None } else { Some(1) };
174 return Some((TypeNs::AdtSelfType(*adt), idx)); 171 return Some((TypeNs::AdtSelfType(*adt), idx));
175 } 172 }
@@ -178,7 +175,7 @@ impl Resolver {
178 let (module_def, idx) = m.crate_def_map.resolve_path( 175 let (module_def, idx) = m.crate_def_map.resolve_path(
179 db, 176 db,
180 m.module_id, 177 m.module_id,
181 path, 178 &path,
182 BuiltinShadowMode::Other, 179 BuiltinShadowMode::Other,
183 ); 180 );
184 let res = match module_def.take_types()? { 181 let res = match module_def.take_types()? {
@@ -205,7 +202,7 @@ impl Resolver {
205 pub fn resolve_path_in_type_ns_fully( 202 pub fn resolve_path_in_type_ns_fully(
206 &self, 203 &self,
207 db: &impl DefDatabase, 204 db: &impl DefDatabase,
208 path: &Path, 205 path: &ModPath,
209 ) -> Option<TypeNs> { 206 ) -> Option<TypeNs> {
210 let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; 207 let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?;
211 if unresolved.is_some() { 208 if unresolved.is_some() {
@@ -214,17 +211,14 @@ impl Resolver {
214 Some(res) 211 Some(res)
215 } 212 }
216 213
217 pub fn resolve_path_in_value_ns<'p>( 214 pub fn resolve_path_in_value_ns(
218 &self, 215 &self,
219 db: &impl DefDatabase, 216 db: &impl DefDatabase,
220 path: &'p Path, 217 path: &ModPath,
221 ) -> Option<ResolveValueResult> { 218 ) -> Option<ResolveValueResult> {
222 if path.is_type_relative() {
223 return None;
224 }
225 let n_segments = path.segments.len(); 219 let n_segments = path.segments.len();
226 let tmp = name::SELF_PARAM; 220 let tmp = name![self];
227 let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; 221 let first_name = if path.is_self() { &tmp } else { &path.segments.first()? };
228 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); 222 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
229 for scope in self.scopes.iter().rev() { 223 for scope in self.scopes.iter().rev() {
230 match scope { 224 match scope {
@@ -259,13 +253,13 @@ impl Resolver {
259 Scope::GenericParams { .. } => continue, 253 Scope::GenericParams { .. } => continue,
260 254
261 Scope::ImplBlockScope(impl_) if n_segments > 1 => { 255 Scope::ImplBlockScope(impl_) if n_segments > 1 => {
262 if first_name == &name::SELF_TYPE { 256 if first_name == &name![Self] {
263 let ty = TypeNs::SelfType(*impl_); 257 let ty = TypeNs::SelfType(*impl_);
264 return Some(ResolveValueResult::Partial(ty, 1)); 258 return Some(ResolveValueResult::Partial(ty, 1));
265 } 259 }
266 } 260 }
267 Scope::AdtScope(adt) if n_segments > 1 => { 261 Scope::AdtScope(adt) if n_segments > 1 => {
268 if first_name == &name::SELF_TYPE { 262 if first_name == &name![Self] {
269 let ty = TypeNs::AdtSelfType(*adt); 263 let ty = TypeNs::AdtSelfType(*adt);
270 return Some(ResolveValueResult::Partial(ty, 1)); 264 return Some(ResolveValueResult::Partial(ty, 1));
271 } 265 }
@@ -276,7 +270,7 @@ impl Resolver {
276 let (module_def, idx) = m.crate_def_map.resolve_path( 270 let (module_def, idx) = m.crate_def_map.resolve_path(
277 db, 271 db,
278 m.module_id, 272 m.module_id,
279 path, 273 &path,
280 BuiltinShadowMode::Other, 274 BuiltinShadowMode::Other,
281 ); 275 );
282 return match idx { 276 return match idx {
@@ -322,7 +316,7 @@ impl Resolver {
322 pub fn resolve_path_in_value_ns_fully( 316 pub fn resolve_path_in_value_ns_fully(
323 &self, 317 &self,
324 db: &impl DefDatabase, 318 db: &impl DefDatabase,
325 path: &Path, 319 path: &ModPath,
326 ) -> Option<ValueNs> { 320 ) -> Option<ValueNs> {
327 match self.resolve_path_in_value_ns(db, path)? { 321 match self.resolve_path_in_value_ns(db, path)? {
328 ResolveValueResult::ValueNs(it) => Some(it), 322 ResolveValueResult::ValueNs(it) => Some(it),
@@ -330,9 +324,13 @@ impl Resolver {
330 } 324 }
331 } 325 }
332 326
333 pub fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> { 327 pub fn resolve_path_as_macro(
328 &self,
329 db: &impl DefDatabase,
330 path: &ModPath,
331 ) -> Option<MacroDefId> {
334 let (item_map, module) = self.module()?; 332 let (item_map, module) = self.module()?;
335 item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros() 333 item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros()
336 } 334 }
337 335
338 pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) { 336 pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
@@ -439,10 +437,10 @@ impl Scope {
439 } 437 }
440 } 438 }
441 Scope::ImplBlockScope(i) => { 439 Scope::ImplBlockScope(i) => {
442 f(name::SELF_TYPE, ScopeDef::ImplSelfType((*i).into())); 440 f(name![Self], ScopeDef::ImplSelfType((*i).into()));
443 } 441 }
444 Scope::AdtScope(i) => { 442 Scope::AdtScope(i) => {
445 f(name::SELF_TYPE, ScopeDef::AdtSelfType((*i).into())); 443 f(name![Self], ScopeDef::AdtSelfType((*i).into()));
446 } 444 }
447 Scope::ExprScope(scope) => { 445 Scope::ExprScope(scope) => {
448 scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { 446 scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| {
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index 574637602..b26441253 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -12,10 +12,10 @@ use crate::db::AstDatabase;
12use crate::{name, quote, MacroCallId, MacroDefId, MacroDefKind}; 12use crate::{name, quote, MacroCallId, MacroDefId, MacroDefKind};
13 13
14macro_rules! register_builtin { 14macro_rules! register_builtin {
15 ( $(($name:ident, $kind: ident) => $expand:ident),* ) => { 15 ( $($trait:ident => $expand:ident),* ) => {
16 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 16 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17 pub enum BuiltinDeriveExpander { 17 pub enum BuiltinDeriveExpander {
18 $($kind),* 18 $($trait),*
19 } 19 }
20 20
21 impl BuiltinDeriveExpander { 21 impl BuiltinDeriveExpander {
@@ -26,7 +26,7 @@ macro_rules! register_builtin {
26 tt: &tt::Subtree, 26 tt: &tt::Subtree,
27 ) -> Result<tt::Subtree, mbe::ExpandError> { 27 ) -> Result<tt::Subtree, mbe::ExpandError> {
28 let expander = match *self { 28 let expander = match *self {
29 $( BuiltinDeriveExpander::$kind => $expand, )* 29 $( BuiltinDeriveExpander::$trait => $expand, )*
30 }; 30 };
31 expander(db, id, tt) 31 expander(db, id, tt)
32 } 32 }
@@ -34,7 +34,7 @@ macro_rules! register_builtin {
34 34
35 pub fn find_builtin_derive(ident: &name::Name) -> Option<MacroDefId> { 35 pub fn find_builtin_derive(ident: &name::Name) -> Option<MacroDefId> {
36 let kind = match ident { 36 let kind = match ident {
37 $( id if id == &name::$name => BuiltinDeriveExpander::$kind, )* 37 $( id if id == &name::name![$trait] => BuiltinDeriveExpander::$trait, )*
38 _ => return None, 38 _ => return None,
39 }; 39 };
40 40
@@ -44,15 +44,15 @@ macro_rules! register_builtin {
44} 44}
45 45
46register_builtin! { 46register_builtin! {
47 (COPY_TRAIT, Copy) => copy_expand, 47 Copy => copy_expand,
48 (CLONE_TRAIT, Clone) => clone_expand, 48 Clone => clone_expand,
49 (DEFAULT_TRAIT, Default) => default_expand, 49 Default => default_expand,
50 (DEBUG_TRAIT, Debug) => debug_expand, 50 Debug => debug_expand,
51 (HASH_TRAIT, Hash) => hash_expand, 51 Hash => hash_expand,
52 (ORD_TRAIT, Ord) => ord_expand, 52 Ord => ord_expand,
53 (PARTIAL_ORD_TRAIT, PartialOrd) => partial_ord_expand, 53 PartialOrd => partial_ord_expand,
54 (EQ_TRAIT, Eq) => eq_expand, 54 Eq => eq_expand,
55 (PARTIAL_EQ_TRAIT, PartialEq) => partial_eq_expand 55 PartialEq => partial_eq_expand
56} 56}
57 57
58struct BasicAdtInfo { 58struct BasicAdtInfo {
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index be5f3cbe3..d2b3d769e 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -34,7 +34,7 @@ macro_rules! register_builtin {
34 ast_id: AstId<ast::MacroCall>, 34 ast_id: AstId<ast::MacroCall>,
35 ) -> Option<MacroDefId> { 35 ) -> Option<MacroDefId> {
36 let kind = match ident { 36 let kind = match ident {
37 $( id if id == &name::$name => BuiltinFnLikeExpander::$kind, )* 37 $( id if id == &name::name![$name] => BuiltinFnLikeExpander::$kind, )*
38 _ => return None, 38 _ => return None,
39 }; 39 };
40 40
@@ -44,15 +44,15 @@ macro_rules! register_builtin {
44} 44}
45 45
46register_builtin! { 46register_builtin! {
47 (COLUMN_MACRO, Column) => column_expand, 47 (column, Column) => column_expand,
48 (COMPILE_ERROR_MACRO, CompileError) => compile_error_expand, 48 (compile_error, CompileError) => compile_error_expand,
49 (FILE_MACRO, File) => file_expand, 49 (file, File) => file_expand,
50 (LINE_MACRO, Line) => line_expand, 50 (line, Line) => line_expand,
51 (STRINGIFY_MACRO, Stringify) => stringify_expand, 51 (stringify, Stringify) => stringify_expand,
52 (FORMAT_ARGS_MACRO, FormatArgs) => format_args_expand, 52 (format_args, FormatArgs) => format_args_expand,
53 // format_args_nl only differs in that it adds a newline in the end, 53 // format_args_nl only differs in that it adds a newline in the end,
54 // so we use the same stub expansion for now 54 // so we use the same stub expansion for now
55 (FORMAT_ARGS_NL_MACRO, FormatArgsNl) => format_args_expand 55 (format_args_nl, FormatArgsNl) => format_args_expand
56} 56}
57 57
58fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { 58fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 9e68dd98d..59d8214fd 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -104,73 +104,99 @@ impl AsName for ra_db::Dependency {
104 } 104 }
105} 105}
106 106
107// Primitives 107pub mod known {
108pub const ISIZE: Name = Name::new_inline_ascii(b"isize"); 108 macro_rules! known_names {
109pub const I8: Name = Name::new_inline_ascii(b"i8"); 109 ($($ident:ident),* $(,)?) => {
110pub const I16: Name = Name::new_inline_ascii(b"i16"); 110 $(
111pub const I32: Name = Name::new_inline_ascii(b"i32"); 111 #[allow(bad_style)]
112pub const I64: Name = Name::new_inline_ascii(b"i64"); 112 pub const $ident: super::Name =
113pub const I128: Name = Name::new_inline_ascii(b"i128"); 113 super::Name::new_inline_ascii(stringify!($ident).as_bytes());
114pub const USIZE: Name = Name::new_inline_ascii(b"usize"); 114 )*
115pub const U8: Name = Name::new_inline_ascii(b"u8"); 115 };
116pub const U16: Name = Name::new_inline_ascii(b"u16"); 116 }
117pub const U32: Name = Name::new_inline_ascii(b"u32"); 117
118pub const U64: Name = Name::new_inline_ascii(b"u64"); 118 known_names!(
119pub const U128: Name = Name::new_inline_ascii(b"u128"); 119 // Primitives
120pub const F32: Name = Name::new_inline_ascii(b"f32"); 120 isize,
121pub const F64: Name = Name::new_inline_ascii(b"f64"); 121 i8,
122pub const BOOL: Name = Name::new_inline_ascii(b"bool"); 122 i16,
123pub const CHAR: Name = Name::new_inline_ascii(b"char"); 123 i32,
124pub const STR: Name = Name::new_inline_ascii(b"str"); 124 i64,
125 125 i128,
126// Special names 126 usize,
127pub const SELF_PARAM: Name = Name::new_inline_ascii(b"self"); 127 u8,
128pub const SELF_TYPE: Name = Name::new_inline_ascii(b"Self"); 128 u16,
129pub const MACRO_RULES: Name = Name::new_inline_ascii(b"macro_rules"); 129 u32,
130 130 u64,
131// Components of known path (value or mod name) 131 u128,
132pub const STD: Name = Name::new_inline_ascii(b"std"); 132 f32,
133pub const ITER: Name = Name::new_inline_ascii(b"iter"); 133 f64,
134pub const OPS: Name = Name::new_inline_ascii(b"ops"); 134 bool,
135pub const FUTURE: Name = Name::new_inline_ascii(b"future"); 135 char,
136pub const RESULT: Name = Name::new_inline_ascii(b"result"); 136 str,
137pub const BOXED: Name = Name::new_inline_ascii(b"boxed"); 137 // Special names
138 138 macro_rules,
139// Components of known path (type name) 139 // Components of known path (value or mod name)
140pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(b"IntoIterator"); 140 std,
141pub const ITEM_TYPE: Name = Name::new_inline_ascii(b"Item"); 141 iter,
142pub const TRY_TYPE: Name = Name::new_inline_ascii(b"Try"); 142 ops,
143pub const OK_TYPE: Name = Name::new_inline_ascii(b"Ok"); 143 future,
144pub const FUTURE_TYPE: Name = Name::new_inline_ascii(b"Future"); 144 result,
145pub const RESULT_TYPE: Name = Name::new_inline_ascii(b"Result"); 145 boxed,
146pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(b"Output"); 146 // Components of known path (type name)
147pub const TARGET_TYPE: Name = Name::new_inline_ascii(b"Target"); 147 IntoIterator,
148pub const BOX_TYPE: Name = Name::new_inline_ascii(b"Box"); 148 Item,
149pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(b"RangeFrom"); 149 Try,
150pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(b"RangeFull"); 150 Ok,
151pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeInclusive"); 151 Future,
152pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive"); 152 Result,
153pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo"); 153 Output,
154pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range"); 154 Target,
155pub const NEG_TYPE: Name = Name::new_inline_ascii(b"Neg"); 155 Box,
156pub const NOT_TYPE: Name = Name::new_inline_ascii(b"Not"); 156 RangeFrom,
157 157 RangeFull,
158// Builtin Macros 158 RangeInclusive,
159pub const FILE_MACRO: Name = Name::new_inline_ascii(b"file"); 159 RangeToInclusive,
160pub const COLUMN_MACRO: Name = Name::new_inline_ascii(b"column"); 160 RangeTo,
161pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(b"compile_error"); 161 Range,
162pub const LINE_MACRO: Name = Name::new_inline_ascii(b"line"); 162 Neg,
163pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(b"stringify"); 163 Not,
164pub const FORMAT_ARGS_MACRO: Name = Name::new_inline_ascii(b"format_args"); 164 // Builtin macros
165pub const FORMAT_ARGS_NL_MACRO: Name = Name::new_inline_ascii(b"format_args_nl"); 165 file,
166 166 column,
167// Builtin derives 167 compile_error,
168pub const COPY_TRAIT: Name = Name::new_inline_ascii(b"Copy"); 168 line,
169pub const CLONE_TRAIT: Name = Name::new_inline_ascii(b"Clone"); 169 stringify,
170pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(b"Default"); 170 format_args,
171pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(b"Debug"); 171 format_args_nl,
172pub const HASH_TRAIT: Name = Name::new_inline_ascii(b"Hash"); 172 // Builtin derives
173pub const ORD_TRAIT: Name = Name::new_inline_ascii(b"Ord"); 173 Copy,
174pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(b"PartialOrd"); 174 Clone,
175pub const EQ_TRAIT: Name = Name::new_inline_ascii(b"Eq"); 175 Default,
176pub const PARTIAL_EQ_TRAIT: Name = Name::new_inline_ascii(b"PartialEq"); 176 Debug,
177 Hash,
178 Ord,
179 PartialOrd,
180 Eq,
181 PartialEq,
182 );
183
184 // self/Self cannot be used as an identifier
185 pub const SELF_PARAM: super::Name = super::Name::new_inline_ascii(b"self");
186 pub const SELF_TYPE: super::Name = super::Name::new_inline_ascii(b"Self");
187
188 #[macro_export]
189 macro_rules! name {
190 (self) => {
191 $crate::name::known::SELF_PARAM
192 };
193 (Self) => {
194 $crate::name::known::SELF_TYPE
195 };
196 ($ident:ident) => {
197 $crate::name::known::$ident
198 };
199 }
200}
201
202pub use crate::name;
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs
index d557962b4..ee48fa537 100644
--- a/crates/ra_hir_ty/src/autoderef.rs
+++ b/crates/ra_hir_ty/src/autoderef.rs
@@ -6,7 +6,7 @@
6use std::iter::successors; 6use std::iter::successors;
7 7
8use hir_def::lang_item::LangItemTarget; 8use hir_def::lang_item::LangItemTarget;
9use hir_expand::name; 9use hir_expand::name::name;
10use log::{info, warn}; 10use log::{info, warn};
11use ra_db::CrateId; 11use ra_db::CrateId;
12 12
@@ -52,7 +52,7 @@ fn deref_by_trait(
52 LangItemTarget::TraitId(it) => it, 52 LangItemTarget::TraitId(it) => it,
53 _ => return None, 53 _ => return None,
54 }; 54 };
55 let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?; 55 let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
56 56
57 let generic_params = generics(db, target.into()); 57 let generic_params = generics(db, target.into());
58 if generic_params.len() != 1 { 58 if generic_params.len() != 1 {
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index d2bd64e5c..f752a9f09 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -3,7 +3,7 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{ 5use hir_def::{
6 path::{known, Path}, 6 path::{path, Path},
7 resolver::HasResolver, 7 resolver::HasResolver,
8 AdtId, FunctionId, 8 AdtId, FunctionId,
9}; 9};
@@ -124,7 +124,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
124 None => return, 124 None => return,
125 }; 125 };
126 126
127 let std_result_path = known::std_result_result(); 127 let std_result_path = path![std::result::Result];
128 128
129 let resolver = self.func.resolver(db); 129 let resolver = self.func.resolver(db);
130 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { 130 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) {
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index a1201b3e4..98ba05fc2 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -24,14 +24,15 @@ use hir_def::{
24 body::Body, 24 body::Body,
25 data::{ConstData, FunctionData}, 25 data::{ConstData, FunctionData},
26 expr::{BindingAnnotation, ExprId, PatId}, 26 expr::{BindingAnnotation, ExprId, PatId},
27 path::{known, Path}, 27 path::{path, Path},
28 resolver::{HasResolver, Resolver, TypeNs}, 28 resolver::{HasResolver, Resolver, TypeNs},
29 type_ref::{Mutability, TypeRef}, 29 type_ref::{Mutability, TypeRef},
30 AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId, 30 AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId,
31}; 31};
32use hir_expand::{diagnostics::DiagnosticSink, name}; 32use hir_expand::{diagnostics::DiagnosticSink, name::name};
33use ra_arena::map::ArenaMap; 33use ra_arena::map::ArenaMap;
34use ra_prof::profile; 34use ra_prof::profile;
35use test_utils::tested_by;
35 36
36use super::{ 37use super::{
37 primitive::{FloatTy, IntTy}, 38 primitive::{FloatTy, IntTy},
@@ -274,6 +275,29 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
274 self.normalize_associated_types_in(ty) 275 self.normalize_associated_types_in(ty)
275 } 276 }
276 277
278 /// Replaces `impl Trait` in `ty` by type variables and obligations for
279 /// those variables. This is done for function arguments when calling a
280 /// function, and for return types when inside the function body, i.e. in
281 /// the cases where the `impl Trait` is 'transparent'. In other cases, `impl
282 /// Trait` is represented by `Ty::Opaque`.
283 fn insert_vars_for_impl_trait(&mut self, ty: Ty) -> Ty {
284 ty.fold(&mut |ty| match ty {
285 Ty::Opaque(preds) => {
286 tested_by!(insert_vars_for_impl_trait);
287 let var = self.table.new_type_var();
288 let var_subst = Substs::builder(1).push(var.clone()).build();
289 self.obligations.extend(
290 preds
291 .iter()
292 .map(|pred| pred.clone().subst_bound_vars(&var_subst))
293 .filter_map(Obligation::from_predicate),
294 );
295 var
296 }
297 _ => ty,
298 })
299 }
300
277 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. 301 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
278 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 302 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
279 match ty { 303 match ty {
@@ -386,7 +410,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
386 let resolver = &self.resolver; 410 let resolver = &self.resolver;
387 // FIXME: this should resolve assoc items as well, see this example: 411 // FIXME: this should resolve assoc items as well, see this example:
388 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 412 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
389 match resolver.resolve_path_in_type_ns_fully(self.db, &path) { 413 match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) {
390 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { 414 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => {
391 let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into()); 415 let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into());
392 let ty = self.db.ty(strukt.into()); 416 let ty = self.db.ty(strukt.into());
@@ -414,7 +438,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
414 438
415 self.infer_pat(*pat, &ty, BindingMode::default()); 439 self.infer_pat(*pat, &ty, BindingMode::default());
416 } 440 }
417 self.return_ty = self.make_ty(&data.ret_type); 441 let return_ty = self.make_ty(&data.ret_type);
442 self.return_ty = self.insert_vars_for_impl_trait(return_ty);
418 } 443 }
419 444
420 fn infer_body(&mut self) { 445 fn infer_body(&mut self) {
@@ -422,73 +447,73 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
422 } 447 }
423 448
424 fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { 449 fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
425 let path = known::std_iter_into_iterator(); 450 let path = path![std::iter::IntoIterator];
426 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 451 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
427 self.db.trait_data(trait_).associated_type_by_name(&name::ITEM_TYPE) 452 self.db.trait_data(trait_).associated_type_by_name(&name![Item])
428 } 453 }
429 454
430 fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { 455 fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
431 let path = known::std_ops_try(); 456 let path = path![std::ops::Try];
432 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 457 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
433 self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE) 458 self.db.trait_data(trait_).associated_type_by_name(&name![Ok])
434 } 459 }
435 460
436 fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { 461 fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
437 let path = known::std_ops_neg(); 462 let path = path![std::ops::Neg];
438 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 463 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
439 self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) 464 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
440 } 465 }
441 466
442 fn resolve_ops_not_output(&self) -> Option<TypeAliasId> { 467 fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
443 let path = known::std_ops_not(); 468 let path = path![std::ops::Not];
444 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 469 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
445 self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) 470 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
446 } 471 }
447 472
448 fn resolve_future_future_output(&self) -> Option<TypeAliasId> { 473 fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
449 let path = known::std_future_future(); 474 let path = path![std::future::Future];
450 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 475 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
451 self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) 476 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
452 } 477 }
453 478
454 fn resolve_boxed_box(&self) -> Option<AdtId> { 479 fn resolve_boxed_box(&self) -> Option<AdtId> {
455 let path = known::std_boxed_box(); 480 let path = path![std::boxed::Box];
456 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 481 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
457 Some(struct_.into()) 482 Some(struct_.into())
458 } 483 }
459 484
460 fn resolve_range_full(&self) -> Option<AdtId> { 485 fn resolve_range_full(&self) -> Option<AdtId> {
461 let path = known::std_ops_range_full(); 486 let path = path![std::ops::RangeFull];
462 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 487 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
463 Some(struct_.into()) 488 Some(struct_.into())
464 } 489 }
465 490
466 fn resolve_range(&self) -> Option<AdtId> { 491 fn resolve_range(&self) -> Option<AdtId> {
467 let path = known::std_ops_range(); 492 let path = path![std::ops::Range];
468 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 493 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
469 Some(struct_.into()) 494 Some(struct_.into())
470 } 495 }
471 496
472 fn resolve_range_inclusive(&self) -> Option<AdtId> { 497 fn resolve_range_inclusive(&self) -> Option<AdtId> {
473 let path = known::std_ops_range_inclusive(); 498 let path = path![std::ops::RangeInclusive];
474 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 499 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
475 Some(struct_.into()) 500 Some(struct_.into())
476 } 501 }
477 502
478 fn resolve_range_from(&self) -> Option<AdtId> { 503 fn resolve_range_from(&self) -> Option<AdtId> {
479 let path = known::std_ops_range_from(); 504 let path = path![std::ops::RangeFrom];
480 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 505 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
481 Some(struct_.into()) 506 Some(struct_.into())
482 } 507 }
483 508
484 fn resolve_range_to(&self) -> Option<AdtId> { 509 fn resolve_range_to(&self) -> Option<AdtId> {
485 let path = known::std_ops_range_to(); 510 let path = path![std::ops::RangeTo];
486 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 511 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
487 Some(struct_.into()) 512 Some(struct_.into())
488 } 513 }
489 514
490 fn resolve_range_to_inclusive(&self) -> Option<AdtId> { 515 fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
491 let path = known::std_ops_range_to_inclusive(); 516 let path = path![std::ops::RangeToInclusive];
492 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 517 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
493 Some(struct_.into()) 518 Some(struct_.into())
494 } 519 }
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index f8c00a7b4..924ad3e81 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -10,7 +10,7 @@ use hir_def::{
10 resolver::resolver_for_expr, 10 resolver::resolver_for_expr,
11 AdtId, ContainerId, Lookup, StructFieldId, 11 AdtId, ContainerId, Lookup, StructFieldId,
12}; 12};
13use hir_expand::name::{self, Name}; 13use hir_expand::name::{name, Name};
14use ra_syntax::ast::RangeOp; 14use ra_syntax::ast::RangeOp;
15 15
16use crate::{ 16use crate::{
@@ -613,6 +613,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
613 continue; 613 continue;
614 } 614 }
615 615
616 let param_ty = self.insert_vars_for_impl_trait(param_ty);
616 let param_ty = self.normalize_associated_types_in(param_ty); 617 let param_ty = self.normalize_associated_types_in(param_ty);
617 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); 618 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
618 } 619 }
@@ -631,7 +632,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
631 // Parent arguments are unknown, except for the receiver type 632 // Parent arguments are unknown, except for the receiver type
632 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { 633 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
633 for (_id, param) in parent_generics { 634 for (_id, param) in parent_generics {
634 if param.name == name::SELF_TYPE { 635 if param.name == name![Self] {
635 substs.push(receiver_ty.clone()); 636 substs.push(receiver_ty.clone());
636 } else { 637 } else {
637 substs.push(Ty::Unknown); 638 substs.push(Ty::Unknown);
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs
index 37db005ea..3bae0ca6c 100644
--- a/crates/ra_hir_ty/src/infer/path.rs
+++ b/crates/ra_hir_ty/src/infer/path.rs
@@ -32,21 +32,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
32 path: &Path, 32 path: &Path,
33 id: ExprOrPatId, 33 id: ExprOrPatId,
34 ) -> Option<Ty> { 34 ) -> Option<Ty> {
35 let (value, self_subst) = if let PathKind::Type(type_ref) = &path.kind { 35 let (value, self_subst) = if let PathKind::Type(type_ref) = path.kind() {
36 if path.segments.is_empty() { 36 if path.segments().is_empty() {
37 // This can't actually happen syntax-wise 37 // This can't actually happen syntax-wise
38 return None; 38 return None;
39 } 39 }
40 let ty = self.make_ty(type_ref); 40 let ty = self.make_ty(type_ref);
41 let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1]; 41 let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
42 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); 42 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty);
43 self.resolve_ty_assoc_item( 43 self.resolve_ty_assoc_item(
44 ty, 44 ty,
45 &path.segments.last().expect("path had at least one segment").name, 45 &path.segments().last().expect("path had at least one segment").name,
46 id, 46 id,
47 )? 47 )?
48 } else { 48 } else {
49 let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; 49 let value_or_partial = resolver.resolve_path_in_value_ns(self.db, path.mod_path())?;
50 50
51 match value_or_partial { 51 match value_or_partial {
52 ResolveValueResult::ValueNs(it) => (it, None), 52 ResolveValueResult::ValueNs(it) => (it, None),
@@ -85,13 +85,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
85 remaining_index: usize, 85 remaining_index: usize,
86 id: ExprOrPatId, 86 id: ExprOrPatId,
87 ) -> Option<(ValueNs, Option<Substs>)> { 87 ) -> Option<(ValueNs, Option<Substs>)> {
88 assert!(remaining_index < path.segments.len()); 88 assert!(remaining_index < path.segments().len());
89 // there may be more intermediate segments between the resolved one and 89 // there may be more intermediate segments between the resolved one and
90 // the end. Only the last segment needs to be resolved to a value; from 90 // the end. Only the last segment needs to be resolved to a value; from
91 // the segments before that, we need to get either a type or a trait ref. 91 // the segments before that, we need to get either a type or a trait ref.
92 92
93 let resolved_segment = &path.segments[remaining_index - 1]; 93 let resolved_segment = path.segments().get(remaining_index - 1).unwrap();
94 let remaining_segments = &path.segments[remaining_index..]; 94 let remaining_segments = path.segments().skip(remaining_index);
95 let is_before_last = remaining_segments.len() == 1; 95 let is_before_last = remaining_segments.len() == 1;
96 96
97 match (def, is_before_last) { 97 match (def, is_before_last) {
@@ -112,7 +112,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
112 // trait but it's not the last segment, so the next segment 112 // trait but it's not the last segment, so the next segment
113 // should resolve to an associated type of that trait (e.g. `<T 113 // should resolve to an associated type of that trait (e.g. `<T
114 // as Iterator>::Item::default`) 114 // as Iterator>::Item::default`)
115 let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1]; 115 let remaining_segments_for_ty =
116 remaining_segments.take(remaining_segments.len() - 1);
116 let ty = Ty::from_partly_resolved_hir_path( 117 let ty = Ty::from_partly_resolved_hir_path(
117 self.db, 118 self.db,
118 &self.resolver, 119 &self.resolver,
@@ -138,7 +139,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
138 fn resolve_trait_assoc_item( 139 fn resolve_trait_assoc_item(
139 &mut self, 140 &mut self,
140 trait_ref: TraitRef, 141 trait_ref: TraitRef,
141 segment: &PathSegment, 142 segment: PathSegment<'_>,
142 id: ExprOrPatId, 143 id: ExprOrPatId,
143 ) -> Option<(ValueNs, Option<Substs>)> { 144 ) -> Option<(ValueNs, Option<Substs>)> {
144 let trait_ = trait_ref.trait_; 145 let trait_ = trait_ref.trait_;
@@ -150,7 +151,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
150 .map(|(_name, id)| (*id).into()) 151 .map(|(_name, id)| (*id).into())
151 .find_map(|item| match item { 152 .find_map(|item| match item {
152 AssocItemId::FunctionId(func) => { 153 AssocItemId::FunctionId(func) => {
153 if segment.name == self.db.function_data(func).name { 154 if segment.name == &self.db.function_data(func).name {
154 Some(AssocItemId::FunctionId(func)) 155 Some(AssocItemId::FunctionId(func))
155 } else { 156 } else {
156 None 157 None
@@ -158,7 +159,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
158 } 159 }
159 160
160 AssocItemId::ConstId(konst) => { 161 AssocItemId::ConstId(konst) => {
161 if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == &segment.name) 162 if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == segment.name)
162 { 163 {
163 Some(AssocItemId::ConstId(konst)) 164 Some(AssocItemId::ConstId(konst))
164 } else { 165 } else {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 5f795bc02..a4ddfc8ef 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -11,7 +11,7 @@ use std::sync::Arc;
11use hir_def::{ 11use hir_def::{
12 builtin_type::BuiltinType, 12 builtin_type::BuiltinType,
13 generics::WherePredicate, 13 generics::WherePredicate,
14 path::{GenericArg, Path, PathKind, PathSegment}, 14 path::{GenericArg, Path, PathKind, PathSegment, PathSegments},
15 resolver::{HasResolver, Resolver, TypeNs}, 15 resolver::{HasResolver, Resolver, TypeNs},
16 type_ref::{TypeBound, TypeRef}, 16 type_ref::{TypeBound, TypeRef},
17 AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, 17 AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
@@ -101,13 +101,13 @@ impl Ty {
101 TypeRef::Path(path) => path, 101 TypeRef::Path(path) => path,
102 _ => return None, 102 _ => return None,
103 }; 103 };
104 if let PathKind::Type(_) = &path.kind { 104 if let PathKind::Type(_) = path.kind() {
105 return None; 105 return None;
106 } 106 }
107 if path.segments.len() > 1 { 107 if path.segments().len() > 1 {
108 return None; 108 return None;
109 } 109 }
110 let resolution = match resolver.resolve_path_in_type_ns(db, path) { 110 let resolution = match resolver.resolve_path_in_type_ns(db, path.mod_path()) {
111 Some((it, None)) => it, 111 Some((it, None)) => it,
112 _ => return None, 112 _ => return None,
113 }; 113 };
@@ -124,11 +124,11 @@ impl Ty {
124 db: &impl HirDatabase, 124 db: &impl HirDatabase,
125 resolver: &Resolver, 125 resolver: &Resolver,
126 ty: Ty, 126 ty: Ty,
127 remaining_segments: &[PathSegment], 127 remaining_segments: PathSegments<'_>,
128 ) -> Ty { 128 ) -> Ty {
129 if remaining_segments.len() == 1 { 129 if remaining_segments.len() == 1 {
130 // resolve unselected assoc types 130 // resolve unselected assoc types
131 let segment = &remaining_segments[0]; 131 let segment = remaining_segments.first().unwrap();
132 Ty::select_associated_type(db, resolver, ty, segment) 132 Ty::select_associated_type(db, resolver, ty, segment)
133 } else if remaining_segments.len() > 1 { 133 } else if remaining_segments.len() > 1 {
134 // FIXME report error (ambiguous associated type) 134 // FIXME report error (ambiguous associated type)
@@ -142,15 +142,15 @@ impl Ty {
142 db: &impl HirDatabase, 142 db: &impl HirDatabase,
143 resolver: &Resolver, 143 resolver: &Resolver,
144 resolution: TypeNs, 144 resolution: TypeNs,
145 resolved_segment: &PathSegment, 145 resolved_segment: PathSegment<'_>,
146 remaining_segments: &[PathSegment], 146 remaining_segments: PathSegments<'_>,
147 ) -> Ty { 147 ) -> Ty {
148 let ty = match resolution { 148 let ty = match resolution {
149 TypeNs::TraitId(trait_) => { 149 TypeNs::TraitId(trait_) => {
150 let trait_ref = 150 let trait_ref =
151 TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None); 151 TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None);
152 return if remaining_segments.len() == 1 { 152 return if remaining_segments.len() == 1 {
153 let segment = &remaining_segments[0]; 153 let segment = remaining_segments.first().unwrap();
154 let associated_ty = associated_type_by_name_including_super_traits( 154 let associated_ty = associated_type_by_name_including_super_traits(
155 db, 155 db,
156 trait_ref.trait_, 156 trait_ref.trait_,
@@ -202,21 +202,21 @@ impl Ty {
202 202
203 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { 203 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
204 // Resolve the path (in type namespace) 204 // Resolve the path (in type namespace)
205 if let PathKind::Type(type_ref) = &path.kind { 205 if let PathKind::Type(type_ref) = path.kind() {
206 let ty = Ty::from_hir(db, resolver, &type_ref); 206 let ty = Ty::from_hir(db, resolver, &type_ref);
207 let remaining_segments = &path.segments[..]; 207 return Ty::from_type_relative_path(db, resolver, ty, path.segments());
208 return Ty::from_type_relative_path(db, resolver, ty, remaining_segments);
209 } 208 }
210 let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { 209 let (resolution, remaining_index) =
211 Some(it) => it, 210 match resolver.resolve_path_in_type_ns(db, path.mod_path()) {
212 None => return Ty::Unknown, 211 Some(it) => it,
213 }; 212 None => return Ty::Unknown,
213 };
214 let (resolved_segment, remaining_segments) = match remaining_index { 214 let (resolved_segment, remaining_segments) = match remaining_index {
215 None => ( 215 None => (
216 path.segments.last().expect("resolved path has at least one element"), 216 path.segments().last().expect("resolved path has at least one element"),
217 &[] as &[PathSegment], 217 PathSegments::EMPTY,
218 ), 218 ),
219 Some(i) => (&path.segments[i - 1], &path.segments[i..]), 219 Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
220 }; 220 };
221 Ty::from_partly_resolved_hir_path( 221 Ty::from_partly_resolved_hir_path(
222 db, 222 db,
@@ -231,7 +231,7 @@ impl Ty {
231 db: &impl HirDatabase, 231 db: &impl HirDatabase,
232 resolver: &Resolver, 232 resolver: &Resolver,
233 self_ty: Ty, 233 self_ty: Ty,
234 segment: &PathSegment, 234 segment: PathSegment<'_>,
235 ) -> Ty { 235 ) -> Ty {
236 let param_idx = match self_ty { 236 let param_idx = match self_ty {
237 Ty::Param { idx, .. } => idx, 237 Ty::Param { idx, .. } => idx,
@@ -261,7 +261,7 @@ impl Ty {
261 fn from_hir_path_inner( 261 fn from_hir_path_inner(
262 db: &impl HirDatabase, 262 db: &impl HirDatabase,
263 resolver: &Resolver, 263 resolver: &Resolver,
264 segment: &PathSegment, 264 segment: PathSegment<'_>,
265 typable: TyDefId, 265 typable: TyDefId,
266 ) -> Ty { 266 ) -> Ty {
267 let generic_def = match typable { 267 let generic_def = match typable {
@@ -284,7 +284,7 @@ impl Ty {
284 // special-case enum variants 284 // special-case enum variants
285 resolved: ValueTyDefId, 285 resolved: ValueTyDefId,
286 ) -> Substs { 286 ) -> Substs {
287 let last = path.segments.last().expect("path should have at least one segment"); 287 let last = path.segments().last().expect("path should have at least one segment");
288 let (segment, generic_def) = match resolved { 288 let (segment, generic_def) = match resolved {
289 ValueTyDefId::FunctionId(it) => (last, Some(it.into())), 289 ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
290 ValueTyDefId::StructId(it) => (last, Some(it.into())), 290 ValueTyDefId::StructId(it) => (last, Some(it.into())),
@@ -296,13 +296,11 @@ impl Ty {
296 // referring to the variant. So `Option::<T>::None` and 296 // referring to the variant. So `Option::<T>::None` and
297 // `Option::None::<T>` are both allowed (though the former is 297 // `Option::None::<T>` are both allowed (though the former is
298 // preferred). See also `def_ids_for_path_segments` in rustc. 298 // preferred). See also `def_ids_for_path_segments` in rustc.
299 let len = path.segments.len(); 299 let len = path.segments().len();
300 let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() { 300 let penultimate = if len >= 2 { path.segments().get(len - 2) } else { None };
301 // Option::<T>::None 301 let segment = match penultimate {
302 &path.segments[len - 2] 302 Some(segment) if segment.args_and_bindings.is_some() => segment,
303 } else { 303 _ => last,
304 // Option::None::<T>
305 last
306 }; 304 };
307 (segment, Some(var.parent.into())) 305 (segment, Some(var.parent.into()))
308 } 306 }
@@ -314,7 +312,7 @@ impl Ty {
314pub(super) fn substs_from_path_segment( 312pub(super) fn substs_from_path_segment(
315 db: &impl HirDatabase, 313 db: &impl HirDatabase,
316 resolver: &Resolver, 314 resolver: &Resolver,
317 segment: &PathSegment, 315 segment: PathSegment<'_>,
318 def_generic: Option<GenericDefId>, 316 def_generic: Option<GenericDefId>,
319 add_self_param: bool, 317 add_self_param: bool,
320) -> Substs { 318) -> Substs {
@@ -372,11 +370,11 @@ impl TraitRef {
372 path: &Path, 370 path: &Path,
373 explicit_self_ty: Option<Ty>, 371 explicit_self_ty: Option<Ty>,
374 ) -> Option<Self> { 372 ) -> Option<Self> {
375 let resolved = match resolver.resolve_path_in_type_ns_fully(db, &path)? { 373 let resolved = match resolver.resolve_path_in_type_ns_fully(db, path.mod_path())? {
376 TypeNs::TraitId(tr) => tr, 374 TypeNs::TraitId(tr) => tr,
377 _ => return None, 375 _ => return None,
378 }; 376 };
379 let segment = path.segments.last().expect("path should have at least one segment"); 377 let segment = path.segments().last().expect("path should have at least one segment");
380 Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty)) 378 Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty))
381 } 379 }
382 380
@@ -384,7 +382,7 @@ impl TraitRef {
384 db: &impl HirDatabase, 382 db: &impl HirDatabase,
385 resolver: &Resolver, 383 resolver: &Resolver,
386 resolved: TraitId, 384 resolved: TraitId,
387 segment: &PathSegment, 385 segment: PathSegment<'_>,
388 explicit_self_ty: Option<Ty>, 386 explicit_self_ty: Option<Ty>,
389 ) -> Self { 387 ) -> Self {
390 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); 388 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved);
@@ -410,7 +408,7 @@ impl TraitRef {
410 fn substs_from_path( 408 fn substs_from_path(
411 db: &impl HirDatabase, 409 db: &impl HirDatabase,
412 resolver: &Resolver, 410 resolver: &Resolver,
413 segment: &PathSegment, 411 segment: PathSegment<'_>,
414 resolved: TraitId, 412 resolved: TraitId,
415 ) -> Substs { 413 ) -> Substs {
416 let has_self_param = 414 let has_self_param =
@@ -464,12 +462,12 @@ fn assoc_type_bindings_from_type_bound<'a>(
464 trait_ref: TraitRef, 462 trait_ref: TraitRef,
465) -> impl Iterator<Item = GenericPredicate> + 'a { 463) -> impl Iterator<Item = GenericPredicate> + 'a {
466 let last_segment = match bound { 464 let last_segment = match bound {
467 TypeBound::Path(path) => path.segments.last(), 465 TypeBound::Path(path) => path.segments().last(),
468 TypeBound::Error => None, 466 TypeBound::Error => None,
469 }; 467 };
470 last_segment 468 last_segment
471 .into_iter() 469 .into_iter()
472 .flat_map(|segment| segment.args_and_bindings.iter()) 470 .flat_map(|segment| segment.args_and_bindings.into_iter())
473 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) 471 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
474 .map(move |(name, type_ref)| { 472 .map(move |(name, type_ref)| {
475 let associated_ty = 473 let associated_ty =
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs
index 0f754eb9c..fe74acf11 100644
--- a/crates/ra_hir_ty/src/marks.rs
+++ b/crates/ra_hir_ty/src/marks.rs
@@ -6,4 +6,5 @@ test_utils::marks!(
6 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
7 match_ergonomics_ref 7 match_ergonomics_ref
8 coerce_merge_fail_fallback 8 coerce_merge_fail_fallback
9 insert_vars_for_impl_trait
9); 10);
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 6139adb72..802937cb0 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1,7 +1,10 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot; 1use insta::assert_snapshot;
2
4use ra_db::fixture::WithFixture; 3use ra_db::fixture::WithFixture;
4use test_utils::covers;
5
6use super::{infer, infer_with_mismatches, type_at, type_at_pos};
7use crate::test_db::TestDB;
5 8
6#[test] 9#[test]
7fn infer_await() { 10fn infer_await() {
@@ -1486,3 +1489,61 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
1486 // this is a legitimate cycle 1489 // this is a legitimate cycle
1487 assert_eq!(t, "{unknown}"); 1490 assert_eq!(t, "{unknown}");
1488} 1491}
1492
1493#[test]
1494fn unify_impl_trait() {
1495 covers!(insert_vars_for_impl_trait);
1496 assert_snapshot!(
1497 infer_with_mismatches(r#"
1498trait Trait<T> {}
1499
1500fn foo(x: impl Trait<u32>) { loop {} }
1501fn bar<T>(x: impl Trait<T>) -> T { loop {} }
1502
1503struct S<T>(T);
1504impl<T> Trait<T> for S<T> {}
1505
1506fn default<T>() -> T { loop {} }
1507
1508fn test() -> impl Trait<i32> {
1509 let s1 = S(default());
1510 foo(s1);
1511 let x: i32 = bar(S(default()));
1512 S(default())
1513}
1514"#, true),
1515 @r###"
1516 [27; 28) 'x': impl Trait<u32>
1517 [47; 58) '{ loop {} }': ()
1518 [49; 56) 'loop {}': !
1519 [54; 56) '{}': ()
1520 [69; 70) 'x': impl Trait<T>
1521 [92; 103) '{ loop {} }': T
1522 [94; 101) 'loop {}': !
1523 [99; 101) '{}': ()
1524 [172; 183) '{ loop {} }': T
1525 [174; 181) 'loop {}': !
1526 [179; 181) '{}': ()
1527 [214; 310) '{ ...t()) }': S<i32>
1528 [224; 226) 's1': S<u32>
1529 [229; 230) 'S': S<u32>(T) -> S<T>
1530 [229; 241) 'S(default())': S<u32>
1531 [231; 238) 'default': fn default<u32>() -> T
1532 [231; 240) 'default()': u32
1533 [247; 250) 'foo': fn foo(impl Trait<u32>) -> ()
1534 [247; 254) 'foo(s1)': ()
1535 [251; 253) 's1': S<u32>
1536 [264; 265) 'x': i32
1537 [273; 276) 'bar': fn bar<i32>(impl Trait<T>) -> T
1538 [273; 290) 'bar(S(...lt()))': i32
1539 [277; 278) 'S': S<i32>(T) -> S<T>
1540 [277; 289) 'S(default())': S<i32>
1541 [279; 286) 'default': fn default<i32>() -> T
1542 [279; 288) 'default()': i32
1543 [296; 297) 'S': S<i32>(T) -> S<T>
1544 [296; 308) 'S(default())': S<i32>
1545 [298; 305) 'default': fn default<i32>() -> T
1546 [298; 307) 'default()': i32
1547 "###
1548 );
1549}
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
index 598fd81e3..cd587a338 100644
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -1,7 +1,7 @@
1//! This module provides the built-in trait implementations, e.g. to make 1//! This module provides the built-in trait implementations, e.g. to make
2//! closures implement `Fn`. 2//! closures implement `Fn`.
3use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId}; 3use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId};
4use hir_expand::name; 4use hir_expand::name::name;
5use ra_db::CrateId; 5use ra_db::CrateId;
6 6
7use super::{AssocTyValue, Impl}; 7use super::{AssocTyValue, Impl};
@@ -79,7 +79,7 @@ fn closure_fn_trait_impl_datum(
79 // and don't want to return a valid value only to find out later that FnOnce 79 // and don't want to return a valid value only to find out later that FnOnce
80 // is broken 80 // is broken
81 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; 81 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
82 let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?; 82 let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
83 83
84 let num_args: u16 = match &db.body(data.def.into())[data.expr] { 84 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
85 Expr::Lambda { args, .. } => args.len() as u16, 85 Expr::Lambda { args, .. } => args.len() as u16,
@@ -137,7 +137,7 @@ fn closure_fn_trait_output_assoc_ty_value(
137 137
138 let output_ty_id = db 138 let output_ty_id = db
139 .trait_data(fn_once_trait) 139 .trait_data(fn_once_trait)
140 .associated_type_by_name(&name::OUTPUT_TYPE) 140 .associated_type_by_name(&name![Output])
141 .expect("assoc ty value should not exist"); 141 .expect("assoc ty value should not exist");
142 142
143 BuiltinImplAssocTyValueData { 143 BuiltinImplAssocTyValueData {
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index aeb211a91..29799a8cb 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -6,14 +6,13 @@ use hir_def::{
6 adt::VariantData, 6 adt::VariantData,
7 db::DefDatabase, 7 db::DefDatabase,
8 generics::{GenericParams, TypeParamData}, 8 generics::{GenericParams, TypeParamData},
9 path::Path,
9 resolver::{HasResolver, TypeNs}, 10 resolver::{HasResolver, TypeNs},
10 type_ref::TypeRef, 11 type_ref::TypeRef,
11 ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, 12 ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
12}; 13};
13use hir_expand::name::{self, Name}; 14use hir_expand::name::{name, Name};
14 15
15// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`.
16// We should return a `TraitREf` here.
17fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> { 16fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
18 let resolver = trait_.resolver(db); 17 let resolver = trait_.resolver(db);
19 // returning the iterator directly doesn't easily work because of 18 // returning the iterator directly doesn't easily work because of
@@ -24,10 +23,10 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
24 .where_predicates 23 .where_predicates
25 .iter() 24 .iter()
26 .filter_map(|pred| match &pred.type_ref { 25 .filter_map(|pred| match &pred.type_ref {
27 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(), 26 TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(),
28 _ => None, 27 _ => None,
29 }) 28 })
30 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { 29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
31 Some(TypeNs::TraitId(t)) => Some(t), 30 Some(TypeNs::TraitId(t)) => Some(t),
32 _ => None, 31 _ => None,
33 }) 32 })
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index ca0a483d4..981da2b79 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -188,10 +188,9 @@ impl<'a> CompletionContext<'a> {
188 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 188 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
189 self.has_type_args = segment.type_arg_list().is_some(); 189 self.has_type_args = segment.type_arg_list().is_some();
190 190
191 if let Some(mut path) = hir::Path::from_ast(path.clone()) { 191 if let Some(path) = hir::Path::from_ast(path.clone()) {
192 if !path.is_ident() { 192 if let Some(path_prefix) = path.qualifier() {
193 path.segments.pop().unwrap(); 193 self.path_prefix = Some(path_prefix);
194 self.path_prefix = Some(path);
195 return; 194 return;
196 } 195 }
197 } 196 }
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index 2c634990d..bee8e9df2 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -3,7 +3,9 @@
3use hir::{db::AstDatabase, InFile}; 3use hir::{db::AstDatabase, InFile};
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, DocCommentsOwner}, 5 ast::{self, DocCommentsOwner},
6 match_ast, AstNode, SyntaxNode, 6 match_ast, AstNode,
7 SyntaxKind::*,
8 SyntaxNode, SyntaxToken, TokenAtOffset,
7}; 9};
8 10
9use crate::{ 11use crate::{
@@ -19,8 +21,7 @@ pub(crate) fn goto_definition(
19 position: FilePosition, 21 position: FilePosition,
20) -> Option<RangeInfo<Vec<NavigationTarget>>> { 22) -> Option<RangeInfo<Vec<NavigationTarget>>> {
21 let file = db.parse_or_expand(position.file_id.into())?; 23 let file = db.parse_or_expand(position.file_id.into())?;
22 let original_token = 24 let original_token = pick_best(file.token_at_offset(position.offset))?;
23 file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?;
24 let token = descend_into_macros(db, position.file_id, original_token.clone()); 25 let token = descend_into_macros(db, position.file_id, original_token.clone());
25 26
26 let nav_targets = match_ast! { 27 let nav_targets = match_ast! {
@@ -38,6 +39,17 @@ pub(crate) fn goto_definition(
38 Some(RangeInfo::new(original_token.text_range(), nav_targets)) 39 Some(RangeInfo::new(original_token.text_range(), nav_targets))
39} 40}
40 41
42fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
43 return tokens.max_by_key(priority);
44 fn priority(n: &SyntaxToken) -> usize {
45 match n.kind() {
46 IDENT | INT_NUMBER => 2,
47 kind if kind.is_trivia() => 0,
48 _ => 1,
49 }
50 }
51}
52
41#[derive(Debug)] 53#[derive(Debug)]
42pub(crate) enum ReferenceResult { 54pub(crate) enum ReferenceResult {
43 Exact(NavigationTarget), 55 Exact(NavigationTarget),
@@ -253,6 +265,18 @@ mod tests {
253 } 265 }
254 266
255 #[test] 267 #[test]
268 fn goto_definition_works_at_start_of_item() {
269 check_goto(
270 "
271 //- /lib.rs
272 struct Foo;
273 enum E { X(<|>Foo) }
274 ",
275 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
276 );
277 }
278
279 #[test]
256 fn goto_definition_resolves_correct_name() { 280 fn goto_definition_resolves_correct_name() {
257 check_goto( 281 check_goto(
258 " 282 "
@@ -453,6 +477,22 @@ mod tests {
453 } 477 }
454 478
455 #[test] 479 #[test]
480 fn goto_for_tuple_fields() {
481 check_goto(
482 "
483 //- /lib.rs
484 struct Foo(u32);
485
486 fn bar() {
487 let foo = Foo(0);
488 foo.<|>0;
489 }
490 ",
491 "TUPLE_FIELD_DEF FileId(1) [11; 14)",
492 );
493 }
494
495 #[test]
456 fn goto_definition_works_for_ufcs_inherent_methods() { 496 fn goto_definition_works_for_ufcs_inherent_methods() {
457 check_goto( 497 check_goto(
458 " 498 "
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs
index 992a08809..ce8b6c72a 100644
--- a/crates/ra_ide/src/goto_type_definition.rs
+++ b/crates/ra_ide/src/goto_type_definition.rs
@@ -1,7 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::db::AstDatabase; 3use hir::db::AstDatabase;
4use ra_syntax::{ast, AstNode}; 4use ra_syntax::{ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset};
5 5
6use crate::{ 6use crate::{
7 db::RootDatabase, display::ToNav, expand::descend_into_macros, FilePosition, NavigationTarget, 7 db::RootDatabase, display::ToNav, expand::descend_into_macros, FilePosition, NavigationTarget,
@@ -13,7 +13,7 @@ pub(crate) fn goto_type_definition(
13 position: FilePosition, 13 position: FilePosition,
14) -> Option<RangeInfo<Vec<NavigationTarget>>> { 14) -> Option<RangeInfo<Vec<NavigationTarget>>> {
15 let file = db.parse_or_expand(position.file_id.into())?; 15 let file = db.parse_or_expand(position.file_id.into())?;
16 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; 16 let token = pick_best(file.token_at_offset(position.offset))?;
17 let token = descend_into_macros(db, position.file_id, token); 17 let token = descend_into_macros(db, position.file_id, token);
18 18
19 let node = token.value.ancestors().find_map(|token| { 19 let node = token.value.ancestors().find_map(|token| {
@@ -41,6 +41,17 @@ pub(crate) fn goto_type_definition(
41 Some(RangeInfo::new(node.text_range(), vec![nav])) 41 Some(RangeInfo::new(node.text_range(), vec![nav]))
42} 42}
43 43
44fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
45 return tokens.max_by_key(priority);
46 fn priority(n: &SyntaxToken) -> usize {
47 match n.kind() {
48 IDENT | INT_NUMBER => 2,
49 kind if kind.is_trivia() => 0,
50 _ => 1,
51 }
52 }
53}
54
44#[cfg(test)] 55#[cfg(test)]
45mod tests { 56mod tests {
46 use crate::mock_analysis::analysis_and_position; 57 use crate::mock_analysis::analysis_and_position;
@@ -102,4 +113,32 @@ mod tests {
102 "Foo STRUCT_DEF FileId(1) [52; 65) [59; 62)", 113 "Foo STRUCT_DEF FileId(1) [52; 65) [59; 62)",
103 ); 114 );
104 } 115 }
116
117 #[test]
118 fn goto_type_definition_for_param() {
119 check_goto(
120 "
121 //- /lib.rs
122 struct Foo;
123 fn foo(<|>f: Foo) {}
124 ",
125 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
126 );
127 }
128
129 #[test]
130 fn goto_type_definition_for_tuple_field() {
131 check_goto(
132 "
133 //- /lib.rs
134 struct Foo;
135 struct Bar(Foo);
136 fn foo() {
137 let bar = Bar(Foo);
138 bar.<|>0;
139 }
140 ",
141 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
142 );
143 }
105} 144}
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index d372ca758..51e320128 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -6,6 +6,8 @@ use ra_syntax::{
6 algo::find_covering_element, 6 algo::find_covering_element,
7 ast::{self, DocCommentsOwner}, 7 ast::{self, DocCommentsOwner},
8 match_ast, AstNode, 8 match_ast, AstNode,
9 SyntaxKind::*,
10 SyntaxToken, TokenAtOffset,
9}; 11};
10 12
11use crate::{ 13use crate::{
@@ -156,7 +158,7 @@ fn hover_text_from_name_kind(
156 158
157pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { 159pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
158 let file = db.parse_or_expand(position.file_id.into())?; 160 let file = db.parse_or_expand(position.file_id.into())?;
159 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; 161 let token = pick_best(file.token_at_offset(position.offset))?;
160 let token = descend_into_macros(db, position.file_id, token); 162 let token = descend_into_macros(db, position.file_id, token);
161 163
162 let mut res = HoverResult::new(); 164 let mut res = HoverResult::new();
@@ -218,6 +220,18 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
218 Some(RangeInfo::new(range, res)) 220 Some(RangeInfo::new(range, res))
219} 221}
220 222
223fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
224 return tokens.max_by_key(priority);
225 fn priority(n: &SyntaxToken) -> usize {
226 match n.kind() {
227 IDENT | INT_NUMBER => 3,
228 L_PAREN | R_PAREN => 2,
229 kind if kind.is_trivia() => 0,
230 _ => 1,
231 }
232 }
233}
234
221pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { 235pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
222 let parse = db.parse(frange.file_id); 236 let parse = db.parse(frange.file_id);
223 let leaf_node = find_covering_element(parse.tree().syntax(), frange.range); 237 let leaf_node = find_covering_element(parse.tree().syntax(), frange.range);
@@ -505,6 +519,13 @@ fn func(foo: i32) { if true { <|>foo; }; }
505 } 519 }
506 520
507 #[test] 521 #[test]
522 fn hover_for_param_edge() {
523 let (analysis, position) = single_file_with_position("fn func(<|>foo: i32) {}");
524 let hover = analysis.hover(position).unwrap().unwrap();
525 assert_eq!(trim_markup_opt(hover.info.first()), Some("i32"));
526 }
527
528 #[test]
508 fn test_type_of_for_function() { 529 fn test_type_of_for_function() {
509 let (analysis, range) = single_file_with_range( 530 let (analysis, range) = single_file_with_range(
510 " 531 "
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index 4166a8f90..40605d9ef 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -10,8 +10,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
10.builtin { color: #DD6718; } 10.builtin { color: #DD6718; }
11.text { color: #DCDCCC; } 11.text { color: #DCDCCC; }
12.type { color: #7CB8BB; } 12.type { color: #7CB8BB; }
13.type\.param { color: #20999D; }
13.attribute { color: #94BFF3; } 14.attribute { color: #94BFF3; }
14.literal { color: #BFEBBF; } 15.literal { color: #BFEBBF; }
16.literal\.numeric { color: #6A8759; }
15.macro { color: #94BFF3; } 17.macro { color: #94BFF3; }
16.variable { color: #DCDCCC; } 18.variable { color: #DCDCCC; }
17.variable\.mut { color: #DCDCCC; text-decoration: underline; } 19.variable\.mut { color: #DCDCCC; text-decoration: underline; }
@@ -22,36 +24,36 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
22</style> 24</style>
23<pre><code><span class="attribute">#</span><span class="attribute">[</span><span class="attribute">derive</span><span class="attribute">(</span><span class="attribute">Clone</span><span class="attribute">,</span><span class="attribute"> </span><span class="attribute">Debug</span><span class="attribute">)</span><span class="attribute">]</span> 25<pre><code><span class="attribute">#</span><span class="attribute">[</span><span class="attribute">derive</span><span class="attribute">(</span><span class="attribute">Clone</span><span class="attribute">,</span><span class="attribute"> </span><span class="attribute">Debug</span><span class="attribute">)</span><span class="attribute">]</span>
24<span class="keyword">struct</span> <span class="type">Foo</span> { 26<span class="keyword">struct</span> <span class="type">Foo</span> {
25 <span class="keyword">pub</span> <span class="field">x</span>: <span class="type">i32</span>, 27 <span class="keyword">pub</span> <span class="field">x</span>: <span class="type.builtin">i32</span>,
26 <span class="keyword">pub</span> <span class="field">y</span>: <span class="type">i32</span>, 28 <span class="keyword">pub</span> <span class="field">y</span>: <span class="type.builtin">i32</span>,
27} 29}
28 30
29<span class="keyword">fn</span> <span class="function">foo</span>&lt;<span class="type">T</span>&gt;() -&gt; <span class="type">T</span> { 31<span class="keyword">fn</span> <span class="function">foo</span>&lt;<span class="type.param">T</span>&gt;() -&gt; <span class="type.param">T</span> {
30 <span class="macro">unimplemented</span><span class="macro">!</span>(); 32 <span class="macro">unimplemented</span><span class="macro">!</span>();
31 <span class="function">foo</span>::&lt;<span class="type">i32</span>&gt;(); 33 <span class="function">foo</span>::&lt;<span class="type.builtin">i32</span>&gt;();
32} 34}
33 35
34<span class="comment">// comment</span> 36<span class="comment">// comment</span>
35<span class="keyword">fn</span> <span class="function">main</span>() { 37<span class="keyword">fn</span> <span class="function">main</span>() {
36 <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Hello, {}!"</span>, <span class="literal">92</span>); 38 <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Hello, {}!"</span>, <span class="literal.numeric">92</span>);
37 39
38 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>(); 40 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>();
39 <span class="keyword.control">if</span> <span class="keyword">true</span> { 41 <span class="keyword.control">if</span> <span class="keyword">true</span> {
40 <span class="variable.mut">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field">x</span>: <span class="literal">0</span>, <span class="field">y</span>: <span class="literal">1</span> }); 42 <span class="variable.mut">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field">x</span>: <span class="literal.numeric">0</span>, <span class="field">y</span>: <span class="literal.numeric">1</span> });
41 } 43 }
42 <span class="keyword.unsafe">unsafe</span> { <span class="variable.mut">vec</span>.<span class="text">set_len</span>(<span class="literal">0</span>); } 44 <span class="keyword.unsafe">unsafe</span> { <span class="variable.mut">vec</span>.<span class="text">set_len</span>(<span class="literal.numeric">0</span>); }
43 45
44 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">x</span> = <span class="literal">42</span>; 46 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">x</span> = <span class="literal.numeric">42</span>;
45 <span class="keyword">let</span> <span class="variable.mut">y</span> = &<span class="keyword">mut</span> <span class="variable.mut">x</span>; 47 <span class="keyword">let</span> <span class="variable.mut">y</span> = &<span class="keyword">mut</span> <span class="variable.mut">x</span>;
46 <span class="keyword">let</span> <span class="variable">z</span> = &<span class="variable.mut">y</span>; 48 <span class="keyword">let</span> <span class="variable">z</span> = &<span class="variable.mut">y</span>;
47 49
48 <span class="variable.mut">y</span>; 50 <span class="variable.mut">y</span>;
49} 51}
50 52
51<span class="keyword">enum</span> <span class="type">E</span>&lt;<span class="type">X</span>&gt; { 53<span class="keyword">enum</span> <span class="type">E</span>&lt;<span class="type.param">X</span>&gt; {
52 <span class="constant">V</span>(<span class="type">X</span>) 54 <span class="constant">V</span>(<span class="type.param">X</span>)
53} 55}
54 56
55<span class="keyword">impl</span>&lt;<span class="type">X</span>&gt; <span class="type">E</span>&lt;<span class="type">X</span>&gt; { 57<span class="keyword">impl</span>&lt;<span class="type.param">X</span>&gt; <span class="type">E</span>&lt;<span class="type.param">X</span>&gt; {
56 <span class="keyword">fn</span> <span class="function">new</span>&lt;<span class="type">T</span>&gt;() -&gt; <span class="type">E</span>&lt;<span class="type">T</span>&gt; {} 58 <span class="keyword">fn</span> <span class="function">new</span>&lt;<span class="type.param">T</span>&gt;() -&gt; <span class="type">E</span>&lt;<span class="type.param">T</span>&gt; {}
57}</code></pre> \ No newline at end of file 59}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index 9dfbc8047..ecf26c708 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -10,8 +10,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
10.builtin { color: #DD6718; } 10.builtin { color: #DD6718; }
11.text { color: #DCDCCC; } 11.text { color: #DCDCCC; }
12.type { color: #7CB8BB; } 12.type { color: #7CB8BB; }
13.type\.param { color: #20999D; }
13.attribute { color: #94BFF3; } 14.attribute { color: #94BFF3; }
14.literal { color: #BFEBBF; } 15.literal { color: #BFEBBF; }
16.literal\.numeric { color: #6A8759; }
15.macro { color: #94BFF3; } 17.macro { color: #94BFF3; }
16.variable { color: #DCDCCC; } 18.variable { color: #DCDCCC; }
17.variable\.mut { color: #DCDCCC; text-decoration: underline; } 19.variable\.mut { color: #DCDCCC; text-decoration: underline; }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 7ecb1a027..eb3dd1779 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -16,6 +16,34 @@ use crate::{
16 FileId, 16 FileId,
17}; 17};
18 18
19pub mod tags {
20 pub(crate) const FIELD: &'static str = "field";
21 pub(crate) const FUNCTION: &'static str = "function";
22 pub(crate) const MODULE: &'static str = "module";
23 pub(crate) const TYPE: &'static str = "type";
24 pub(crate) const CONSTANT: &'static str = "constant";
25 pub(crate) const MACRO: &'static str = "macro";
26 pub(crate) const VARIABLE: &'static str = "variable";
27 pub(crate) const VARIABLE_MUT: &'static str = "variable.mut";
28 pub(crate) const TEXT: &'static str = "text";
29
30 pub(crate) const TYPE_BUILTIN: &'static str = "type.builtin";
31 pub(crate) const TYPE_SELF: &'static str = "type.self";
32 pub(crate) const TYPE_PARAM: &'static str = "type.param";
33 pub(crate) const TYPE_LIFETIME: &'static str = "type.lifetime";
34
35 pub(crate) const LITERAL_BYTE: &'static str = "literal.byte";
36 pub(crate) const LITERAL_NUMERIC: &'static str = "literal.numeric";
37 pub(crate) const LITERAL_CHAR: &'static str = "literal.char";
38 pub(crate) const LITERAL_COMMENT: &'static str = "comment";
39 pub(crate) const LITERAL_STRING: &'static str = "string";
40 pub(crate) const LITERAL_ATTRIBUTE: &'static str = "attribute";
41
42 pub(crate) const KEYWORD_UNSAFE: &'static str = "keyword.unsafe";
43 pub(crate) const KEYWORD_CONTROL: &'static str = "keyword.control";
44 pub(crate) const KEYWORD: &'static str = "keyword";
45}
46
19#[derive(Debug)] 47#[derive(Debug)]
20pub struct HighlightedRange { 48pub struct HighlightedRange {
21 pub range: TextRange, 49 pub range: TextRange,
@@ -71,9 +99,9 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
71 bindings_shadow_count.clear(); 99 bindings_shadow_count.clear();
72 continue; 100 continue;
73 } 101 }
74 COMMENT => "comment", 102 COMMENT => tags::LITERAL_COMMENT,
75 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", 103 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => tags::LITERAL_STRING,
76 ATTR => "attribute", 104 ATTR => tags::LITERAL_ATTRIBUTE,
77 NAME_REF => { 105 NAME_REF => {
78 if node.ancestors().any(|it| it.kind() == ATTR) { 106 if node.ancestors().any(|it| it.kind() == ATTR) {
79 continue; 107 continue;
@@ -90,7 +118,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
90 } 118 }
91 }; 119 };
92 120
93 name_kind.map_or("text", |it| highlight_name(db, it)) 121 name_kind.map_or(tags::TEXT, |it| highlight_name(db, it))
94 } 122 }
95 NAME => { 123 NAME => {
96 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); 124 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
@@ -107,18 +135,21 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
107 135
108 match name_kind { 136 match name_kind {
109 Some(name_kind) => highlight_name(db, name_kind), 137 Some(name_kind) => highlight_name(db, name_kind),
110 None => name.syntax().parent().map_or("function", |x| match x.kind() { 138 None => name.syntax().parent().map_or(tags::FUNCTION, |x| match x.kind() {
111 TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type", 139 STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => tags::TYPE,
112 RECORD_FIELD_DEF => "field", 140 TYPE_PARAM => tags::TYPE_PARAM,
113 _ => "function", 141 RECORD_FIELD_DEF => tags::FIELD,
142 _ => tags::FUNCTION,
114 }), 143 }),
115 } 144 }
116 } 145 }
117 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", 146 INT_NUMBER | FLOAT_NUMBER => tags::LITERAL_NUMERIC,
118 LIFETIME => "parameter", 147 BYTE => tags::LITERAL_BYTE,
119 T![unsafe] => "keyword.unsafe", 148 CHAR => tags::LITERAL_CHAR,
120 k if is_control_keyword(k) => "keyword.control", 149 LIFETIME => tags::TYPE_LIFETIME,
121 k if k.is_keyword() => "keyword", 150 T![unsafe] => tags::KEYWORD_UNSAFE,
151 k if is_control_keyword(k) => tags::KEYWORD_CONTROL,
152 k if k.is_keyword() => tags::KEYWORD,
122 _ => { 153 _ => {
123 if let Some(macro_call) = node.as_node().cloned().and_then(ast::MacroCall::cast) { 154 if let Some(macro_call) = node.as_node().cloned().and_then(ast::MacroCall::cast) {
124 if let Some(path) = macro_call.path() { 155 if let Some(path) = macro_call.path() {
@@ -135,7 +166,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
135 } 166 }
136 res.push(HighlightedRange { 167 res.push(HighlightedRange {
137 range: TextRange::from_to(range_start, range_end), 168 range: TextRange::from_to(range_start, range_end),
138 tag: "macro", 169 tag: tags::MACRO,
139 binding_hash: None, 170 binding_hash: None,
140 }) 171 })
141 } 172 }
@@ -211,28 +242,29 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
211 242
212fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str { 243fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
213 match name_kind { 244 match name_kind {
214 Macro(_) => "macro", 245 Macro(_) => tags::MACRO,
215 Field(_) => "field", 246 Field(_) => tags::FIELD,
216 AssocItem(hir::AssocItem::Function(_)) => "function", 247 AssocItem(hir::AssocItem::Function(_)) => tags::FUNCTION,
217 AssocItem(hir::AssocItem::Const(_)) => "constant", 248 AssocItem(hir::AssocItem::Const(_)) => tags::CONSTANT,
218 AssocItem(hir::AssocItem::TypeAlias(_)) => "type", 249 AssocItem(hir::AssocItem::TypeAlias(_)) => tags::TYPE,
219 Def(hir::ModuleDef::Module(_)) => "module", 250 Def(hir::ModuleDef::Module(_)) => tags::MODULE,
220 Def(hir::ModuleDef::Function(_)) => "function", 251 Def(hir::ModuleDef::Function(_)) => tags::FUNCTION,
221 Def(hir::ModuleDef::Adt(_)) => "type", 252 Def(hir::ModuleDef::Adt(_)) => tags::TYPE,
222 Def(hir::ModuleDef::EnumVariant(_)) => "constant", 253 Def(hir::ModuleDef::EnumVariant(_)) => tags::CONSTANT,
223 Def(hir::ModuleDef::Const(_)) => "constant", 254 Def(hir::ModuleDef::Const(_)) => tags::CONSTANT,
224 Def(hir::ModuleDef::Static(_)) => "constant", 255 Def(hir::ModuleDef::Static(_)) => tags::CONSTANT,
225 Def(hir::ModuleDef::Trait(_)) => "type", 256 Def(hir::ModuleDef::Trait(_)) => tags::TYPE,
226 Def(hir::ModuleDef::TypeAlias(_)) => "type", 257 Def(hir::ModuleDef::TypeAlias(_)) => tags::TYPE,
227 Def(hir::ModuleDef::BuiltinType(_)) => "type", 258 Def(hir::ModuleDef::BuiltinType(_)) => tags::TYPE_BUILTIN,
228 SelfType(_) | TypeParam(_) => "type", 259 SelfType(_) => tags::TYPE_SELF,
260 TypeParam(_) => tags::TYPE_PARAM,
229 Local(local) => { 261 Local(local) => {
230 if local.is_mut(db) { 262 if local.is_mut(db) {
231 "variable.mut" 263 tags::VARIABLE_MUT
232 } else if local.ty(db).is_mutable_reference() { 264 } else if local.ty(db).is_mutable_reference() {
233 "variable.mut" 265 tags::VARIABLE_MUT
234 } else { 266 } else {
235 "variable" 267 tags::VARIABLE
236 } 268 }
237 } 269 }
238 } 270 }
@@ -255,8 +287,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
255.builtin { color: #DD6718; } 287.builtin { color: #DD6718; }
256.text { color: #DCDCCC; } 288.text { color: #DCDCCC; }
257.type { color: #7CB8BB; } 289.type { color: #7CB8BB; }
290.type\\.param { color: #20999D; }
258.attribute { color: #94BFF3; } 291.attribute { color: #94BFF3; }
259.literal { color: #BFEBBF; } 292.literal { color: #BFEBBF; }
293.literal\\.numeric { color: #6A8759; }
260.macro { color: #94BFF3; } 294.macro { color: #94BFF3; }
261.variable { color: #DCDCCC; } 295.variable { color: #DCDCCC; }
262.variable\\.mut { color: #DCDCCC; text-decoration: underline; } 296.variable\\.mut { color: #DCDCCC; text-decoration: underline; }
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index 927449b45..16cc11e8c 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -17,11 +17,13 @@ use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace};
17use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; 17use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
18use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; 18use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
19use relative_path::RelativePathBuf; 19use relative_path::RelativePathBuf;
20use std::path::{Component, Prefix};
20 21
21use crate::{ 22use crate::{
22 main_loop::pending_requests::{CompletedRequest, LatestRequests}, 23 main_loop::pending_requests::{CompletedRequest, LatestRequests},
23 LspError, Result, 24 LspError, Result,
24}; 25};
26use std::str::FromStr;
25 27
26#[derive(Debug, Clone)] 28#[derive(Debug, Clone)]
27pub struct Options { 29pub struct Options {
@@ -233,8 +235,8 @@ impl WorldSnapshot {
233 235
234 pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> { 236 pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
235 let path = self.vfs.read().file2path(VfsFile(id.0)); 237 let path = self.vfs.read().file2path(VfsFile(id.0));
236 let url = Url::from_file_path(&path) 238 let url = url_from_path_with_drive_lowercasing(path)?;
237 .map_err(|_| format!("can't convert path to url: {}", path.display()))?; 239
238 Ok(url) 240 Ok(url)
239 } 241 }
240 242
@@ -279,3 +281,65 @@ impl WorldSnapshot {
279 self.analysis.feature_flags() 281 self.analysis.feature_flags()
280 } 282 }
281} 283}
284
285/// Returns a `Url` object from a given path, will lowercase drive letters if present.
286/// This will only happen when processing windows paths.
287///
288/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
289fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
290 let component_has_windows_drive = path
291 .as_ref()
292 .components()
293 .find(|comp| {
294 if let Component::Prefix(c) = comp {
295 match c.kind() {
296 Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true,
297 _ => return false,
298 }
299 }
300 false
301 })
302 .is_some();
303
304 // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
305 if component_has_windows_drive {
306 let url_original = Url::from_file_path(&path)
307 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;
308
309 let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect();
310
311 // There is a drive partition, but we never found a colon.
312 // This should not happen, but in this case we just pass it through.
313 if drive_partition.len() == 1 {
314 return Ok(url_original);
315 }
316
317 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
318 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
319
320 Ok(url)
321 } else {
322 Ok(Url::from_file_path(&path)
323 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
324 }
325}
326
327// `Url` is not able to parse windows paths on unix machines.
328#[cfg(target_os = "windows")]
329#[cfg(test)]
330mod path_conversion_windows_tests {
331 use super::url_from_path_with_drive_lowercasing;
332 #[test]
333 fn test_lowercase_drive_letter_with_drive() {
334 let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
335
336 assert_eq!(url.to_string(), "file:///c:/Test");
337 }
338
339 #[test]
340 fn test_drive_without_colon_passthrough() {
341 let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
342
343 assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
344 }
345}
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index f06191963..09f0a2d98 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -248,7 +248,12 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker {
248 p.error("expected `{`"); 248 p.error("expected `{`");
249 } 249 }
250 } 250 }
251 expr(p); 251
252 if p.at_ts(EXPR_FIRST) {
253 expr(p);
254 } else {
255 p.error("expected expression");
256 }
252 m.complete(p, LAMBDA_EXPR) 257 m.complete(p, LAMBDA_EXPR)
253} 258}
254 259
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 4a0437da3..c862d3912 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -24,7 +24,7 @@ pub struct CargoWorkspace {
24 pub(crate) workspace_root: PathBuf, 24 pub(crate) workspace_root: PathBuf,
25} 25}
26 26
27#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Default)] 27#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
28#[serde(rename_all = "camelCase", default)] 28#[serde(rename_all = "camelCase", default)]
29pub struct CargoFeatures { 29pub struct CargoFeatures {
30 /// Do not activate the `default` feature. 30 /// Do not activate the `default` feature.
@@ -38,6 +38,12 @@ pub struct CargoFeatures {
38 pub features: Vec<String>, 38 pub features: Vec<String>,
39} 39}
40 40
41impl Default for CargoFeatures {
42 fn default() -> Self {
43 CargoFeatures { no_default_features: false, all_features: true, features: Vec::new() }
44 }
45}
46
41#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 47#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
42pub struct Package(RawId); 48pub struct Package(RawId);
43impl_arena_id!(Package); 49impl_arena_id!(Package);
diff --git a/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs
new file mode 100644
index 000000000..a2f74bd87
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs
@@ -0,0 +1,5 @@
1fn foo() -> i32 {
2 [1, 2, 3].iter()
3 .map(|it|)
4 .max::<i32>();
5}
diff --git a/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt
new file mode 100644
index 000000000..d1544634c
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt
@@ -0,0 +1,83 @@
1SOURCE_FILE@[0; 83)
2 FN_DEF@[0; 82)
3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7) "("
9 R_PAREN@[7; 8) ")"
10 WHITESPACE@[8; 9) " "
11 RET_TYPE@[9; 15)
12 THIN_ARROW@[9; 11) "->"
13 WHITESPACE@[11; 12) " "
14 PATH_TYPE@[12; 15)
15 PATH@[12; 15)
16 PATH_SEGMENT@[12; 15)
17 NAME_REF@[12; 15)
18 IDENT@[12; 15) "i32"
19 WHITESPACE@[15; 16) " "
20 BLOCK_EXPR@[16; 82)
21 BLOCK@[16; 82)
22 L_CURLY@[16; 17) "{"
23 WHITESPACE@[17; 22) "\n "
24 EXPR_STMT@[22; 80)
25 METHOD_CALL_EXPR@[22; 79)
26 METHOD_CALL_EXPR@[22; 57)
27 METHOD_CALL_EXPR@[22; 38)
28 ARRAY_EXPR@[22; 31)
29 L_BRACK@[22; 23) "["
30 LITERAL@[23; 24)
31 INT_NUMBER@[23; 24) "1"
32 COMMA@[24; 25) ","
33 WHITESPACE@[25; 26) " "
34 LITERAL@[26; 27)
35 INT_NUMBER@[26; 27) "2"
36 COMMA@[27; 28) ","
37 WHITESPACE@[28; 29) " "
38 LITERAL@[29; 30)
39 INT_NUMBER@[29; 30) "3"
40 R_BRACK@[30; 31) "]"
41 DOT@[31; 32) "."
42 NAME_REF@[32; 36)
43 IDENT@[32; 36) "iter"
44 ARG_LIST@[36; 38)
45 L_PAREN@[36; 37) "("
46 R_PAREN@[37; 38) ")"
47 WHITESPACE@[38; 47) "\n "
48 DOT@[47; 48) "."
49 NAME_REF@[48; 51)
50 IDENT@[48; 51) "map"
51 ARG_LIST@[51; 57)
52 L_PAREN@[51; 52) "("
53 LAMBDA_EXPR@[52; 56)
54 PARAM_LIST@[52; 56)
55 PIPE@[52; 53) "|"
56 PARAM@[53; 55)
57 BIND_PAT@[53; 55)
58 NAME@[53; 55)
59 IDENT@[53; 55) "it"
60 PIPE@[55; 56) "|"
61 R_PAREN@[56; 57) ")"
62 WHITESPACE@[57; 66) "\n "
63 DOT@[66; 67) "."
64 NAME_REF@[67; 70)
65 IDENT@[67; 70) "max"
66 TYPE_ARG_LIST@[70; 77)
67 COLONCOLON@[70; 72) "::"
68 L_ANGLE@[72; 73) "<"
69 TYPE_ARG@[73; 76)
70 PATH_TYPE@[73; 76)
71 PATH@[73; 76)
72 PATH_SEGMENT@[73; 76)
73 NAME_REF@[73; 76)
74 IDENT@[73; 76) "i32"
75 R_ANGLE@[76; 77) ">"
76 ARG_LIST@[77; 79)
77 L_PAREN@[77; 78) "("
78 R_PAREN@[78; 79) ")"
79 SEMI@[79; 80) ";"
80 WHITESPACE@[80; 81) "\n"
81 R_CURLY@[81; 82) "}"
82 WHITESPACE@[82; 83) "\n"
83error 56: expected expression