diff options
author | Florian Diebold <[email protected]> | 2019-09-15 11:50:57 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-17 18:47:45 +0100 |
commit | 406280e52f20e25af609d947efbed8b352ca1249 (patch) | |
tree | 3e7e5e284dd323173581b2c8618304f6125791b2 /crates | |
parent | 828d60574f8ecbc33fe4987913c6f713e41af1ae (diff) |
Refactor associated item resolution more
When resolving an associated item in value namespace, use the `Ty` lowering code
for the segments before the last instead of replicating it.
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 125 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 119 |
2 files changed, 120 insertions, 124 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 6aaf61c0e..f33479dc4 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -48,7 +48,7 @@ use crate::{ | |||
48 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 48 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
49 | ty::infer::diagnostics::InferenceDiagnostic, | 49 | ty::infer::diagnostics::InferenceDiagnostic, |
50 | type_ref::{Mutability, TypeRef}, | 50 | type_ref::{Mutability, TypeRef}, |
51 | Adt, AssocItem, ConstData, DefWithBody, Either, FnData, Function, HasBody, ImplItem, Name, Path, | 51 | Adt, AssocItem, ConstData, DefWithBody, Either, FnData, Function, HasBody, Name, Path, |
52 | StructField, | 52 | StructField, |
53 | }; | 53 | }; |
54 | 54 | ||
@@ -508,7 +508,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
508 | 508 | ||
509 | fn resolve_assoc_item( | 509 | fn resolve_assoc_item( |
510 | &mut self, | 510 | &mut self, |
511 | mut def_or_ty: Either<TypeNs, Ty>, | 511 | // mut def_or_ty: Either<TypeNs, Ty>, |
512 | def: TypeNs, | ||
512 | path: &Path, | 513 | path: &Path, |
513 | remaining_index: usize, | 514 | remaining_index: usize, |
514 | id: ExprOrPatId, | 515 | id: ExprOrPatId, |
@@ -516,80 +517,63 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
516 | assert!(remaining_index < path.segments.len()); | 517 | assert!(remaining_index < path.segments.len()); |
517 | let krate = self.resolver.krate()?; | 518 | let krate = self.resolver.krate()?; |
518 | 519 | ||
519 | let mut ty = Ty::Unknown; | 520 | // there may be more intermediate segments between the resolved one and |
520 | 521 | // the end. Only the last segment needs to be resolved to a value; from | |
521 | // resolve intermediate segments | 522 | // the segments before that, we need to get either a type or a trait ref. |
522 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { | ||
523 | let is_last_segment = i == path.segments[remaining_index..].len() - 1; | ||
524 | ty = match def_or_ty { | ||
525 | Either::A(def) => { | ||
526 | let typable: TypableDef = match def { | ||
527 | TypeNs::Adt(it) => it.into(), | ||
528 | TypeNs::TypeAlias(it) => it.into(), | ||
529 | TypeNs::BuiltinType(it) => it.into(), | ||
530 | // FIXME associated item of traits, generics, and Self | ||
531 | TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => { | ||
532 | return None; | ||
533 | } | ||
534 | // FIXME: report error here | ||
535 | TypeNs::EnumVariant(_) => return None, | ||
536 | }; | ||
537 | |||
538 | let ty = self.db.type_for_def(typable, Namespace::Types); | ||
539 | |||
540 | // For example, this substs will take `Gen::*<u32>*::make` | ||
541 | assert!(remaining_index > 0); | ||
542 | let substs = Ty::substs_from_path_segment( | ||
543 | self.db, | ||
544 | &self.resolver, | ||
545 | &path.segments[remaining_index + i - 1], | ||
546 | typable, | ||
547 | ); | ||
548 | ty.subst(&substs) | ||
549 | } | ||
550 | Either::B(ty) => ty, | ||
551 | }; | ||
552 | if is_last_segment { | ||
553 | break; | ||
554 | } | ||
555 | 523 | ||
556 | // Attempt to find an impl_item for the type which has a name matching | 524 | let resolved_segment = &path.segments[remaining_index - 1]; |
557 | // the current segment | 525 | let remaining_segments = &path.segments[remaining_index..]; |
558 | log::debug!("looking for path segment: {:?}", segment); | 526 | let is_before_last = remaining_segments.len() == 1; |
559 | 527 | ||
560 | let ty = mem::replace(&mut ty, Ty::Unknown); | 528 | let (def, substs) = match (def, is_before_last) { |
561 | def_or_ty = ty.iterate_impl_items(self.db, krate, |item| { | 529 | (TypeNs::Trait(_trait), true) => { |
562 | match item { | 530 | // Associated item of trait, e.g. `Default::default` |
563 | crate::ImplItem::Method(_) | crate::ImplItem::Const(_) => None, | 531 | // FIXME |
532 | return None; | ||
533 | } | ||
534 | (def, _) => { | ||
535 | // Either we already have a type (e.g. `Vec::new`), or we have a | ||
536 | // trait but it's not the last segment, so the next segment | ||
537 | // should resolve to an associated type of that trait (e.g. `<T | ||
538 | // as Iterator>::Item::default`) | ||
539 | let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1]; | ||
540 | let ty = Ty::from_partly_resolved_hir_path( | ||
541 | self.db, | ||
542 | &self.resolver, | ||
543 | def, | ||
544 | resolved_segment, | ||
545 | remaining_segments_for_ty, | ||
546 | ); | ||
547 | if let Ty::Unknown = ty { | ||
548 | return None; | ||
549 | } | ||
564 | 550 | ||
565 | // FIXME: Resolve associated types | 551 | let segment = |
566 | crate::ImplItem::TypeAlias(_) => { | 552 | remaining_segments.last().expect("there should be at least one segment here"); |
567 | // Some(Either::A(TypeNs::TypeAlias(..))) | 553 | // Find impl |
568 | None | 554 | let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { |
555 | crate::ImplItem::Method(func) => { | ||
556 | if segment.name == func.name(self.db) { | ||
557 | Some(ValueNs::Function(func)) | ||
558 | } else { | ||
559 | None | ||
560 | } | ||
569 | } | 561 | } |
570 | } | ||
571 | })?; | ||
572 | } | ||
573 | 562 | ||
574 | let segment = path.segments.last().unwrap(); | 563 | crate::ImplItem::Const(konst) => { |
575 | let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { | 564 | if segment.name == konst.name(self.db) { |
576 | crate::ImplItem::Method(func) => { | 565 | Some(ValueNs::Const(konst)) |
577 | if segment.name == func.name(self.db) { | 566 | } else { |
578 | Some(ValueNs::Function(func)) | 567 | None |
579 | } else { | 568 | } |
580 | None | 569 | } |
581 | } | 570 | crate::ImplItem::TypeAlias(_) => None, |
571 | })?; | ||
572 | let self_types = self.find_self_types(&def, ty); | ||
573 | (def, self_types) | ||
582 | } | 574 | } |
575 | }; | ||
583 | 576 | ||
584 | crate::ImplItem::Const(konst) => { | ||
585 | if konst.name(self.db).map_or(false, |n| n == segment.name) { | ||
586 | Some(ValueNs::Const(konst)) | ||
587 | } else { | ||
588 | None | ||
589 | } | ||
590 | } | ||
591 | crate::ImplItem::TypeAlias(_) => None, | ||
592 | })?; | ||
593 | self.write_assoc_resolution( | 577 | self.write_assoc_resolution( |
594 | id, | 578 | id, |
595 | match def { | 579 | match def { |
@@ -598,8 +582,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
598 | _ => unreachable!(), | 582 | _ => unreachable!(), |
599 | }, | 583 | }, |
600 | ); | 584 | ); |
601 | let self_types = self.find_self_types(&def, ty); | 585 | Some((def, substs)) |
602 | Some((def, self_types)) | ||
603 | } | 586 | } |
604 | 587 | ||
605 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { | 588 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 62e4ed0f4..e29b68f1a 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -86,81 +86,94 @@ impl Ty { | |||
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
89 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { | 89 | pub(crate) fn from_partly_resolved_hir_path( |
90 | // Resolve the path (in type namespace) | 90 | db: &impl HirDatabase, |
91 | let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { | 91 | resolver: &Resolver, |
92 | Some(it) => it, | 92 | resolution: TypeNs, |
93 | None => return Ty::Unknown, | 93 | resolved_segment: &PathSegment, |
94 | }; | 94 | remaining_segments: &[PathSegment], |
95 | 95 | ) -> Ty { | |
96 | let ty = match resolution { | 96 | let ty = match resolution { |
97 | TypeNs::Trait(trait_) => { | 97 | TypeNs::Trait(trait_) => { |
98 | let segment = match remaining_index { | 98 | let trait_ref = |
99 | None => path.segments.last().expect("resolved path has at least one element"), | 99 | TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None); |
100 | Some(i) => &path.segments[i - 1], | 100 | return if remaining_segments.len() == 1 { |
101 | }; | 101 | let segment = &remaining_segments[0]; |
102 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); | 102 | match trait_ref |
103 | return if let Some(remaining_index) = remaining_index { | 103 | .trait_ |
104 | if remaining_index == path.segments.len() - 1 { | 104 | .associated_type_by_name_including_super_traits(db, &segment.name) |
105 | let segment = &path.segments[remaining_index]; | 105 | { |
106 | match trait_ref | 106 | Some(associated_ty) => { |
107 | .trait_ | 107 | // FIXME handle type parameters on the segment |
108 | .associated_type_by_name_including_super_traits(db, &segment.name) | 108 | Ty::Projection(ProjectionTy { |
109 | { | 109 | associated_ty, |
110 | Some(associated_ty) => { | 110 | parameters: trait_ref.substs, |
111 | // FIXME handle type parameters on the segment | 111 | }) |
112 | Ty::Projection(ProjectionTy { | 112 | } |
113 | associated_ty, | 113 | None => { |
114 | parameters: trait_ref.substs, | 114 | // associated type not found (FIXME: report error) |
115 | }) | 115 | Ty::Unknown |
116 | } | ||
117 | None => { | ||
118 | // associated type not found (FIXME: report error) | ||
119 | Ty::Unknown | ||
120 | } | ||
121 | } | 116 | } |
122 | } else { | ||
123 | // FIXME report error (ambiguous associated type) | ||
124 | Ty::Unknown | ||
125 | } | 117 | } |
118 | } else if remaining_segments.len() > 1 { | ||
119 | // FIXME report error (ambiguous associated type) | ||
120 | Ty::Unknown | ||
126 | } else { | 121 | } else { |
127 | Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) | 122 | Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) |
128 | }; | 123 | }; |
129 | } | 124 | } |
130 | TypeNs::GenericParam(idx) => { | 125 | TypeNs::GenericParam(idx) => { |
131 | // FIXME: maybe return name in resolution? | 126 | // FIXME: maybe return name in resolution? |
132 | let name = match remaining_index { | 127 | let name = resolved_segment.name.clone(); |
133 | None => path | ||
134 | .as_ident() | ||
135 | .expect("generic param should be single-segment path") | ||
136 | .clone(), | ||
137 | Some(idx) => path.segments[idx - 1].name.clone(), | ||
138 | }; | ||
139 | Ty::Param { idx, name } | 128 | Ty::Param { idx, name } |
140 | } | 129 | } |
141 | TypeNs::SelfType(impl_block) => impl_block.target_ty(db), | 130 | TypeNs::SelfType(impl_block) => impl_block.target_ty(db), |
142 | 131 | ||
143 | TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), | 132 | TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()), |
144 | TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), | 133 | TypeNs::BuiltinType(it) => { |
145 | TypeNs::TypeAlias(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), | 134 | Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()) |
135 | } | ||
136 | TypeNs::TypeAlias(it) => { | ||
137 | Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()) | ||
138 | } | ||
146 | // FIXME: report error | 139 | // FIXME: report error |
147 | TypeNs::EnumVariant(_) => return Ty::Unknown, | 140 | TypeNs::EnumVariant(_) => return Ty::Unknown, |
148 | }; | 141 | }; |
149 | 142 | ||
150 | if let Some(remaining_index) = remaining_index { | 143 | if remaining_segments.len() == 1 { |
151 | // resolve unselected assoc types | 144 | // resolve unselected assoc types |
152 | if remaining_index == path.segments.len() - 1 { | 145 | let segment = &remaining_segments[0]; |
153 | let segment = &path.segments[remaining_index]; | 146 | Ty::select_associated_type(db, resolver, ty, segment) |
154 | Ty::select_associated_type(db, resolver, ty, segment) | 147 | } else if remaining_segments.len() > 1 { |
155 | } else { | 148 | // FIXME report error (ambiguous associated type) |
156 | // FIXME report error (ambiguous associated type) | 149 | Ty::Unknown |
157 | Ty::Unknown | ||
158 | } | ||
159 | } else { | 150 | } else { |
160 | ty | 151 | ty |
161 | } | 152 | } |
162 | } | 153 | } |
163 | 154 | ||
155 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { | ||
156 | // Resolve the path (in type namespace) | ||
157 | let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { | ||
158 | Some(it) => it, | ||
159 | None => return Ty::Unknown, | ||
160 | }; | ||
161 | let (resolved_segment, remaining_segments) = match remaining_index { | ||
162 | None => ( | ||
163 | path.segments.last().expect("resolved path has at least one element"), | ||
164 | &[] as &[PathSegment], | ||
165 | ), | ||
166 | Some(i) => (&path.segments[i - 1], &path.segments[i..]), | ||
167 | }; | ||
168 | Ty::from_partly_resolved_hir_path( | ||
169 | db, | ||
170 | resolver, | ||
171 | resolution, | ||
172 | resolved_segment, | ||
173 | remaining_segments, | ||
174 | ) | ||
175 | } | ||
176 | |||
164 | fn select_associated_type( | 177 | fn select_associated_type( |
165 | db: &impl HirDatabase, | 178 | db: &impl HirDatabase, |
166 | resolver: &Resolver, | 179 | resolver: &Resolver, |
@@ -190,11 +203,11 @@ impl Ty { | |||
190 | fn from_hir_path_inner( | 203 | fn from_hir_path_inner( |
191 | db: &impl HirDatabase, | 204 | db: &impl HirDatabase, |
192 | resolver: &Resolver, | 205 | resolver: &Resolver, |
193 | path: &Path, | 206 | segment: &PathSegment, |
194 | typable: TypableDef, | 207 | typable: TypableDef, |
195 | ) -> Ty { | 208 | ) -> Ty { |
196 | let ty = db.type_for_def(typable, Namespace::Types); | 209 | let ty = db.type_for_def(typable, Namespace::Types); |
197 | let substs = Ty::substs_from_path(db, resolver, path, typable); | 210 | let substs = Ty::substs_from_path_segment(db, resolver, segment, typable); |
198 | ty.subst(&substs) | 211 | ty.subst(&substs) |
199 | } | 212 | } |
200 | 213 | ||