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 | |
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.
-rw-r--r-- | crates/ra_hir/src/path.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 100 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 34 |
4 files changed, 100 insertions, 57 deletions
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index a61161b63..39d1b7e46 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -190,6 +190,13 @@ impl Path { | |||
190 | pub fn expand_macro_expr(&self) -> Option<Name> { | 190 | pub fn expand_macro_expr(&self) -> Option<Name> { |
191 | self.as_ident().and_then(|name| Some(name.clone())) | 191 | self.as_ident().and_then(|name| Some(name.clone())) |
192 | } | 192 | } |
193 | |||
194 | pub fn is_type_relative(&self) -> bool { | ||
195 | match self.kind { | ||
196 | PathKind::Type(_) => true, | ||
197 | _ => false, | ||
198 | } | ||
199 | } | ||
193 | } | 200 | } |
194 | 201 | ||
195 | impl GenericArgs { | 202 | impl GenericArgs { |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 7f4c78859..a23c8792a 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -15,7 +15,6 @@ use crate::{ | |||
15 | name::{Name, SELF_PARAM, SELF_TYPE}, | 15 | name::{Name, SELF_PARAM, SELF_TYPE}, |
16 | nameres::{CrateDefMap, CrateModuleId, PerNs}, | 16 | nameres::{CrateDefMap, CrateModuleId, PerNs}, |
17 | path::{Path, PathKind}, | 17 | path::{Path, PathKind}, |
18 | type_ref::TypeRef, | ||
19 | Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, | 18 | Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, |
20 | Trait, TypeAlias, | 19 | Trait, TypeAlias, |
21 | }; | 20 | }; |
@@ -65,10 +64,9 @@ pub enum TypeNs { | |||
65 | } | 64 | } |
66 | 65 | ||
67 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 66 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
68 | pub enum ResolveValueResult<'a> { | 67 | pub enum ResolveValueResult { |
69 | ValueNs(ValueNs), | 68 | ValueNs(ValueNs), |
70 | Partial(TypeNs, usize), | 69 | Partial(TypeNs, usize), |
71 | TypeRef(&'a TypeRef), | ||
72 | } | 70 | } |
73 | 71 | ||
74 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 72 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
@@ -131,6 +129,9 @@ impl Resolver { | |||
131 | db: &impl HirDatabase, | 129 | db: &impl HirDatabase, |
132 | path: &Path, | 130 | path: &Path, |
133 | ) -> Option<(TypeNs, Option<usize>)> { | 131 | ) -> Option<(TypeNs, Option<usize>)> { |
132 | if path.is_type_relative() { | ||
133 | return None; | ||
134 | } | ||
134 | let first_name = &path.segments.first()?.name; | 135 | let first_name = &path.segments.first()?.name; |
135 | let skip_to_mod = path.kind != PathKind::Plain; | 136 | let skip_to_mod = path.kind != PathKind::Plain; |
136 | for scope in self.scopes.iter().rev() { | 137 | for scope in self.scopes.iter().rev() { |
@@ -189,11 +190,10 @@ impl Resolver { | |||
189 | &self, | 190 | &self, |
190 | db: &impl HirDatabase, | 191 | db: &impl HirDatabase, |
191 | path: &'p Path, | 192 | path: &'p Path, |
192 | ) -> Option<ResolveValueResult<'p>> { | 193 | ) -> Option<ResolveValueResult> { |
193 | if let PathKind::Type(type_ref) = &path.kind { | 194 | if path.is_type_relative() { |
194 | return Some(ResolveValueResult::TypeRef(type_ref)); | 195 | return None; |
195 | } | 196 | } |
196 | |||
197 | let n_segments = path.segments.len(); | 197 | let n_segments = path.segments.len(); |
198 | let tmp = SELF_PARAM; | 198 | let tmp = SELF_PARAM; |
199 | let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; | 199 | let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; |
@@ -284,7 +284,7 @@ impl Resolver { | |||
284 | ) -> Option<ValueNs> { | 284 | ) -> Option<ValueNs> { |
285 | match self.resolve_path_in_value_ns(db, path)? { | 285 | match self.resolve_path_in_value_ns(db, path)? { |
286 | ResolveValueResult::ValueNs(it) => Some(it), | 286 | ResolveValueResult::ValueNs(it) => Some(it), |
287 | ResolveValueResult::Partial(..) | ResolveValueResult::TypeRef(_) => None, | 287 | ResolveValueResult::Partial(..) => None, |
288 | } | 288 | } |
289 | } | 289 | } |
290 | 290 | ||
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, |