diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-17 22:16:28 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-17 22:16:28 +0100 |
commit | 54379ec6f8f82a470a275771e70825634d3d553b (patch) | |
tree | 498719aafe633f9eb9cb65ba65932076981e4632 /crates/ra_hir/src/ty/infer.rs | |
parent | d505ee968b2a99eed65dfe7be27940ad9b2647c1 (diff) | |
parent | c2f9558e1af8dbf73ff86eeffcb9ea6940947dd6 (diff) |
Merge #1862
1862: Assoc item resolution refactoring (again) r=flodiebold a=flodiebold
This is #1849, with the associated type selection code removed for now. Handling cycles there will need some more thought.
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty/infer.rs')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 188 |
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 | ||
55 | mod unify; | 54 | mod 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> { |