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 | |
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')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 256 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 108 |
2 files changed, 176 insertions, 188 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 { |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 946e9e9fb..3fdb2ca92 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -19,7 +19,7 @@ use crate::{ | |||
19 | generics::{GenericDef, WherePredicate}, | 19 | generics::{GenericDef, WherePredicate}, |
20 | nameres::Namespace, | 20 | nameres::Namespace, |
21 | path::{GenericArg, PathSegment}, | 21 | path::{GenericArg, PathSegment}, |
22 | resolve::{Resolution, Resolver}, | 22 | resolve::{Resolver, TypeNs}, |
23 | ty::Adt, | 23 | ty::Adt, |
24 | type_ref::{TypeBound, TypeRef}, | 24 | type_ref::{TypeBound, TypeRef}, |
25 | BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, | 25 | BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, |
@@ -88,16 +88,47 @@ impl Ty { | |||
88 | 88 | ||
89 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { | 89 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { |
90 | // Resolve the path (in type namespace) | 90 | // Resolve the path (in type namespace) |
91 | let (resolution, remaining_index) = resolver.resolve_path_segments(db, path).into_inner(); | 91 | let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { |
92 | let resolution = resolution.take_types(); | 92 | Some(it) => it, |
93 | 93 | None => return Ty::Unknown, | |
94 | let def = match resolution { | 94 | }; |
95 | Some(Resolution::Def(def)) => def, | 95 | |
96 | Some(Resolution::LocalBinding(..)) => { | 96 | let typable: TypableDef = match resolution { |
97 | // this should never happen | 97 | TypeNs::Trait(trait_) => { |
98 | panic!("path resolved to local binding in type ns"); | 98 | let segment = match remaining_index { |
99 | None => path.segments.last().expect("resolved path has at least one element"), | ||
100 | Some(i) => &path.segments[i - 1], | ||
101 | }; | ||
102 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); | ||
103 | return if let Some(remaining_index) = remaining_index { | ||
104 | if remaining_index == path.segments.len() - 1 { | ||
105 | let segment = &path.segments[remaining_index]; | ||
106 | match trait_ref | ||
107 | .trait_ | ||
108 | .associated_type_by_name_including_super_traits(db, &segment.name) | ||
109 | { | ||
110 | Some(associated_ty) => { | ||
111 | // FIXME handle type parameters on the segment | ||
112 | Ty::Projection(ProjectionTy { | ||
113 | associated_ty, | ||
114 | parameters: trait_ref.substs, | ||
115 | }) | ||
116 | } | ||
117 | None => { | ||
118 | // associated type not found | ||
119 | Ty::Unknown | ||
120 | } | ||
121 | } | ||
122 | } else { | ||
123 | // FIXME more than one segment remaining, is this possible? | ||
124 | Ty::Unknown | ||
125 | } | ||
126 | } else { | ||
127 | // FIXME dyn Trait without the dyn | ||
128 | Ty::Unknown | ||
129 | }; | ||
99 | } | 130 | } |
100 | Some(Resolution::GenericParam(idx)) => { | 131 | TypeNs::GenericParam(idx) => { |
101 | if remaining_index.is_some() { | 132 | if remaining_index.is_some() { |
102 | // e.g. T::Item | 133 | // e.g. T::Item |
103 | return Ty::Unknown; | 134 | return Ty::Unknown; |
@@ -111,57 +142,24 @@ impl Ty { | |||
111 | .clone(), | 142 | .clone(), |
112 | }; | 143 | }; |
113 | } | 144 | } |
114 | Some(Resolution::SelfType(impl_block)) => { | 145 | TypeNs::SelfType(impl_block) => { |
115 | if remaining_index.is_some() { | 146 | if remaining_index.is_some() { |
116 | // e.g. Self::Item | 147 | // e.g. Self::Item |
117 | return Ty::Unknown; | 148 | return Ty::Unknown; |
118 | } | 149 | } |
119 | return impl_block.target_ty(db); | 150 | return impl_block.target_ty(db); |
120 | } | 151 | } |
121 | None => { | 152 | |
122 | // path did not resolve | 153 | TypeNs::Adt(it) => it.into(), |
123 | return Ty::Unknown; | 154 | TypeNs::BuiltinType(it) => it.into(), |
124 | } | 155 | TypeNs::TypeAlias(it) => it.into(), |
156 | // FIXME: report error | ||
157 | TypeNs::EnumVariant(_) => return Ty::Unknown, | ||
125 | }; | 158 | }; |
126 | 159 | ||
127 | if let ModuleDef::Trait(trait_) = def { | 160 | let ty = db.type_for_def(typable, Namespace::Types); |
128 | let segment = match remaining_index { | 161 | let substs = Ty::substs_from_path(db, resolver, path, typable); |
129 | None => path.segments.last().expect("resolved path has at least one element"), | 162 | ty.subst(&substs) |
130 | Some(i) => &path.segments[i - 1], | ||
131 | }; | ||
132 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); | ||
133 | if let Some(remaining_index) = remaining_index { | ||
134 | if remaining_index == path.segments.len() - 1 { | ||
135 | let segment = &path.segments[remaining_index]; | ||
136 | let associated_ty = match trait_ref | ||
137 | .trait_ | ||
138 | .associated_type_by_name_including_super_traits(db, &segment.name) | ||
139 | { | ||
140 | Some(t) => t, | ||
141 | None => { | ||
142 | // associated type not found | ||
143 | return Ty::Unknown; | ||
144 | } | ||
145 | }; | ||
146 | // FIXME handle type parameters on the segment | ||
147 | Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs }) | ||
148 | } else { | ||
149 | // FIXME more than one segment remaining, is this possible? | ||
150 | Ty::Unknown | ||
151 | } | ||
152 | } else { | ||
153 | // FIXME dyn Trait without the dyn | ||
154 | Ty::Unknown | ||
155 | } | ||
156 | } else { | ||
157 | let typable: TypableDef = match def.into() { | ||
158 | None => return Ty::Unknown, | ||
159 | Some(it) => it, | ||
160 | }; | ||
161 | let ty = db.type_for_def(typable, Namespace::Types); | ||
162 | let substs = Ty::substs_from_path(db, resolver, path, typable); | ||
163 | ty.subst(&substs) | ||
164 | } | ||
165 | } | 163 | } |
166 | 164 | ||
167 | pub(super) fn substs_from_path_segment( | 165 | pub(super) fn substs_from_path_segment( |
@@ -278,8 +276,8 @@ impl TraitRef { | |||
278 | path: &Path, | 276 | path: &Path, |
279 | explicit_self_ty: Option<Ty>, | 277 | explicit_self_ty: Option<Ty>, |
280 | ) -> Option<Self> { | 278 | ) -> Option<Self> { |
281 | let resolved = match resolver.resolve_path_without_assoc_items(db, &path).take_types()? { | 279 | let resolved = match resolver.resolve_path_in_type_ns_fully(db, &path)? { |
282 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | 280 | TypeNs::Trait(tr) => tr, |
283 | _ => return None, | 281 | _ => return None, |
284 | }; | 282 | }; |
285 | let segment = path.segments.last().expect("path should have at least one segment"); | 283 | let segment = path.segments.last().expect("path should have at least one segment"); |