diff options
Diffstat (limited to 'crates/ra_hir/src/ty/infer.rs')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 5e4d49ffb..268d2c110 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -29,6 +29,7 @@ use crate::{ | |||
29 | Function, StructField, Path, Name, | 29 | Function, StructField, Path, Name, |
30 | FnSignature, AdtDef, | 30 | FnSignature, AdtDef, |
31 | HirDatabase, | 31 | HirDatabase, |
32 | ImplItem, | ||
32 | type_ref::{TypeRef, Mutability}, | 33 | type_ref::{TypeRef, Mutability}, |
33 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, | 34 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, |
34 | generics::GenericParams, | 35 | generics::GenericParams, |
@@ -54,6 +55,14 @@ pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> { | |||
54 | Arc::new(ctx.resolve_all()) | 55 | Arc::new(ctx.resolve_all()) |
55 | } | 56 | } |
56 | 57 | ||
58 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | ||
59 | enum ExprOrPatId { | ||
60 | ExprId(ExprId), | ||
61 | PatId(PatId), | ||
62 | } | ||
63 | |||
64 | impl_froms!(ExprOrPatId: ExprId, PatId); | ||
65 | |||
57 | /// The result of type inference: A mapping from expressions and patterns to types. | 66 | /// The result of type inference: A mapping from expressions and patterns to types. |
58 | #[derive(Clone, PartialEq, Eq, Debug)] | 67 | #[derive(Clone, PartialEq, Eq, Debug)] |
59 | pub struct InferenceResult { | 68 | pub struct InferenceResult { |
@@ -61,6 +70,8 @@ pub struct InferenceResult { | |||
61 | method_resolutions: FxHashMap<ExprId, Function>, | 70 | method_resolutions: FxHashMap<ExprId, Function>, |
62 | /// For each field access expr, records the field it resolves to. | 71 | /// For each field access expr, records the field it resolves to. |
63 | field_resolutions: FxHashMap<ExprId, StructField>, | 72 | field_resolutions: FxHashMap<ExprId, StructField>, |
73 | /// For each associated item record what it resolves to | ||
74 | assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>, | ||
64 | pub(super) type_of_expr: ArenaMap<ExprId, Ty>, | 75 | pub(super) type_of_expr: ArenaMap<ExprId, Ty>, |
65 | pub(super) type_of_pat: ArenaMap<PatId, Ty>, | 76 | pub(super) type_of_pat: ArenaMap<PatId, Ty>, |
66 | } | 77 | } |
@@ -72,6 +83,12 @@ impl InferenceResult { | |||
72 | pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> { | 83 | pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> { |
73 | self.field_resolutions.get(&expr).map(|it| *it) | 84 | self.field_resolutions.get(&expr).map(|it| *it) |
74 | } | 85 | } |
86 | pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<ImplItem> { | ||
87 | self.assoc_resolutions.get(&id.into()).map(|it| *it) | ||
88 | } | ||
89 | pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<ImplItem> { | ||
90 | self.assoc_resolutions.get(&id.into()).map(|it| *it) | ||
91 | } | ||
75 | } | 92 | } |
76 | 93 | ||
77 | impl Index<ExprId> for InferenceResult { | 94 | impl Index<ExprId> for InferenceResult { |
@@ -99,6 +116,7 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
99 | var_unification_table: InPlaceUnificationTable<TypeVarId>, | 116 | var_unification_table: InPlaceUnificationTable<TypeVarId>, |
100 | method_resolutions: FxHashMap<ExprId, Function>, | 117 | method_resolutions: FxHashMap<ExprId, Function>, |
101 | field_resolutions: FxHashMap<ExprId, StructField>, | 118 | field_resolutions: FxHashMap<ExprId, StructField>, |
119 | assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>, | ||
102 | type_of_expr: ArenaMap<ExprId, Ty>, | 120 | type_of_expr: ArenaMap<ExprId, Ty>, |
103 | type_of_pat: ArenaMap<PatId, Ty>, | 121 | type_of_pat: ArenaMap<PatId, Ty>, |
104 | /// The return type of the function being inferred. | 122 | /// The return type of the function being inferred. |
@@ -110,6 +128,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
110 | InferenceContext { | 128 | InferenceContext { |
111 | method_resolutions: FxHashMap::default(), | 129 | method_resolutions: FxHashMap::default(), |
112 | field_resolutions: FxHashMap::default(), | 130 | field_resolutions: FxHashMap::default(), |
131 | assoc_resolutions: FxHashMap::default(), | ||
113 | type_of_expr: ArenaMap::default(), | 132 | type_of_expr: ArenaMap::default(), |
114 | type_of_pat: ArenaMap::default(), | 133 | type_of_pat: ArenaMap::default(), |
115 | var_unification_table: InPlaceUnificationTable::new(), | 134 | var_unification_table: InPlaceUnificationTable::new(), |
@@ -135,6 +154,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
135 | InferenceResult { | 154 | InferenceResult { |
136 | method_resolutions: self.method_resolutions, | 155 | method_resolutions: self.method_resolutions, |
137 | field_resolutions: self.field_resolutions, | 156 | field_resolutions: self.field_resolutions, |
157 | assoc_resolutions: self.assoc_resolutions, | ||
138 | type_of_expr: expr_types, | 158 | type_of_expr: expr_types, |
139 | type_of_pat: pat_types, | 159 | type_of_pat: pat_types, |
140 | } | 160 | } |
@@ -152,6 +172,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
152 | self.field_resolutions.insert(expr, field); | 172 | self.field_resolutions.insert(expr, field); |
153 | } | 173 | } |
154 | 174 | ||
175 | fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: ImplItem) { | ||
176 | self.assoc_resolutions.insert(id, item); | ||
177 | } | ||
178 | |||
155 | fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { | 179 | fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { |
156 | self.type_of_pat.insert(pat, ty); | 180 | self.type_of_pat.insert(pat, ty); |
157 | } | 181 | } |
@@ -341,7 +365,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
341 | }) | 365 | }) |
342 | } | 366 | } |
343 | 367 | ||
344 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> { | 368 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> { |
345 | let resolved = resolver.resolve_path_segments(self.db, &path); | 369 | let resolved = resolver.resolve_path_segments(self.db, &path); |
346 | 370 | ||
347 | let (def, remaining_index) = resolved.into_inner(); | 371 | let (def, remaining_index) = resolved.into_inner(); |
@@ -393,26 +417,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
393 | // Attempt to find an impl_item for the type which has a name matching | 417 | // Attempt to find an impl_item for the type which has a name matching |
394 | // the current segment | 418 | // the current segment |
395 | log::debug!("looking for path segment: {:?}", segment); | 419 | log::debug!("looking for path segment: {:?}", segment); |
396 | let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| match item { | 420 | let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| { |
397 | crate::ImplItem::Method(func) => { | 421 | let matching_def: Option<crate::ModuleDef> = match item { |
398 | let sig = func.signature(self.db); | 422 | crate::ImplItem::Method(func) => { |
399 | if segment.name == *sig.name() { | 423 | let sig = func.signature(self.db); |
400 | return Some(func.into()); | 424 | if segment.name == *sig.name() { |
425 | Some(func.into()) | ||
426 | } else { | ||
427 | None | ||
428 | } | ||
401 | } | 429 | } |
402 | None | ||
403 | } | ||
404 | 430 | ||
405 | crate::ImplItem::Const(konst) => { | 431 | crate::ImplItem::Const(konst) => { |
406 | let sig = konst.signature(self.db); | 432 | let sig = konst.signature(self.db); |
407 | if segment.name == *sig.name() { | 433 | if segment.name == *sig.name() { |
408 | return Some(konst.into()); | 434 | Some(konst.into()) |
435 | } else { | ||
436 | None | ||
437 | } | ||
409 | } | 438 | } |
410 | None | ||
411 | } | ||
412 | 439 | ||
413 | // TODO: Resolve associated types | 440 | // TODO: Resolve associated types |
414 | crate::ImplItem::TypeAlias(_) => None, | 441 | crate::ImplItem::TypeAlias(_) => None, |
442 | }; | ||
443 | match matching_def { | ||
444 | Some(_) => { | ||
445 | self.write_assoc_resolution(id, item); | ||
446 | return matching_def; | ||
447 | } | ||
448 | None => None, | ||
449 | } | ||
415 | })?; | 450 | })?; |
451 | |||
416 | resolved = Resolution::Def(item.into()); | 452 | resolved = Resolution::Def(item.into()); |
417 | } | 453 | } |
418 | 454 | ||
@@ -420,7 +456,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
420 | Resolution::Def(def) => { | 456 | Resolution::Def(def) => { |
421 | let typable: Option<TypableDef> = def.into(); | 457 | let typable: Option<TypableDef> = def.into(); |
422 | let typable = typable?; | 458 | let typable = typable?; |
423 | |||
424 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | 459 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); |
425 | let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs); | 460 | let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs); |
426 | let ty = self.insert_type_vars(ty); | 461 | let ty = self.insert_type_vars(ty); |
@@ -572,7 +607,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
572 | Pat::Path(path) => { | 607 | Pat::Path(path) => { |
573 | // TODO use correct resolver for the surrounding expression | 608 | // TODO use correct resolver for the surrounding expression |
574 | let resolver = self.resolver.clone(); | 609 | let resolver = self.resolver.clone(); |
575 | self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown) | 610 | self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) |
576 | } | 611 | } |
577 | Pat::Bind { mode, name: _name, subpat } => { | 612 | Pat::Bind { mode, name: _name, subpat } => { |
578 | let inner_ty = if let Some(subpat) = subpat { | 613 | let inner_ty = if let Some(subpat) = subpat { |
@@ -782,7 +817,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
782 | Expr::Path(p) => { | 817 | Expr::Path(p) => { |
783 | // TODO this could be more efficient... | 818 | // TODO this could be more efficient... |
784 | let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); | 819 | let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); |
785 | self.infer_path_expr(&resolver, p).unwrap_or(Ty::Unknown) | 820 | self.infer_path_expr(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) |
786 | } | 821 | } |
787 | Expr::Continue => Ty::Never, | 822 | Expr::Continue => Ty::Never, |
788 | Expr::Break { expr } => { | 823 | Expr::Break { expr } => { |