diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-22 19:58:22 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-22 19:58:22 +0000 |
commit | 3d8a0982a12f3aa4b8c193a841f864b15c3cb66e (patch) | |
tree | e20ae00628cc28417e22621f583ba6988677ffcd /crates/ra_hir/src/ty.rs | |
parent | bb665a70627cbc2f4fb930fefb04899941b6afa6 (diff) | |
parent | 247d1c17b385ff8a8c1dda2e899495146b643b98 (diff) |
Merge #866
866: Implement basic support for Associated Methods r=flodiebold a=vipentti
This is my attempt at learning to understand how the type inference works by adding basic support for associated methods. Currently it does not resolve associated types or constants.
The basic idea is that `Resolver::resolve_path` returns a new `PathResult` type, which has two variants, `FullyResolved` and `PartiallyResolved`, fully resolved matches the previous behavior, where as `PartiallyResolved` contains the `PerNs<Resolution` in addition to a `segment_index` which contains the index of the segment which we failed to resolve. This index can then be used to continue inference in `infer_path_expr` using the `Type` we managed to resolve.
This changes some of the previous apis, so looking for feedback and suggestions.
This should enable fixing #832
Co-authored-by: Ville Penttinen <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 1a3e1994f..ae595c16d 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -37,7 +37,7 @@ use crate::{ | |||
37 | FnSignature, ModuleDef, AdtDef, | 37 | FnSignature, ModuleDef, AdtDef, |
38 | HirDatabase, | 38 | HirDatabase, |
39 | type_ref::{TypeRef, Mutability}, | 39 | type_ref::{TypeRef, Mutability}, |
40 | name::KnownName, | 40 | name::{KnownName}, |
41 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, | 41 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, |
42 | generics::GenericParams, | 42 | generics::GenericParams, |
43 | path::{ GenericArgs, GenericArg}, | 43 | path::{ GenericArgs, GenericArg}, |
@@ -1166,15 +1166,55 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1166 | } | 1166 | } |
1167 | 1167 | ||
1168 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> { | 1168 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> { |
1169 | let resolved = resolver.resolve_path(self.db, &path).take_values()?; | 1169 | let resolved = resolver.resolve_path_segments(self.db, &path); |
1170 | |||
1171 | let (def, remaining_index) = resolved.into_inner(); | ||
1172 | |||
1173 | // if the remaining_index is None, we expect the path | ||
1174 | // to be fully resolved, in this case we continue with | ||
1175 | // the default by attempting to `take_values´ from the resolution. | ||
1176 | // Otherwise the path was partially resolved, which means | ||
1177 | // we might have resolved into a type for which | ||
1178 | // we may find some associated item starting at the | ||
1179 | // path.segment pointed to by `remaining_index´ | ||
1180 | let resolved = | ||
1181 | if remaining_index.is_none() { def.take_values()? } else { def.take_types()? }; | ||
1182 | |||
1170 | match resolved { | 1183 | match resolved { |
1171 | Resolution::Def(def) => { | 1184 | Resolution::Def(def) => { |
1172 | let typable: Option<TypableDef> = def.into(); | 1185 | let typable: Option<TypableDef> = def.into(); |
1173 | let typable = typable?; | 1186 | let typable = typable?; |
1174 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | 1187 | |
1175 | let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs); | 1188 | if let Some(remaining_index) = remaining_index { |
1176 | let ty = self.insert_type_vars(ty); | 1189 | let ty = self.db.type_for_def(typable, Namespace::Types); |
1177 | Some(ty) | 1190 | // TODO: Keep resolving the segments |
1191 | // if we have more segments to process | ||
1192 | let segment = &path.segments[remaining_index]; | ||
1193 | |||
1194 | // Attempt to find an impl_item for the type which has a name matching | ||
1195 | // the current segment | ||
1196 | let ty = ty.iterate_impl_items(self.db, |item| match item { | ||
1197 | crate::ImplItem::Method(func) => { | ||
1198 | let sig = func.signature(self.db); | ||
1199 | if segment.name == *sig.name() { | ||
1200 | return Some(type_for_fn(self.db, func)); | ||
1201 | } | ||
1202 | None | ||
1203 | } | ||
1204 | |||
1205 | // TODO: Resolve associated const | ||
1206 | crate::ImplItem::Const(_) => None, | ||
1207 | |||
1208 | // TODO: Resolve associated types | ||
1209 | crate::ImplItem::Type(_) => None, | ||
1210 | }); | ||
1211 | ty | ||
1212 | } else { | ||
1213 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | ||
1214 | let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs); | ||
1215 | let ty = self.insert_type_vars(ty); | ||
1216 | Some(ty) | ||
1217 | } | ||
1178 | } | 1218 | } |
1179 | Resolution::LocalBinding(pat) => { | 1219 | Resolution::LocalBinding(pat) => { |
1180 | let ty = self.type_of_pat.get(pat)?; | 1220 | let ty = self.type_of_pat.get(pat)?; |