aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-09-16 20:38:27 +0100
committerFlorian Diebold <[email protected]>2019-09-17 18:47:45 +0100
commitfe1dfd2b20b256b99f40f6f6421f7c7e12c23e41 (patch)
tree4ac1178549999db25d67fd7358c4a705cfe629fc /crates
parent406280e52f20e25af609d947efbed8b352ca1249 (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')
-rw-r--r--crates/ra_hir/src/path.rs7
-rw-r--r--crates/ra_hir/src/resolve.rs16
-rw-r--r--crates/ra_hir/src/ty/infer.rs100
-rw-r--r--crates/ra_hir/src/ty/lower.rs34
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
195impl GenericArgs { 202impl 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)]
68pub enum ResolveValueResult<'a> { 67pub 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
55mod unify; 54mod 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,