diff options
author | Florian Diebold <[email protected]> | 2019-09-16 20:38:27 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-17 18:47:45 +0100 |
commit | fe1dfd2b20b256b99f40f6f6421f7c7e12c23e41 (patch) | |
tree | 4ac1178549999db25d67fd7358c4a705cfe629fc /crates/ra_hir/src/ty | |
parent | 406280e52f20e25af609d947efbed8b352ca1249 (diff) |
Refactor some more
Type-relative paths (`<T>::foo`) also need to work in type context, for example
`<T>::Item` is legal. So rather than returning the type ref from the resolver
function, just check it before.
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 100 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 34 |
2 files changed, 85 insertions, 49 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index f33479dc4..181be0fcc 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -48,8 +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, Name, Path, | 51 | Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField, |
52 | StructField, | ||
53 | }; | 52 | }; |
54 | 53 | ||
55 | mod unify; | 54 | mod unify; |
@@ -468,16 +467,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
468 | } | 467 | } |
469 | 468 | ||
470 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> { | 469 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> { |
471 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; | 470 | let (value, self_subst) = if let crate::PathKind::Type(type_ref) = &path.kind { |
472 | 471 | if path.segments.is_empty() { | |
473 | let (value, self_subst) = match value_or_partial { | 472 | // This can't actually happen syntax-wise |
474 | ResolveValueResult::ValueNs(it) => (it, None), | 473 | return None; |
475 | ResolveValueResult::Partial(def, remaining_index) => { | ||
476 | self.resolve_assoc_item(Either::A(def), path, remaining_index, id)? | ||
477 | } | 474 | } |
478 | ResolveValueResult::TypeRef(type_ref) => { | 475 | let ty = self.make_ty(type_ref); |
479 | let ty = self.make_ty(type_ref); | 476 | let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1]; |
480 | self.resolve_assoc_item(Either::B(ty), path, 0, id)? | 477 | let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); |
478 | self.resolve_ty_assoc_item( | ||
479 | ty, | ||
480 | path.segments.last().expect("path had at least one segment"), | ||
481 | id, | ||
482 | )? | ||
483 | } else { | ||
484 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; | ||
485 | |||
486 | match value_or_partial { | ||
487 | ResolveValueResult::ValueNs(it) => (it, None), | ||
488 | ResolveValueResult::Partial(def, remaining_index) => { | ||
489 | self.resolve_assoc_item(def, path, remaining_index, id)? | ||
490 | } | ||
481 | } | 491 | } |
482 | }; | 492 | }; |
483 | 493 | ||
@@ -508,15 +518,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
508 | 518 | ||
509 | fn resolve_assoc_item( | 519 | fn resolve_assoc_item( |
510 | &mut self, | 520 | &mut self, |
511 | // mut def_or_ty: Either<TypeNs, Ty>, | ||
512 | def: TypeNs, | 521 | def: TypeNs, |
513 | path: &Path, | 522 | path: &Path, |
514 | remaining_index: usize, | 523 | remaining_index: usize, |
515 | id: ExprOrPatId, | 524 | id: ExprOrPatId, |
516 | ) -> Option<(ValueNs, Option<Substs>)> { | 525 | ) -> Option<(ValueNs, Option<Substs>)> { |
517 | assert!(remaining_index < path.segments.len()); | 526 | assert!(remaining_index < path.segments.len()); |
518 | let krate = self.resolver.krate()?; | ||
519 | |||
520 | // there may be more intermediate segments between the resolved one and | 527 | // there may be more intermediate segments between the resolved one and |
521 | // the end. Only the last segment needs to be resolved to a value; from | 528 | // the end. Only the last segment needs to be resolved to a value; from |
522 | // the segments before that, we need to get either a type or a trait ref. | 529 | // the segments before that, we need to get either a type or a trait ref. |
@@ -525,11 +532,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
525 | let remaining_segments = &path.segments[remaining_index..]; | 532 | let remaining_segments = &path.segments[remaining_index..]; |
526 | let is_before_last = remaining_segments.len() == 1; | 533 | let is_before_last = remaining_segments.len() == 1; |
527 | 534 | ||
528 | let (def, substs) = match (def, is_before_last) { | 535 | match (def, is_before_last) { |
529 | (TypeNs::Trait(_trait), true) => { | 536 | (TypeNs::Trait(_trait), true) => { |
530 | // Associated item of trait, e.g. `Default::default` | 537 | // FIXME Associated item of trait, e.g. `Default::default` |
531 | // FIXME | 538 | None |
532 | return None; | ||
533 | } | 539 | } |
534 | (def, _) => { | 540 | (def, _) => { |
535 | // Either we already have a type (e.g. `Vec::new`), or we have a | 541 | // Either we already have a type (e.g. `Vec::new`), or we have a |
@@ -550,29 +556,45 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
550 | 556 | ||
551 | let segment = | 557 | let segment = |
552 | remaining_segments.last().expect("there should be at least one segment here"); | 558 | remaining_segments.last().expect("there should be at least one segment here"); |
553 | // Find impl | ||
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 | } | ||
561 | } | ||
562 | 559 | ||
563 | crate::ImplItem::Const(konst) => { | 560 | self.resolve_ty_assoc_item(ty, segment, id) |
564 | if segment.name == konst.name(self.db) { | ||
565 | Some(ValueNs::Const(konst)) | ||
566 | } else { | ||
567 | None | ||
568 | } | ||
569 | } | ||
570 | crate::ImplItem::TypeAlias(_) => None, | ||
571 | })?; | ||
572 | let self_types = self.find_self_types(&def, ty); | ||
573 | (def, self_types) | ||
574 | } | 561 | } |
575 | }; | 562 | } |
563 | } | ||
564 | |||
565 | fn resolve_ty_assoc_item( | ||
566 | &mut self, | ||
567 | ty: Ty, | ||
568 | segment: &crate::path::PathSegment, | ||
569 | id: ExprOrPatId, | ||
570 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
571 | if let Ty::Unknown = ty { | ||
572 | return None; | ||
573 | } | ||
574 | |||
575 | let krate = self.resolver.krate()?; | ||
576 | |||
577 | // Find impl | ||
578 | // FIXME: consider trait candidates | ||
579 | let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { | ||
580 | crate::ImplItem::Method(func) => { | ||
581 | if segment.name == func.name(self.db) { | ||
582 | Some(ValueNs::Function(func)) | ||
583 | } else { | ||
584 | None | ||
585 | } | ||
586 | } | ||
587 | |||
588 | crate::ImplItem::Const(konst) => { | ||
589 | if konst.name(self.db).map_or(false, |n| n == segment.name) { | ||
590 | Some(ValueNs::Const(konst)) | ||
591 | } else { | ||
592 | None | ||
593 | } | ||
594 | } | ||
595 | crate::ImplItem::TypeAlias(_) => None, | ||
596 | })?; | ||
597 | let substs = self.find_self_types(&def, ty); | ||
576 | 598 | ||
577 | self.write_assoc_resolution( | 599 | self.write_assoc_resolution( |
578 | id, | 600 | id, |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index e29b68f1a..e6cd5d0be 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -86,6 +86,24 @@ impl Ty { | |||
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
89 | pub(crate) fn from_type_relative_path( | ||
90 | db: &impl HirDatabase, | ||
91 | resolver: &Resolver, | ||
92 | ty: Ty, | ||
93 | remaining_segments: &[PathSegment], | ||
94 | ) -> Ty { | ||
95 | if remaining_segments.len() == 1 { | ||
96 | // resolve unselected assoc types | ||
97 | let segment = &remaining_segments[0]; | ||
98 | Ty::select_associated_type(db, resolver, ty, segment) | ||
99 | } else if remaining_segments.len() > 1 { | ||
100 | // FIXME report error (ambiguous associated type) | ||
101 | Ty::Unknown | ||
102 | } else { | ||
103 | ty | ||
104 | } | ||
105 | } | ||
106 | |||
89 | pub(crate) fn from_partly_resolved_hir_path( | 107 | pub(crate) fn from_partly_resolved_hir_path( |
90 | db: &impl HirDatabase, | 108 | db: &impl HirDatabase, |
91 | resolver: &Resolver, | 109 | resolver: &Resolver, |
@@ -140,20 +158,16 @@ impl Ty { | |||
140 | TypeNs::EnumVariant(_) => return Ty::Unknown, | 158 | TypeNs::EnumVariant(_) => return Ty::Unknown, |
141 | }; | 159 | }; |
142 | 160 | ||
143 | if remaining_segments.len() == 1 { | 161 | Ty::from_type_relative_path(db, resolver, ty, remaining_segments) |
144 | // resolve unselected assoc types | ||
145 | let segment = &remaining_segments[0]; | ||
146 | Ty::select_associated_type(db, resolver, ty, segment) | ||
147 | } else if remaining_segments.len() > 1 { | ||
148 | // FIXME report error (ambiguous associated type) | ||
149 | Ty::Unknown | ||
150 | } else { | ||
151 | ty | ||
152 | } | ||
153 | } | 162 | } |
154 | 163 | ||
155 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { | 164 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { |
156 | // Resolve the path (in type namespace) | 165 | // Resolve the path (in type namespace) |
166 | if let crate::PathKind::Type(type_ref) = &path.kind { | ||
167 | let ty = Ty::from_hir(db, resolver, &type_ref); | ||
168 | let remaining_segments = &path.segments[..]; | ||
169 | return Ty::from_type_relative_path(db, resolver, ty, remaining_segments); | ||
170 | } | ||
157 | let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { | 171 | let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { |
158 | Some(it) => it, | 172 | Some(it) => it, |
159 | None => return Ty::Unknown, | 173 | None => return Ty::Unknown, |