diff options
author | Aleksey Kladov <[email protected]> | 2019-09-12 21:35:53 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-09-13 14:24:10 +0100 |
commit | 51e2d76b9839410020c75ac02ad602675b0a5aa9 (patch) | |
tree | 989afd660d62db28196a8792cec2affb7bfd50a7 /crates/ra_hir/src/ty/infer.rs | |
parent | 1adf0519bcc8286c06e12aa7e5b16298addfea4a (diff) |
Specify desirable namespace when calling resolve
That way, we are able to get rid of a number of unreachable statements
Diffstat (limited to 'crates/ra_hir/src/ty/infer.rs')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 256 |
1 files changed, 123 insertions, 133 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 540a99b15..3ee083a04 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -45,11 +45,10 @@ use crate::{ | |||
45 | name, | 45 | name, |
46 | nameres::Namespace, | 46 | nameres::Namespace, |
47 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, | 47 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, |
48 | resolve::{Resolution, Resolver}, | 48 | resolve::{Resolver, TypeNs, ValueNs, ValueOrPartial}, |
49 | ty::infer::diagnostics::InferenceDiagnostic, | 49 | ty::infer::diagnostics::InferenceDiagnostic, |
50 | type_ref::{Mutability, TypeRef}, | 50 | type_ref::{Mutability, TypeRef}, |
51 | Adt, ConstData, DefWithBody, FnData, Function, HasBody, ImplItem, ModuleDef, Name, Path, | 51 | Adt, ConstData, DefWithBody, FnData, Function, HasBody, ImplItem, Name, Path, StructField, |
52 | StructField, | ||
53 | }; | 52 | }; |
54 | 53 | ||
55 | mod unify; | 54 | mod unify; |
@@ -472,141 +471,138 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
472 | } | 471 | } |
473 | 472 | ||
474 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> { | 473 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> { |
475 | let resolved = resolver.resolve_path_segments(self.db, &path); | 474 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; |
476 | 475 | ||
477 | let (def, remaining_index) = resolved.into_inner(); | 476 | let (value, self_subst) = match value_or_partial { |
477 | ValueOrPartial::ValueNs(it) => (it, None), | ||
478 | ValueOrPartial::Partial(def, remaining_index) => { | ||
479 | self.resolve_assoc_item(def, path, remaining_index, id)? | ||
480 | } | ||
481 | }; | ||
478 | 482 | ||
479 | log::debug!( | 483 | let typable: TypableDef = match value { |
480 | "path {:?} resolved to {:?} with remaining index {:?}", | 484 | ValueNs::LocalBinding(pat) => { |
481 | path, | 485 | let ty = self.result.type_of_pat.get(pat)?.clone(); |
482 | def, | 486 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); |
483 | remaining_index | 487 | return Some(ty); |
484 | ); | 488 | } |
489 | ValueNs::Function(it) => it.into(), | ||
490 | ValueNs::Const(it) => it.into(), | ||
491 | ValueNs::Static(it) => it.into(), | ||
492 | ValueNs::Struct(it) => it.into(), | ||
493 | ValueNs::EnumVariant(it) => it.into(), | ||
494 | }; | ||
485 | 495 | ||
486 | // if the remaining_index is None, we expect the path | 496 | let mut ty = self.db.type_for_def(typable, Namespace::Values); |
487 | // to be fully resolved, in this case we continue with | 497 | if let Some(self_subst) = self_subst { |
488 | // the default by attempting to `take_values´ from the resolution. | 498 | ty = ty.subst(&self_subst); |
489 | // Otherwise the path was partially resolved, which means | 499 | } |
490 | // we might have resolved into a type for which | ||
491 | // we may find some associated item starting at the | ||
492 | // path.segment pointed to by `remaining_index´ | ||
493 | let mut resolved = | ||
494 | if remaining_index.is_none() { def.take_values()? } else { def.take_types()? }; | ||
495 | 500 | ||
496 | let remaining_index = remaining_index.unwrap_or_else(|| path.segments.len()); | 501 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); |
497 | let mut actual_def_ty: Option<Ty> = None; | 502 | let ty = ty.subst(&substs); |
503 | let ty = self.insert_type_vars(ty); | ||
504 | let ty = self.normalize_associated_types_in(ty); | ||
505 | Some(ty) | ||
506 | } | ||
507 | |||
508 | fn resolve_assoc_item( | ||
509 | &mut self, | ||
510 | mut def: TypeNs, | ||
511 | path: &Path, | ||
512 | remaining_index: usize, | ||
513 | id: ExprOrPatId, | ||
514 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
515 | assert!(remaining_index < path.segments.len()); | ||
516 | let krate = self.resolver.krate()?; | ||
517 | |||
518 | let mut ty = Ty::Unknown; | ||
498 | 519 | ||
499 | let krate = resolver.krate()?; | ||
500 | // resolve intermediate segments | 520 | // resolve intermediate segments |
501 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { | 521 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { |
502 | let ty = match resolved { | 522 | let is_last_segment = i == path.segments[remaining_index..].len() - 1; |
503 | Resolution::Def(def) => { | 523 | ty = { |
504 | // FIXME resolve associated items from traits as well | 524 | let typable: TypableDef = match def { |
505 | let typable: Option<TypableDef> = def.into(); | 525 | TypeNs::Adt(it) => it.into(), |
506 | let typable = typable?; | 526 | TypeNs::TypeAlias(it) => it.into(), |
507 | 527 | TypeNs::BuiltinType(it) => it.into(), | |
508 | let ty = self.db.type_for_def(typable, Namespace::Types); | 528 | // FIXME associated item of traits, generics, and Self |
509 | 529 | TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => { | |
510 | // For example, this substs will take `Gen::*<u32>*::make` | 530 | return None; |
511 | assert!(remaining_index > 0); | 531 | } |
512 | let substs = Ty::substs_from_path_segment( | 532 | // FIXME: report error here |
513 | self.db, | 533 | TypeNs::EnumVariant(_) => return None, |
514 | &self.resolver, | 534 | }; |
515 | &path.segments[remaining_index + i - 1], | 535 | |
516 | typable, | 536 | let ty = self.db.type_for_def(typable, Namespace::Types); |
517 | ); | 537 | |
518 | 538 | // For example, this substs will take `Gen::*<u32>*::make` | |
519 | ty.subst(&substs) | 539 | assert!(remaining_index > 0); |
520 | } | 540 | let substs = Ty::substs_from_path_segment( |
521 | Resolution::LocalBinding(_) => { | 541 | self.db, |
522 | // can't have a local binding in an associated item path | 542 | &self.resolver, |
523 | return None; | 543 | &path.segments[remaining_index + i - 1], |
524 | } | 544 | typable, |
525 | Resolution::GenericParam(..) => { | 545 | ); |
526 | // FIXME associated item of generic param | 546 | ty.subst(&substs) |
527 | return None; | ||
528 | } | ||
529 | Resolution::SelfType(_) => { | ||
530 | // FIXME associated item of self type | ||
531 | return None; | ||
532 | } | ||
533 | }; | 547 | }; |
548 | if is_last_segment { | ||
549 | break; | ||
550 | } | ||
534 | 551 | ||
535 | // Attempt to find an impl_item for the type which has a name matching | 552 | // Attempt to find an impl_item for the type which has a name matching |
536 | // the current segment | 553 | // the current segment |
537 | log::debug!("looking for path segment: {:?}", segment); | 554 | log::debug!("looking for path segment: {:?}", segment); |
538 | 555 | ||
539 | actual_def_ty = Some(ty.clone()); | 556 | let ty = mem::replace(&mut ty, Ty::Unknown); |
540 | 557 | def = ty.iterate_impl_items(self.db, krate, |item| { | |
541 | let item: crate::ModuleDef = ty.iterate_impl_items(self.db, krate, |item| { | 558 | match item { |
542 | let matching_def: Option<crate::ModuleDef> = match item { | 559 | crate::ImplItem::Method(_) => None, |
543 | crate::ImplItem::Method(func) => { | 560 | crate::ImplItem::Const(_) => None, |
544 | if segment.name == func.name(self.db) { | ||
545 | Some(func.into()) | ||
546 | } else { | ||
547 | None | ||
548 | } | ||
549 | } | ||
550 | |||
551 | crate::ImplItem::Const(konst) => { | ||
552 | let data = konst.data(self.db); | ||
553 | if segment.name == *data.name() { | ||
554 | Some(konst.into()) | ||
555 | } else { | ||
556 | None | ||
557 | } | ||
558 | } | ||
559 | 561 | ||
560 | // FIXME: Resolve associated types | 562 | // FIXME: Resolve associated types |
561 | crate::ImplItem::TypeAlias(_) => None, | 563 | crate::ImplItem::TypeAlias(_) => { |
562 | }; | 564 | // Some(TypeNs::TypeAlias(..)) |
563 | match matching_def { | 565 | None::<TypeNs> |
564 | Some(_) => { | ||
565 | self.write_assoc_resolution(id, item); | ||
566 | matching_def | ||
567 | } | 566 | } |
568 | None => None, | ||
569 | } | 567 | } |
570 | })?; | 568 | })?; |
571 | |||
572 | resolved = Resolution::Def(item); | ||
573 | } | 569 | } |
574 | 570 | ||
575 | match resolved { | 571 | let segment = path.segments.last().unwrap(); |
576 | Resolution::Def(def) => { | 572 | let def = ty.clone().iterate_impl_items(self.db, krate, |item| { |
577 | let typable: Option<TypableDef> = def.into(); | 573 | let matching_def: Option<ValueNs> = match item { |
578 | let typable = typable?; | 574 | crate::ImplItem::Method(func) => { |
579 | let mut ty = self.db.type_for_def(typable, Namespace::Values); | 575 | if segment.name == func.name(self.db) { |
580 | if let Some(sts) = self.find_self_types(&def, actual_def_ty) { | 576 | Some(ValueNs::Function(func)) |
581 | ty = ty.subst(&sts); | 577 | } else { |
578 | None | ||
579 | } | ||
582 | } | 580 | } |
583 | 581 | ||
584 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | 582 | crate::ImplItem::Const(konst) => { |
585 | let ty = ty.subst(&substs); | 583 | let data = konst.data(self.db); |
586 | let ty = self.insert_type_vars(ty); | 584 | if segment.name == *data.name() { |
587 | let ty = self.normalize_associated_types_in(ty); | 585 | Some(ValueNs::Const(konst)) |
588 | Some(ty) | 586 | } else { |
589 | } | 587 | None |
590 | Resolution::LocalBinding(pat) => { | 588 | } |
591 | let ty = self.result.type_of_pat.get(pat)?.clone(); | 589 | } |
592 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); | 590 | crate::ImplItem::TypeAlias(_) => None, |
593 | Some(ty) | 591 | }; |
594 | } | 592 | match matching_def { |
595 | Resolution::GenericParam(..) => { | 593 | Some(_) => { |
596 | // generic params can't refer to values... yet | 594 | self.write_assoc_resolution(id, item); |
597 | None | 595 | matching_def |
598 | } | 596 | } |
599 | Resolution::SelfType(_) => { | 597 | None => None, |
600 | log::error!("path expr {:?} resolved to Self type in values ns", path); | ||
601 | None | ||
602 | } | 598 | } |
603 | } | 599 | })?; |
600 | let self_types = self.find_self_types(&def, ty); | ||
601 | Some((def, self_types)) | ||
604 | } | 602 | } |
605 | 603 | ||
606 | fn find_self_types(&self, def: &ModuleDef, actual_def_ty: Option<Ty>) -> Option<Substs> { | 604 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { |
607 | let actual_def_ty = actual_def_ty?; | 605 | if let ValueNs::Function(func) = def { |
608 | |||
609 | if let crate::ModuleDef::Function(func) = def { | ||
610 | // We only do the infer if parent has generic params | 606 | // We only do the infer if parent has generic params |
611 | let gen = func.generic_params(self.db); | 607 | let gen = func.generic_params(self.db); |
612 | if gen.count_parent_params() == 0 { | 608 | if gen.count_parent_params() == 0 { |
@@ -641,30 +637,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
641 | None => return (Ty::Unknown, None), | 637 | None => return (Ty::Unknown, None), |
642 | }; | 638 | }; |
643 | let resolver = &self.resolver; | 639 | let resolver = &self.resolver; |
644 | let typable: Option<TypableDef> = | 640 | let def: TypableDef = |
645 | // FIXME: this should resolve assoc items as well, see this example: | 641 | // FIXME: this should resolve assoc items as well, see this example: |
646 | // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 | 642 | // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 |
647 | match resolver.resolve_path_without_assoc_items(self.db, &path).take_types() { | 643 | match resolver.resolve_path_in_type_ns_fully(self.db, &path) { |
648 | Some(Resolution::Def(def)) => def.into(), | 644 | Some(TypeNs::Adt(Adt::Struct(it))) => it.into(), |
649 | Some(Resolution::LocalBinding(..)) => { | 645 | Some(TypeNs::Adt(Adt::Union(it))) => it.into(), |
650 | // this cannot happen | 646 | Some(TypeNs::EnumVariant(it)) => it.into(), |
651 | log::error!("path resolved to local binding in type ns"); | 647 | Some(TypeNs::TypeAlias(it)) => it.into(), |
652 | return (Ty::Unknown, None); | 648 | |
653 | } | 649 | Some(TypeNs::SelfType(_)) | |
654 | Some(Resolution::GenericParam(..)) => { | 650 | Some(TypeNs::GenericParam(_)) | |
655 | // generic params can't be used in struct literals | 651 | Some(TypeNs::BuiltinType(_)) | |
656 | return (Ty::Unknown, None); | 652 | Some(TypeNs::Trait(_)) | |
657 | } | 653 | Some(TypeNs::Adt(Adt::Enum(_))) | |
658 | Some(Resolution::SelfType(..)) => { | 654 | None => { |
659 | // FIXME this is allowed in an impl for a struct, handle this | 655 | return (Ty::Unknown, None) |
660 | return (Ty::Unknown, None); | ||
661 | } | 656 | } |
662 | None => return (Ty::Unknown, None), | ||
663 | }; | 657 | }; |
664 | let def = match typable { | ||
665 | None => return (Ty::Unknown, None), | ||
666 | Some(it) => it, | ||
667 | }; | ||
668 | // FIXME remove the duplication between here and `Ty::from_path`? | 658 | // FIXME remove the duplication between here and `Ty::from_path`? |
669 | let substs = Ty::substs_from_path(self.db, resolver, path, def); | 659 | let substs = Ty::substs_from_path(self.db, resolver, path, def); |
670 | match def { | 660 | match def { |