aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/infer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/infer.rs')
-rw-r--r--crates/ra_hir/src/ty/infer.rs188
1 files changed, 94 insertions, 94 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index bf9609d8c..70da7f311 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, ConstData, DefWithBody, Either, FnData, Function, HasBody, ImplItem, Name, Path, 51 Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField,
52 StructField,
53}; 52};
54 53
55mod unify; 54mod unify;
@@ -121,7 +120,7 @@ pub struct InferenceResult {
121 /// For each struct literal, records the variant it resolves to. 120 /// For each struct literal, records the variant it resolves to.
122 variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>, 121 variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>,
123 /// For each associated item record what it resolves to 122 /// For each associated item record what it resolves to
124 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>, 123 assoc_resolutions: FxHashMap<ExprOrPatId, AssocItem>,
125 diagnostics: Vec<InferenceDiagnostic>, 124 diagnostics: Vec<InferenceDiagnostic>,
126 pub(super) type_of_expr: ArenaMap<ExprId, Ty>, 125 pub(super) type_of_expr: ArenaMap<ExprId, Ty>,
127 pub(super) type_of_pat: ArenaMap<PatId, Ty>, 126 pub(super) type_of_pat: ArenaMap<PatId, Ty>,
@@ -141,10 +140,10 @@ impl InferenceResult {
141 pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantDef> { 140 pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantDef> {
142 self.variant_resolutions.get(&id.into()).copied() 141 self.variant_resolutions.get(&id.into()).copied()
143 } 142 }
144 pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<ImplItem> { 143 pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItem> {
145 self.assoc_resolutions.get(&id.into()).copied() 144 self.assoc_resolutions.get(&id.into()).copied()
146 } 145 }
147 pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<ImplItem> { 146 pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItem> {
148 self.assoc_resolutions.get(&id.into()).copied() 147 self.assoc_resolutions.get(&id.into()).copied()
149 } 148 }
150 pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { 149 pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
@@ -235,7 +234,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
235 self.result.variant_resolutions.insert(id, variant); 234 self.result.variant_resolutions.insert(id, variant);
236 } 235 }
237 236
238 fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: ImplItem) { 237 fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItem) {
239 self.result.assoc_resolutions.insert(id, item); 238 self.result.assoc_resolutions.insert(id, item);
240 } 239 }
241 240
@@ -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,101 +518,91 @@ 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>, 521 def: TypeNs,
512 path: &Path, 522 path: &Path,
513 remaining_index: usize, 523 remaining_index: usize,
514 id: ExprOrPatId, 524 id: ExprOrPatId,
515 ) -> Option<(ValueNs, Option<Substs>)> { 525 ) -> Option<(ValueNs, Option<Substs>)> {
516 assert!(remaining_index < path.segments.len()); 526 assert!(remaining_index < path.segments.len());
517 let krate = self.resolver.krate()?; 527 // there may be more intermediate segments between the resolved one and
518 528 // the end. Only the last segment needs to be resolved to a value; from
519 let mut ty = Ty::Unknown; 529 // the segments before that, we need to get either a type or a trait ref.
520 530
521 // resolve intermediate segments 531 let resolved_segment = &path.segments[remaining_index - 1];
522 for (i, segment) in path.segments[remaining_index..].iter().enumerate() { 532 let remaining_segments = &path.segments[remaining_index..];
523 let is_last_segment = i == path.segments[remaining_index..].len() - 1; 533 let is_before_last = remaining_segments.len() == 1;
524 ty = match def_or_ty { 534
525 Either::A(def) => { 535 match (def, is_before_last) {
526 let typable: TypableDef = match def { 536 (TypeNs::Trait(_trait), true) => {
527 TypeNs::Adt(it) => it.into(), 537 // FIXME Associated item of trait, e.g. `Default::default`
528 TypeNs::TypeAlias(it) => it.into(), 538 None
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 } 539 }
540 (def, _) => {
541 // Either we already have a type (e.g. `Vec::new`), or we have a
542 // trait but it's not the last segment, so the next segment
543 // should resolve to an associated type of that trait (e.g. `<T
544 // as Iterator>::Item::default`)
545 let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1];
546 let ty = Ty::from_partly_resolved_hir_path(
547 self.db,
548 &self.resolver,
549 def,
550 resolved_segment,
551 remaining_segments_for_ty,
552 );
553 if let Ty::Unknown = ty {
554 return None;
555 }
555 556
556 // Attempt to find an impl_item for the type which has a name matching 557 let segment =
557 // the current segment 558 remaining_segments.last().expect("there should be at least one segment here");
558 log::debug!("looking for path segment: {:?}", segment);
559 559
560 let ty = mem::replace(&mut ty, Ty::Unknown); 560 self.resolve_ty_assoc_item(ty, segment, id)
561 def_or_ty = ty.iterate_impl_items(self.db, krate, |item| { 561 }
562 match item { 562 }
563 crate::ImplItem::Method(_) => None, 563 }
564 crate::ImplItem::Const(_) => None,
565 564
566 // FIXME: Resolve associated types 565 fn resolve_ty_assoc_item(
567 crate::ImplItem::TypeAlias(_) => { 566 &mut self,
568 // Some(Either::A(TypeNs::TypeAlias(..))) 567 ty: Ty,
569 None 568 segment: &crate::path::PathSegment,
570 } 569 id: ExprOrPatId,
571 } 570 ) -> Option<(ValueNs, Option<Substs>)> {
572 })?; 571 if let Ty::Unknown = ty {
572 return None;
573 } 573 }
574 574
575 let segment = path.segments.last().unwrap(); 575 let krate = self.resolver.krate()?;
576 let def = ty.clone().iterate_impl_items(self.db, krate, |item| {
577 let matching_def: Option<ValueNs> = match item {
578 crate::ImplItem::Method(func) => {
579 if segment.name == func.name(self.db) {
580 Some(ValueNs::Function(func))
581 } else {
582 None
583 }
584 }
585 576
586 crate::ImplItem::Const(konst) => { 577 // Find impl
587 let data = konst.data(self.db); 578 // FIXME: consider trait candidates
588 if Some(&segment.name) == data.name() { 579 let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
589 Some(ValueNs::Const(konst)) 580 AssocItem::Function(func) => {
590 } else { 581 if segment.name == func.name(self.db) {
591 None 582 Some(AssocItem::Function(func))
592 } 583 } else {
584 None
593 } 585 }
594 crate::ImplItem::TypeAlias(_) => None, 586 }
595 }; 587
596 match matching_def { 588 AssocItem::Const(konst) => {
597 Some(_) => { 589 if konst.name(self.db).map_or(false, |n| n == segment.name) {
598 self.write_assoc_resolution(id, item); 590 Some(AssocItem::Const(konst))
599 matching_def 591 } else {
592 None
600 } 593 }
601 None => None,
602 } 594 }
595 AssocItem::TypeAlias(_) => None,
603 })?; 596 })?;
604 let self_types = self.find_self_types(&def, ty); 597 let def = match item {
605 Some((def, self_types)) 598 AssocItem::Function(f) => ValueNs::Function(f),
599 AssocItem::Const(c) => ValueNs::Const(c),
600 AssocItem::TypeAlias(_) => unreachable!(),
601 };
602 let substs = self.find_self_types(&def, ty);
603
604 self.write_assoc_resolution(id, item);
605 Some((def, substs))
606 } 606 }
607 607
608 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { 608 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {