aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-09-15 11:50:57 +0100
committerFlorian Diebold <[email protected]>2019-09-17 18:47:45 +0100
commit406280e52f20e25af609d947efbed8b352ca1249 (patch)
tree3e7e5e284dd323173581b2c8618304f6125791b2 /crates
parent828d60574f8ecbc33fe4987913c6f713e41af1ae (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.rs125
-rw-r--r--crates/ra_hir/src/ty/lower.rs119
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