diff options
author | Florian Diebold <[email protected]> | 2019-09-23 17:53:52 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-23 17:53:52 +0100 |
commit | 4f1afe77b98566bd27bb587aff6fe2c744373b68 (patch) | |
tree | 890379c54508dcd291a0fd1b2c51ab153675e811 | |
parent | c2d9cca4e42ad052cf8a37ba3f6d9eacae07cbea (diff) |
Split off path expression inference code into submodule
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 176 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/path.rs | 195 |
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 | ||
54 | mod unify; | 54 | mod unify; |
55 | mod path; | ||
55 | 56 | ||
56 | /// The entry point of type inference. | 57 | /// The entry point of type inference. |
57 | pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { | 58 | pub 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 | |||
3 | use super::{ExprOrPatId, InferenceContext}; | ||
4 | use crate::{ | ||
5 | db::HirDatabase, | ||
6 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | ||
7 | ty::{Substs, Ty, TypableDef, TypeWalk}, | ||
8 | AssocItem, HasGenericParams, Namespace, Path, | ||
9 | }; | ||
10 | |||
11 | impl<'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 | } | ||