aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/ty/infer.rs176
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs195
2 files changed, 199 insertions, 172 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 70da7f311..81a8623bf 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -45,13 +45,14 @@ use crate::{
45 name, 45 name,
46 nameres::Namespace, 46 nameres::Namespace,
47 path::{known, GenericArg, GenericArgs}, 47 path::{known, GenericArg, GenericArgs},
48 resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, 48 resolve::{Resolver, TypeNs},
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, FnData, Function, HasBody, Name, Path, StructField, 51 Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField,
52}; 52};
53 53
54mod unify; 54mod unify;
55mod path;
55 56
56/// The entry point of type inference. 57/// The entry point of type inference.
57pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { 58pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> {
@@ -466,175 +467,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
466 }) 467 })
467 } 468 }
468 469
469 fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> {
470 let (value, self_subst) = if let crate::PathKind::Type(type_ref) = &path.kind {
471 if path.segments.is_empty() {
472 // This can't actually happen syntax-wise
473 return None;
474 }
475 let ty = self.make_ty(type_ref);
476 let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1];
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 }
491 }
492 };
493
494 let typable: TypableDef = match value {
495 ValueNs::LocalBinding(pat) => {
496 let ty = self.result.type_of_pat.get(pat)?.clone();
497 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
498 return Some(ty);
499 }
500 ValueNs::Function(it) => it.into(),
501 ValueNs::Const(it) => it.into(),
502 ValueNs::Static(it) => it.into(),
503 ValueNs::Struct(it) => it.into(),
504 ValueNs::EnumVariant(it) => it.into(),
505 };
506
507 let mut ty = self.db.type_for_def(typable, Namespace::Values);
508 if let Some(self_subst) = self_subst {
509 ty = ty.subst(&self_subst);
510 }
511
512 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
513 let ty = ty.subst(&substs);
514 let ty = self.insert_type_vars(ty);
515 let ty = self.normalize_associated_types_in(ty);
516 Some(ty)
517 }
518
519 fn resolve_assoc_item(
520 &mut self,
521 def: TypeNs,
522 path: &Path,
523 remaining_index: usize,
524 id: ExprOrPatId,
525 ) -> Option<(ValueNs, Option<Substs>)> {
526 assert!(remaining_index < path.segments.len());
527 // there may be more intermediate segments between the resolved one and
528 // the end. Only the last segment needs to be resolved to a value; from
529 // the segments before that, we need to get either a type or a trait ref.
530
531 let resolved_segment = &path.segments[remaining_index - 1];
532 let remaining_segments = &path.segments[remaining_index..];
533 let is_before_last = remaining_segments.len() == 1;
534
535 match (def, is_before_last) {
536 (TypeNs::Trait(_trait), true) => {
537 // FIXME Associated item of trait, e.g. `Default::default`
538 None
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 }
556
557 let segment =
558 remaining_segments.last().expect("there should be at least one segment here");
559
560 self.resolve_ty_assoc_item(ty, segment, id)
561 }
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 item = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
580 AssocItem::Function(func) => {
581 if segment.name == func.name(self.db) {
582 Some(AssocItem::Function(func))
583 } else {
584 None
585 }
586 }
587
588 AssocItem::Const(konst) => {
589 if konst.name(self.db).map_or(false, |n| n == segment.name) {
590 Some(AssocItem::Const(konst))
591 } else {
592 None
593 }
594 }
595 AssocItem::TypeAlias(_) => None,
596 })?;
597 let def = match item {
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 }
607
608 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
609 if let ValueNs::Function(func) = def {
610 // We only do the infer if parent has generic params
611 let gen = func.generic_params(self.db);
612 if gen.count_parent_params() == 0 {
613 return None;
614 }
615
616 let impl_block = func.impl_block(self.db)?.target_ty(self.db);
617 let impl_block_substs = impl_block.substs()?;
618 let actual_substs = actual_def_ty.substs()?;
619
620 let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()];
621
622 // The following code *link up* the function actual parma type
623 // and impl_block type param index
624 impl_block_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| {
625 if let Ty::Param { idx, .. } = param {
626 if let Some(s) = new_substs.get_mut(*idx as usize) {
627 *s = pty.clone();
628 }
629 }
630 });
631
632 Some(Substs(new_substs.into()))
633 } else {
634 None
635 }
636 }
637
638 fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) { 470 fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) {
639 let path = match path { 471 let path = match path {
640 Some(path) => path, 472 Some(path) => path,
@@ -807,7 +639,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
807 Pat::Path(path) => { 639 Pat::Path(path) => {
808 // FIXME use correct resolver for the surrounding expression 640 // FIXME use correct resolver for the surrounding expression
809 let resolver = self.resolver.clone(); 641 let resolver = self.resolver.clone();
810 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) 642 self.infer_path(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown)
811 } 643 }
812 Pat::Bind { mode, name: _, subpat } => { 644 Pat::Bind { mode, name: _, subpat } => {
813 let mode = if mode == &BindingAnnotation::Unannotated { 645 let mode = if mode == &BindingAnnotation::Unannotated {
@@ -1121,7 +953,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1121 Expr::Path(p) => { 953 Expr::Path(p) => {
1122 // FIXME this could be more efficient... 954 // FIXME this could be more efficient...
1123 let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); 955 let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr);
1124 self.infer_path_expr(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) 956 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown)
1125 } 957 }
1126 Expr::Continue => Ty::simple(TypeCtor::Never), 958 Expr::Continue => Ty::simple(TypeCtor::Never),
1127 Expr::Break { expr } => { 959 Expr::Break { expr } => {
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs
new file mode 100644
index 000000000..54aae4f0c
--- /dev/null
+++ b/crates/ra_hir/src/ty/infer/path.rs
@@ -0,0 +1,195 @@
1//! Path expression resolution.
2
3use super::{ExprOrPatId, InferenceContext};
4use crate::{
5 db::HirDatabase,
6 resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
7 ty::{Substs, Ty, TypableDef, TypeWalk},
8 AssocItem, HasGenericParams, Namespace, Path,
9};
10
11impl<'a, D: HirDatabase> InferenceContext<'a, D> {
12 pub(super) fn infer_path(
13 &mut self,
14 resolver: &Resolver,
15 path: &Path,
16 id: ExprOrPatId,
17 ) -> Option<Ty> {
18 let ty = self.resolve_value_path(resolver, path, id)?;
19 let ty = self.insert_type_vars(ty);
20 let ty = self.normalize_associated_types_in(ty);
21 Some(ty)
22 }
23
24 fn resolve_value_path(
25 &mut self,
26 resolver: &Resolver,
27 path: &Path,
28 id: ExprOrPatId,
29 ) -> Option<Ty> {
30 let (value, self_subst) = if let crate::PathKind::Type(type_ref) = &path.kind {
31 if path.segments.is_empty() {
32 // This can't actually happen syntax-wise
33 return None;
34 }
35 let ty = self.make_ty(type_ref);
36 let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1];
37 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty);
38 self.resolve_ty_assoc_item(
39 ty,
40 path.segments.last().expect("path had at least one segment"),
41 id,
42 )?
43 } else {
44 let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?;
45
46 match value_or_partial {
47 ResolveValueResult::ValueNs(it) => (it, None),
48 ResolveValueResult::Partial(def, remaining_index) => {
49 self.resolve_assoc_item(def, path, remaining_index, id)?
50 }
51 }
52 };
53
54 let typable: TypableDef = match value {
55 ValueNs::LocalBinding(pat) => {
56 let ty = self.result.type_of_pat.get(pat)?.clone();
57 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
58 return Some(ty);
59 }
60 ValueNs::Function(it) => it.into(),
61 ValueNs::Const(it) => it.into(),
62 ValueNs::Static(it) => it.into(),
63 ValueNs::Struct(it) => it.into(),
64 ValueNs::EnumVariant(it) => it.into(),
65 };
66
67 let mut ty = self.db.type_for_def(typable, Namespace::Values);
68 if let Some(self_subst) = self_subst {
69 ty = ty.subst(&self_subst);
70 }
71
72 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
73 let ty = ty.subst(&substs);
74 Some(ty)
75 }
76
77 fn resolve_assoc_item(
78 &mut self,
79 def: TypeNs,
80 path: &Path,
81 remaining_index: usize,
82 id: ExprOrPatId,
83 ) -> Option<(ValueNs, Option<Substs>)> {
84 assert!(remaining_index < path.segments.len());
85 // there may be more intermediate segments between the resolved one and
86 // the end. Only the last segment needs to be resolved to a value; from
87 // the segments before that, we need to get either a type or a trait ref.
88
89 let resolved_segment = &path.segments[remaining_index - 1];
90 let remaining_segments = &path.segments[remaining_index..];
91 let is_before_last = remaining_segments.len() == 1;
92
93 match (def, is_before_last) {
94 (TypeNs::Trait(_trait), true) => {
95 // FIXME Associated item of trait, e.g. `Default::default`
96 None
97 }
98 (def, _) => {
99 // Either we already have a type (e.g. `Vec::new`), or we have a
100 // trait but it's not the last segment, so the next segment
101 // should resolve to an associated type of that trait (e.g. `<T
102 // as Iterator>::Item::default`)
103 let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1];
104 let ty = Ty::from_partly_resolved_hir_path(
105 self.db,
106 &self.resolver,
107 def,
108 resolved_segment,
109 remaining_segments_for_ty,
110 );
111 if let Ty::Unknown = ty {
112 return None;
113 }
114
115 let segment =
116 remaining_segments.last().expect("there should be at least one segment here");
117
118 self.resolve_ty_assoc_item(ty, segment, id)
119 }
120 }
121 }
122
123 fn resolve_ty_assoc_item(
124 &mut self,
125 ty: Ty,
126 segment: &crate::path::PathSegment,
127 id: ExprOrPatId,
128 ) -> Option<(ValueNs, Option<Substs>)> {
129 if let Ty::Unknown = ty {
130 return None;
131 }
132
133 let krate = self.resolver.krate()?;
134
135 // Find impl
136 // FIXME: consider trait candidates
137 let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
138 AssocItem::Function(func) => {
139 if segment.name == func.name(self.db) {
140 Some(AssocItem::Function(func))
141 } else {
142 None
143 }
144 }
145
146 AssocItem::Const(konst) => {
147 if konst.name(self.db).map_or(false, |n| n == segment.name) {
148 Some(AssocItem::Const(konst))
149 } else {
150 None
151 }
152 }
153 AssocItem::TypeAlias(_) => None,
154 })?;
155 let def = match item {
156 AssocItem::Function(f) => ValueNs::Function(f),
157 AssocItem::Const(c) => ValueNs::Const(c),
158 AssocItem::TypeAlias(_) => unreachable!(),
159 };
160 let substs = self.find_self_types(&def, ty);
161
162 self.write_assoc_resolution(id, item);
163 Some((def, substs))
164 }
165
166 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
167 if let ValueNs::Function(func) = def {
168 // We only do the infer if parent has generic params
169 let gen = func.generic_params(self.db);
170 if gen.count_parent_params() == 0 {
171 return None;
172 }
173
174 let impl_block = func.impl_block(self.db)?.target_ty(self.db);
175 let impl_block_substs = impl_block.substs()?;
176 let actual_substs = actual_def_ty.substs()?;
177
178 let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()];
179
180 // The following code *link up* the function actual parma type
181 // and impl_block type param index
182 impl_block_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| {
183 if let Ty::Param { idx, .. } = param {
184 if let Some(s) = new_substs.get_mut(*idx as usize) {
185 *s = pty.clone();
186 }
187 }
188 });
189
190 Some(Substs(new_substs.into()))
191 } else {
192 None
193 }
194 }
195}