aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-03-06 17:08:10 +0000
committerFlorian Diebold <[email protected]>2020-03-06 17:14:39 +0000
commitd17c5416af3d90b4c827224d4cd73366fa5a294b (patch)
treee67ea28da54f3ff428fdfeab1689f2a334f362a8 /crates/ra_hir_ty
parentce7496ec2227746cfcd2147fadf58fa71f65e35b (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.rs4
-rw-r--r--crates/ra_hir_ty/src/lower.rs86
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs41
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
92impl Ty { 92impl 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]
1806fn unselected_projection_on_trait_self() {
1807 assert_snapshot!(infer(
1808 r#"
1809//- /main.rs
1810trait Trait {
1811 type Item;
1812
1813 fn f(&self, x: Self::Item);
1814}
1815
1816struct S;
1817
1818impl Trait for S {
1819 type Item = u32;
1820 fn f(&self, x: Self::Item) { let y = x; }
1821}
1822
1823struct S2;
1824
1825impl 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]
1806fn trait_impl_self_ty() { 1847fn trait_impl_self_ty() {
1807 let t = type_at( 1848 let t = type_at(
1808 r#" 1849 r#"