aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/lower.rs
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/src/lower.rs
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/src/lower.rs')
-rw-r--r--crates/ra_hir_ty/src/lower.rs86
1 files changed, 50 insertions, 36 deletions
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 {