diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/auto_import.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 38 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 88 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 14 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 10 |
5 files changed, 128 insertions, 23 deletions
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs index a32e2f9b6..1158adbbc 100644 --- a/crates/ra_assists/src/auto_import.rs +++ b/crates/ra_assists/src/auto_import.rs | |||
@@ -71,6 +71,7 @@ fn compare_path_segment(a: &SmolStr, b: &ast::PathSegment) -> bool { | |||
71 | ast::PathSegmentKind::SelfKw => a == "self", | 71 | ast::PathSegmentKind::SelfKw => a == "self", |
72 | ast::PathSegmentKind::SuperKw => a == "super", | 72 | ast::PathSegmentKind::SuperKw => a == "super", |
73 | ast::PathSegmentKind::CrateKw => a == "crate", | 73 | ast::PathSegmentKind::CrateKw => a == "crate", |
74 | ast::PathSegmentKind::Type { .. } => false, // not allowed in imports | ||
74 | } | 75 | } |
75 | } else { | 76 | } else { |
76 | false | 77 | false |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 882db7681..5ee71e421 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -25,6 +25,12 @@ pub struct PathSegment { | |||
25 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 25 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
26 | pub struct GenericArgs { | 26 | pub struct GenericArgs { |
27 | pub args: Vec<GenericArg>, | 27 | pub args: Vec<GenericArg>, |
28 | /// This specifies whether the args contain a Self type as the first | ||
29 | /// element. This is the case for path segments like `<T as Trait>`, where | ||
30 | /// `T` is actually a type parameter for the path `Trait` specifying the | ||
31 | /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type | ||
32 | /// is left out. | ||
33 | pub has_self_type: bool, | ||
28 | // someday also bindings | 34 | // someday also bindings |
29 | } | 35 | } |
30 | 36 | ||
@@ -74,6 +80,28 @@ impl Path { | |||
74 | let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; | 80 | let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; |
75 | segments.push(segment); | 81 | segments.push(segment); |
76 | } | 82 | } |
83 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | ||
84 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | ||
85 | |||
86 | // FIXME: handle <T> syntax (type segments without trait) | ||
87 | |||
88 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | ||
89 | let path = Path::from_ast(trait_ref?.path()?)?; | ||
90 | kind = path.kind; | ||
91 | let mut prefix_segments = path.segments; | ||
92 | prefix_segments.reverse(); | ||
93 | segments.extend(prefix_segments); | ||
94 | // Insert the type reference (T in the above example) as Self parameter for the trait | ||
95 | let self_type = TypeRef::from_ast(type_ref?); | ||
96 | let mut last_segment = segments.last_mut()?; | ||
97 | if last_segment.args_and_bindings.is_none() { | ||
98 | last_segment.args_and_bindings = Some(Arc::new(GenericArgs::empty())); | ||
99 | }; | ||
100 | let args = last_segment.args_and_bindings.as_mut().unwrap(); | ||
101 | let mut args_inner = Arc::make_mut(args); | ||
102 | args_inner.has_self_type = true; | ||
103 | args_inner.args.insert(0, GenericArg::Type(self_type)); | ||
104 | } | ||
77 | ast::PathSegmentKind::CrateKw => { | 105 | ast::PathSegmentKind::CrateKw => { |
78 | kind = PathKind::Crate; | 106 | kind = PathKind::Crate; |
79 | break; | 107 | break; |
@@ -144,11 +172,15 @@ impl GenericArgs { | |||
144 | } | 172 | } |
145 | // lifetimes and assoc type args ignored for now | 173 | // lifetimes and assoc type args ignored for now |
146 | if !args.is_empty() { | 174 | if !args.is_empty() { |
147 | Some(GenericArgs { args }) | 175 | Some(GenericArgs { args, has_self_type: false }) |
148 | } else { | 176 | } else { |
149 | None | 177 | None |
150 | } | 178 | } |
151 | } | 179 | } |
180 | |||
181 | pub(crate) fn empty() -> GenericArgs { | ||
182 | GenericArgs { args: Vec::new(), has_self_type: false } | ||
183 | } | ||
152 | } | 184 | } |
153 | 185 | ||
154 | impl From<Name> for Path { | 186 | impl From<Name> for Path { |
@@ -236,6 +268,10 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | |||
236 | } | 268 | } |
237 | Path { kind: PathKind::Super, segments: Vec::new() } | 269 | Path { kind: PathKind::Super, segments: Vec::new() } |
238 | } | 270 | } |
271 | ast::PathSegmentKind::Type { .. } => { | ||
272 | // not allowed in imports | ||
273 | return None; | ||
274 | } | ||
239 | }; | 275 | }; |
240 | Some(res) | 276 | Some(res) |
241 | } | 277 | } |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 894ba0695..24ec77fcf 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -8,7 +8,7 @@ | |||
8 | use std::iter; | 8 | use std::iter; |
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use super::{FnSig, GenericPredicate, Substs, TraitRef, Ty, TypeCtor}; | 11 | use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; |
12 | use crate::{ | 12 | use crate::{ |
13 | adt::VariantDef, | 13 | adt::VariantDef, |
14 | generics::HasGenericParams, | 14 | generics::HasGenericParams, |
@@ -64,7 +64,8 @@ impl Ty { | |||
64 | 64 | ||
65 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { | 65 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { |
66 | // Resolve the path (in type namespace) | 66 | // Resolve the path (in type namespace) |
67 | let resolution = resolver.resolve_path_without_assoc_items(db, path).take_types(); | 67 | let (resolution, remaining_index) = resolver.resolve_path_segments(db, path).into_inner(); |
68 | let resolution = resolution.take_types(); | ||
68 | 69 | ||
69 | let def = match resolution { | 70 | let def = match resolution { |
70 | Some(Resolution::Def(def)) => def, | 71 | Some(Resolution::Def(def)) => def, |
@@ -73,6 +74,10 @@ impl Ty { | |||
73 | panic!("path resolved to local binding in type ns"); | 74 | panic!("path resolved to local binding in type ns"); |
74 | } | 75 | } |
75 | Some(Resolution::GenericParam(idx)) => { | 76 | Some(Resolution::GenericParam(idx)) => { |
77 | if remaining_index.is_some() { | ||
78 | // e.g. T::Item | ||
79 | return Ty::Unknown; | ||
80 | } | ||
76 | return Ty::Param { | 81 | return Ty::Param { |
77 | idx, | 82 | idx, |
78 | // FIXME: maybe return name in resolution? | 83 | // FIXME: maybe return name in resolution? |
@@ -83,18 +88,59 @@ impl Ty { | |||
83 | }; | 88 | }; |
84 | } | 89 | } |
85 | Some(Resolution::SelfType(impl_block)) => { | 90 | Some(Resolution::SelfType(impl_block)) => { |
91 | if remaining_index.is_some() { | ||
92 | // e.g. Self::Item | ||
93 | return Ty::Unknown; | ||
94 | } | ||
86 | return impl_block.target_ty(db); | 95 | return impl_block.target_ty(db); |
87 | } | 96 | } |
88 | None => return Ty::Unknown, | 97 | None => { |
98 | // path did not resolve | ||
99 | return Ty::Unknown; | ||
100 | } | ||
89 | }; | 101 | }; |
90 | 102 | ||
91 | let typable: TypableDef = match def.into() { | 103 | if let ModuleDef::Trait(trait_) = def { |
92 | None => return Ty::Unknown, | 104 | let segment = match remaining_index { |
93 | Some(it) => it, | 105 | None => path.segments.last().expect("resolved path has at least one element"), |
94 | }; | 106 | Some(i) => &path.segments[i - 1], |
95 | let ty = db.type_for_def(typable, Namespace::Types); | 107 | }; |
96 | let substs = Ty::substs_from_path(db, resolver, path, typable); | 108 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); |
97 | ty.subst(&substs) | 109 | if let Some(remaining_index) = remaining_index { |
110 | if remaining_index == path.segments.len() - 1 { | ||
111 | let segment = &path.segments[remaining_index]; | ||
112 | let associated_ty = | ||
113 | match trait_ref.trait_.associated_type_by_name(db, segment.name.clone()) { | ||
114 | Some(t) => t, | ||
115 | None => { | ||
116 | // associated type not found | ||
117 | return Ty::Unknown; | ||
118 | } | ||
119 | }; | ||
120 | eprintln!( | ||
121 | "assoc ty: {:?}, parameters: {:?}", | ||
122 | associated_ty.name(db), | ||
123 | trait_ref.substs | ||
124 | ); | ||
125 | // FIXME handle type parameters on the segment | ||
126 | Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs }) | ||
127 | } else { | ||
128 | // FIXME more than one segment remaining, is this possible? | ||
129 | Ty::Unknown | ||
130 | } | ||
131 | } else { | ||
132 | // FIXME dyn Trait without the dyn | ||
133 | Ty::Unknown | ||
134 | } | ||
135 | } else { | ||
136 | let typable: TypableDef = match def.into() { | ||
137 | None => return Ty::Unknown, | ||
138 | Some(it) => it, | ||
139 | }; | ||
140 | let ty = db.type_for_def(typable, Namespace::Types); | ||
141 | let substs = Ty::substs_from_path(db, resolver, path, typable); | ||
142 | ty.subst(&substs) | ||
143 | } | ||
98 | } | 144 | } |
99 | 145 | ||
100 | pub(super) fn substs_from_path_segment( | 146 | pub(super) fn substs_from_path_segment( |
@@ -219,14 +265,25 @@ impl TraitRef { | |||
219 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | 265 | Resolution::Def(ModuleDef::Trait(tr)) => tr, |
220 | _ => return None, | 266 | _ => return None, |
221 | }; | 267 | }; |
222 | let mut substs = Self::substs_from_path(db, resolver, path, resolved); | 268 | let segment = path.segments.last().expect("path should have at least one segment"); |
269 | Some(TraitRef::from_resolved_path(db, resolver, resolved, segment, explicit_self_ty)) | ||
270 | } | ||
271 | |||
272 | fn from_resolved_path( | ||
273 | db: &impl HirDatabase, | ||
274 | resolver: &Resolver, | ||
275 | resolved: Trait, | ||
276 | segment: &PathSegment, | ||
277 | explicit_self_ty: Option<Ty>, | ||
278 | ) -> Self { | ||
279 | let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); | ||
223 | if let Some(self_ty) = explicit_self_ty { | 280 | if let Some(self_ty) = explicit_self_ty { |
224 | // FIXME this could be nicer | 281 | // FIXME this could be nicer |
225 | let mut substs_vec = substs.0.to_vec(); | 282 | let mut substs_vec = substs.0.to_vec(); |
226 | substs_vec[0] = self_ty; | 283 | substs_vec[0] = self_ty; |
227 | substs.0 = substs_vec.into(); | 284 | substs.0 = substs_vec.into(); |
228 | } | 285 | } |
229 | Some(TraitRef { trait_: resolved, substs }) | 286 | TraitRef { trait_: resolved, substs } |
230 | } | 287 | } |
231 | 288 | ||
232 | pub(crate) fn from_hir( | 289 | pub(crate) fn from_hir( |
@@ -245,11 +302,12 @@ impl TraitRef { | |||
245 | fn substs_from_path( | 302 | fn substs_from_path( |
246 | db: &impl HirDatabase, | 303 | db: &impl HirDatabase, |
247 | resolver: &Resolver, | 304 | resolver: &Resolver, |
248 | path: &Path, | 305 | segment: &PathSegment, |
249 | resolved: Trait, | 306 | resolved: Trait, |
250 | ) -> Substs { | 307 | ) -> Substs { |
251 | let segment = path.segments.last().expect("path should have at least one segment"); | 308 | let has_self_param = |
252 | substs_from_path_segment(db, resolver, segment, Some(resolved.into()), true) | 309 | segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false); |
310 | substs_from_path_segment(db, resolver, segment, Some(resolved.into()), !has_self_param) | ||
253 | } | 311 | } |
254 | 312 | ||
255 | pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { | 313 | pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 9d412ff61..01b358335 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2515,10 +2515,10 @@ fn test<T: Iterable>() { | |||
2515 | @r###" | 2515 | @r###" |
2516 | ⋮ | 2516 | ⋮ |
2517 | ⋮[108; 227) '{ ...ter; }': () | 2517 | ⋮[108; 227) '{ ...ter; }': () |
2518 | ⋮[118; 119) 'x': i32 | 2518 | ⋮[118; 119) 'x': <S as Iterable>::Item |
2519 | ⋮[145; 146) '1': i32 | 2519 | ⋮[145; 146) '1': <S as Iterable>::Item |
2520 | ⋮[156; 157) 'y': {unknown} | 2520 | ⋮[156; 157) 'y': <T as Iterable>::Item |
2521 | ⋮[183; 192) 'no_matter': {unknown} | 2521 | ⋮[183; 192) 'no_matter': <T as Iterable>::Item |
2522 | ⋮[202; 203) 'z': {unknown} | 2522 | ⋮[202; 203) 'z': {unknown} |
2523 | ⋮[215; 224) 'no_matter': {unknown} | 2523 | ⋮[215; 224) 'no_matter': {unknown} |
2524 | "### | 2524 | "### |
@@ -2552,9 +2552,9 @@ fn test() { | |||
2552 | ⋮[205; 209) 'foo1': fn foo1<S>(T) -> {unknown} | 2552 | ⋮[205; 209) 'foo1': fn foo1<S>(T) -> {unknown} |
2553 | ⋮[205; 212) 'foo1(S)': {unknown} | 2553 | ⋮[205; 212) 'foo1(S)': {unknown} |
2554 | ⋮[210; 211) 'S': S | 2554 | ⋮[210; 211) 'S': S |
2555 | ⋮[222; 223) 'y': {unknown} | 2555 | ⋮[222; 223) 'y': <S as Iterable>::Item |
2556 | ⋮[226; 230) 'foo2': fn foo2<S>(T) -> {unknown} | 2556 | ⋮[226; 230) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item |
2557 | ⋮[226; 233) 'foo2(S)': {unknown} | 2557 | ⋮[226; 233) 'foo2(S)': <S as Iterable>::Item |
2558 | ⋮[231; 232) 'S': S | 2558 | ⋮[231; 232) 'S': S |
2559 | "### | 2559 | "### |
2560 | ); | 2560 | ); |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index d4873b39a..2a59cf653 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -91,6 +91,7 @@ impl ast::Attr { | |||
91 | #[derive(Debug, Clone, PartialEq, Eq)] | 91 | #[derive(Debug, Clone, PartialEq, Eq)] |
92 | pub enum PathSegmentKind { | 92 | pub enum PathSegmentKind { |
93 | Name(ast::NameRef), | 93 | Name(ast::NameRef), |
94 | Type { type_ref: Option<ast::TypeRef>, trait_ref: Option<ast::PathType> }, | ||
94 | SelfKw, | 95 | SelfKw, |
95 | SuperKw, | 96 | SuperKw, |
96 | CrateKw, | 97 | CrateKw, |
@@ -112,6 +113,15 @@ impl ast::PathSegment { | |||
112 | T![self] => PathSegmentKind::SelfKw, | 113 | T![self] => PathSegmentKind::SelfKw, |
113 | T![super] => PathSegmentKind::SuperKw, | 114 | T![super] => PathSegmentKind::SuperKw, |
114 | T![crate] => PathSegmentKind::CrateKw, | 115 | T![crate] => PathSegmentKind::CrateKw, |
116 | T![<] => { | ||
117 | // <T> or <T as Trait> | ||
118 | // T is any TypeRef, Trait has to be a PathType | ||
119 | let mut type_refs = | ||
120 | self.syntax().children().filter(|node| ast::TypeRef::can_cast(node.kind())); | ||
121 | let type_ref = type_refs.next().and_then(ast::TypeRef::cast); | ||
122 | let trait_ref = type_refs.next().and_then(ast::PathType::cast); | ||
123 | PathSegmentKind::Type { type_ref, trait_ref } | ||
124 | } | ||
115 | _ => return None, | 125 | _ => return None, |
116 | } | 126 | } |
117 | }; | 127 | }; |