diff options
author | Florian Diebold <[email protected]> | 2020-03-06 17:08:10 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-03-06 17:14:39 +0000 |
commit | d17c5416af3d90b4c827224d4cd73366fa5a294b (patch) | |
tree | e67ea28da54f3ff428fdfeab1689f2a334f362a8 /crates/ra_hir_ty | |
parent | ce7496ec2227746cfcd2147fadf58fa71f65e35b (diff) |
Resolve `Self::AssocTy` in impls
To do this we need to carry around the original resolution a bit, because `Self`
gets resolved to the actual type immediately, but you're not allowed to write
the equivalent type in a projection. (I tried just comparing the projection base
type with the impl self type, but that seemed too dirty.) This is basically how
rustc does it as well.
Fixes #3249.
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r-- | crates/ra_hir_ty/src/infer/path.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 86 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 41 |
3 files changed, 93 insertions, 38 deletions
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 471d60342..c733b9e1d 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs | |||
@@ -40,7 +40,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
40 | let ty = self.make_ty(type_ref); | 40 | let ty = self.make_ty(type_ref); |
41 | let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); | 41 | let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); |
42 | let ctx = crate::lower::TyLoweringContext::new(self.db, &resolver); | 42 | let ctx = crate::lower::TyLoweringContext::new(self.db, &resolver); |
43 | let ty = Ty::from_type_relative_path(&ctx, ty, remaining_segments_for_ty); | 43 | let (ty, _) = Ty::from_type_relative_path(&ctx, ty, None, remaining_segments_for_ty); |
44 | self.resolve_ty_assoc_item( | 44 | self.resolve_ty_assoc_item( |
45 | ty, | 45 | ty, |
46 | &path.segments().last().expect("path had at least one segment").name, | 46 | &path.segments().last().expect("path had at least one segment").name, |
@@ -115,7 +115,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
115 | let remaining_segments_for_ty = | 115 | let remaining_segments_for_ty = |
116 | remaining_segments.take(remaining_segments.len() - 1); | 116 | remaining_segments.take(remaining_segments.len() - 1); |
117 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); | 117 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); |
118 | let ty = Ty::from_partly_resolved_hir_path( | 118 | let (ty, _) = Ty::from_partly_resolved_hir_path( |
119 | &ctx, | 119 | &ctx, |
120 | def, | 120 | def, |
121 | resolved_segment, | 121 | resolved_segment, |
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 092977e93..b96dc126c 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -91,7 +91,14 @@ pub enum TypeParamLoweringMode { | |||
91 | 91 | ||
92 | impl Ty { | 92 | impl Ty { |
93 | pub fn from_hir(ctx: &TyLoweringContext<'_, impl HirDatabase>, type_ref: &TypeRef) -> Self { | 93 | pub fn from_hir(ctx: &TyLoweringContext<'_, impl HirDatabase>, type_ref: &TypeRef) -> Self { |
94 | match type_ref { | 94 | Ty::from_hir_ext(ctx, type_ref).0 |
95 | } | ||
96 | pub fn from_hir_ext( | ||
97 | ctx: &TyLoweringContext<'_, impl HirDatabase>, | ||
98 | type_ref: &TypeRef, | ||
99 | ) -> (Self, Option<TypeNs>) { | ||
100 | let mut res = None; | ||
101 | let ty = match type_ref { | ||
95 | TypeRef::Never => Ty::simple(TypeCtor::Never), | 102 | TypeRef::Never => Ty::simple(TypeCtor::Never), |
96 | TypeRef::Tuple(inner) => { | 103 | TypeRef::Tuple(inner) => { |
97 | let inner_tys: Arc<[Ty]> = inner.iter().map(|tr| Ty::from_hir(ctx, tr)).collect(); | 104 | let inner_tys: Arc<[Ty]> = inner.iter().map(|tr| Ty::from_hir(ctx, tr)).collect(); |
@@ -100,7 +107,11 @@ impl Ty { | |||
100 | Substs(inner_tys), | 107 | Substs(inner_tys), |
101 | ) | 108 | ) |
102 | } | 109 | } |
103 | TypeRef::Path(path) => Ty::from_hir_path(ctx, path), | 110 | TypeRef::Path(path) => { |
111 | let (ty, res_) = Ty::from_hir_path(ctx, path); | ||
112 | res = res_; | ||
113 | ty | ||
114 | } | ||
104 | TypeRef::RawPtr(inner, mutability) => { | 115 | TypeRef::RawPtr(inner, mutability) => { |
105 | let inner_ty = Ty::from_hir(ctx, inner); | 116 | let inner_ty = Ty::from_hir(ctx, inner); |
106 | Ty::apply_one(TypeCtor::RawPtr(*mutability), inner_ty) | 117 | Ty::apply_one(TypeCtor::RawPtr(*mutability), inner_ty) |
@@ -183,7 +194,8 @@ impl Ty { | |||
183 | } | 194 | } |
184 | } | 195 | } |
185 | TypeRef::Error => Ty::Unknown, | 196 | TypeRef::Error => Ty::Unknown, |
186 | } | 197 | }; |
198 | (ty, res) | ||
187 | } | 199 | } |
188 | 200 | ||
189 | /// This is only for `generic_predicates_for_param`, where we can't just | 201 | /// This is only for `generic_predicates_for_param`, where we can't just |
@@ -217,17 +229,19 @@ impl Ty { | |||
217 | pub(crate) fn from_type_relative_path( | 229 | pub(crate) fn from_type_relative_path( |
218 | ctx: &TyLoweringContext<'_, impl HirDatabase>, | 230 | ctx: &TyLoweringContext<'_, impl HirDatabase>, |
219 | ty: Ty, | 231 | ty: Ty, |
232 | // We need the original resolution to lower `Self::AssocTy` correctly | ||
233 | res: Option<TypeNs>, | ||
220 | remaining_segments: PathSegments<'_>, | 234 | remaining_segments: PathSegments<'_>, |
221 | ) -> Ty { | 235 | ) -> (Ty, Option<TypeNs>) { |
222 | if remaining_segments.len() == 1 { | 236 | if remaining_segments.len() == 1 { |
223 | // resolve unselected assoc types | 237 | // resolve unselected assoc types |
224 | let segment = remaining_segments.first().unwrap(); | 238 | let segment = remaining_segments.first().unwrap(); |
225 | Ty::select_associated_type(ctx, ty, segment) | 239 | (Ty::select_associated_type(ctx, ty, res, segment), None) |
226 | } else if remaining_segments.len() > 1 { | 240 | } else if remaining_segments.len() > 1 { |
227 | // FIXME report error (ambiguous associated type) | 241 | // FIXME report error (ambiguous associated type) |
228 | Ty::Unknown | 242 | (Ty::Unknown, None) |
229 | } else { | 243 | } else { |
230 | ty | 244 | (ty, res) |
231 | } | 245 | } |
232 | } | 246 | } |
233 | 247 | ||
@@ -236,14 +250,14 @@ impl Ty { | |||
236 | resolution: TypeNs, | 250 | resolution: TypeNs, |
237 | resolved_segment: PathSegment<'_>, | 251 | resolved_segment: PathSegment<'_>, |
238 | remaining_segments: PathSegments<'_>, | 252 | remaining_segments: PathSegments<'_>, |
239 | ) -> Ty { | 253 | ) -> (Ty, Option<TypeNs>) { |
240 | let ty = match resolution { | 254 | let ty = match resolution { |
241 | TypeNs::TraitId(trait_) => { | 255 | TypeNs::TraitId(trait_) => { |
242 | // if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there | 256 | // if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there |
243 | let self_ty = if remaining_segments.len() == 0 { Some(Ty::Bound(0)) } else { None }; | 257 | let self_ty = if remaining_segments.len() == 0 { Some(Ty::Bound(0)) } else { None }; |
244 | let trait_ref = | 258 | let trait_ref = |
245 | TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); | 259 | TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); |
246 | return if remaining_segments.len() == 1 { | 260 | let ty = if remaining_segments.len() == 1 { |
247 | let segment = remaining_segments.first().unwrap(); | 261 | let segment = remaining_segments.first().unwrap(); |
248 | let associated_ty = associated_type_by_name_including_super_traits( | 262 | let associated_ty = associated_type_by_name_including_super_traits( |
249 | ctx.db, | 263 | ctx.db, |
@@ -269,6 +283,7 @@ impl Ty { | |||
269 | } else { | 283 | } else { |
270 | Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) | 284 | Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) |
271 | }; | 285 | }; |
286 | return (ty, None); | ||
272 | } | 287 | } |
273 | TypeNs::GenericParam(param_id) => { | 288 | TypeNs::GenericParam(param_id) => { |
274 | let generics = | 289 | let generics = |
@@ -306,22 +321,25 @@ impl Ty { | |||
306 | TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), | 321 | TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), |
307 | TypeNs::TypeAliasId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), | 322 | TypeNs::TypeAliasId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), |
308 | // FIXME: report error | 323 | // FIXME: report error |
309 | TypeNs::EnumVariantId(_) => return Ty::Unknown, | 324 | TypeNs::EnumVariantId(_) => return (Ty::Unknown, None), |
310 | }; | 325 | }; |
311 | 326 | ||
312 | Ty::from_type_relative_path(ctx, ty, remaining_segments) | 327 | Ty::from_type_relative_path(ctx, ty, Some(resolution), remaining_segments) |
313 | } | 328 | } |
314 | 329 | ||
315 | pub(crate) fn from_hir_path(ctx: &TyLoweringContext<'_, impl HirDatabase>, path: &Path) -> Ty { | 330 | pub(crate) fn from_hir_path( |
331 | ctx: &TyLoweringContext<'_, impl HirDatabase>, | ||
332 | path: &Path, | ||
333 | ) -> (Ty, Option<TypeNs>) { | ||
316 | // Resolve the path (in type namespace) | 334 | // Resolve the path (in type namespace) |
317 | if let Some(type_ref) = path.type_anchor() { | 335 | if let Some(type_ref) = path.type_anchor() { |
318 | let ty = Ty::from_hir(ctx, &type_ref); | 336 | let (ty, res) = Ty::from_hir_ext(ctx, &type_ref); |
319 | return Ty::from_type_relative_path(ctx, ty, path.segments()); | 337 | return Ty::from_type_relative_path(ctx, ty, res, path.segments()); |
320 | } | 338 | } |
321 | let (resolution, remaining_index) = | 339 | let (resolution, remaining_index) = |
322 | match ctx.resolver.resolve_path_in_type_ns(ctx.db, path.mod_path()) { | 340 | match ctx.resolver.resolve_path_in_type_ns(ctx.db, path.mod_path()) { |
323 | Some(it) => it, | 341 | Some(it) => it, |
324 | None => return Ty::Unknown, | 342 | None => return (Ty::Unknown, None), |
325 | }; | 343 | }; |
326 | let (resolved_segment, remaining_segments) = match remaining_index { | 344 | let (resolved_segment, remaining_segments) = match remaining_index { |
327 | None => ( | 345 | None => ( |
@@ -336,31 +354,27 @@ impl Ty { | |||
336 | fn select_associated_type( | 354 | fn select_associated_type( |
337 | ctx: &TyLoweringContext<'_, impl HirDatabase>, | 355 | ctx: &TyLoweringContext<'_, impl HirDatabase>, |
338 | self_ty: Ty, | 356 | self_ty: Ty, |
357 | res: Option<TypeNs>, | ||
339 | segment: PathSegment<'_>, | 358 | segment: PathSegment<'_>, |
340 | ) -> Ty { | 359 | ) -> Ty { |
341 | let def = match ctx.resolver.generic_def() { | 360 | let traits_from_env: Vec<_> = match res { |
342 | Some(def) => def, | 361 | Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) { |
343 | None => return Ty::Unknown, // this can't actually happen | 362 | None => return Ty::Unknown, |
344 | }; | 363 | Some(trait_ref) => vec![trait_ref.value.trait_], |
345 | let param_id = match self_ty { | 364 | }, |
346 | Ty::Placeholder(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id, | 365 | Some(TypeNs::GenericParam(param_id)) => { |
347 | Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => { | 366 | let predicates = ctx.db.generic_predicates_for_param(param_id); |
348 | let generics = generics(ctx.db, def); | 367 | predicates |
349 | let param_id = if let Some((id, _)) = generics.iter().nth(idx as usize) { | 368 | .iter() |
350 | id | 369 | .filter_map(|pred| match &pred.value { |
351 | } else { | 370 | GenericPredicate::Implemented(tr) => Some(tr.trait_), |
352 | return Ty::Unknown; | 371 | _ => None, |
353 | }; | 372 | }) |
354 | param_id | 373 | .collect() |
355 | } | 374 | } |
356 | _ => return Ty::Unknown, // Error: Ambiguous associated type | 375 | _ => return Ty::Unknown, |
357 | }; | 376 | }; |
358 | let predicates = ctx.db.generic_predicates_for_param(param_id); | 377 | let traits = traits_from_env.into_iter().flat_map(|t| all_super_traits(ctx.db, t)); |
359 | let traits_from_env = predicates.iter().filter_map(|pred| match &pred.value { | ||
360 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | ||
361 | _ => None, | ||
362 | }); | ||
363 | let traits = traits_from_env.flat_map(|t| all_super_traits(ctx.db, t)); | ||
364 | for t in traits { | 378 | for t in traits { |
365 | if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name) | 379 | if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name) |
366 | { | 380 | { |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 547010b35..f009a708c 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -1803,6 +1803,47 @@ fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { | |||
1803 | } | 1803 | } |
1804 | 1804 | ||
1805 | #[test] | 1805 | #[test] |
1806 | fn unselected_projection_on_trait_self() { | ||
1807 | assert_snapshot!(infer( | ||
1808 | r#" | ||
1809 | //- /main.rs | ||
1810 | trait Trait { | ||
1811 | type Item; | ||
1812 | |||
1813 | fn f(&self, x: Self::Item); | ||
1814 | } | ||
1815 | |||
1816 | struct S; | ||
1817 | |||
1818 | impl Trait for S { | ||
1819 | type Item = u32; | ||
1820 | fn f(&self, x: Self::Item) { let y = x; } | ||
1821 | } | ||
1822 | |||
1823 | struct S2; | ||
1824 | |||
1825 | impl Trait for S2 { | ||
1826 | type Item = i32; | ||
1827 | fn f(&self, x: <Self>::Item) { let y = x; } | ||
1828 | } | ||
1829 | "#, | ||
1830 | ), @r###" | ||
1831 | [54; 58) 'self': &Self | ||
1832 | [60; 61) 'x': {unknown} | ||
1833 | [140; 144) 'self': &S | ||
1834 | [146; 147) 'x': u32 | ||
1835 | [161; 175) '{ let y = x; }': () | ||
1836 | [167; 168) 'y': u32 | ||
1837 | [171; 172) 'x': u32 | ||
1838 | [242; 246) 'self': &S2 | ||
1839 | [248; 249) 'x': i32 | ||
1840 | [265; 279) '{ let y = x; }': () | ||
1841 | [271; 272) 'y': i32 | ||
1842 | [275; 276) 'x': i32 | ||
1843 | "###); | ||
1844 | } | ||
1845 | |||
1846 | #[test] | ||
1806 | fn trait_impl_self_ty() { | 1847 | fn trait_impl_self_ty() { |
1807 | let t = type_at( | 1848 | let t = type_at( |
1808 | r#" | 1849 | r#" |