diff options
author | Unreal Hoang <[email protected]> | 2019-07-07 08:31:09 +0100 |
---|---|---|
committer | Unreal Hoang <[email protected]> | 2019-07-07 14:26:51 +0100 |
commit | f7cd40d8306dfd3f2c55ad97de5167319350a592 (patch) | |
tree | 73d1da8789a0a6109805768d7f2cad3336d3453b /crates/ra_hir/src | |
parent | fee552d4873b1cce4e622c7eb2f0189b276b01be (diff) |
add projection to infer for loop variable
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/name.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 124 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 2 |
5 files changed, 170 insertions, 35 deletions
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 06a2dbc76..b71590560 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs | |||
@@ -86,6 +86,11 @@ impl Name { | |||
86 | "Self" => KnownName::SelfType, | 86 | "Self" => KnownName::SelfType, |
87 | "self" => KnownName::SelfParam, | 87 | "self" => KnownName::SelfParam, |
88 | "macro_rules" => KnownName::MacroRules, | 88 | "macro_rules" => KnownName::MacroRules, |
89 | |||
90 | "std" => KnownName::Std, | ||
91 | "iter" => KnownName::Iter, | ||
92 | "IntoIterator" => KnownName::IntoIterator, | ||
93 | "Item" => KnownName::Item, | ||
89 | _ => return None, | 94 | _ => return None, |
90 | }; | 95 | }; |
91 | Some(name) | 96 | Some(name) |
@@ -157,6 +162,11 @@ pub(crate) enum KnownName { | |||
157 | SelfParam, | 162 | SelfParam, |
158 | 163 | ||
159 | MacroRules, | 164 | MacroRules, |
165 | |||
166 | Std, | ||
167 | Iter, | ||
168 | IntoIterator, | ||
169 | Item, | ||
160 | } | 170 | } |
161 | 171 | ||
162 | impl AsName for KnownName { | 172 | impl AsName for KnownName { |
@@ -182,6 +192,10 @@ impl AsName for KnownName { | |||
182 | KnownName::SelfType => "Self", | 192 | KnownName::SelfType => "Self", |
183 | KnownName::SelfParam => "self", | 193 | KnownName::SelfParam => "self", |
184 | KnownName::MacroRules => "macro_rules", | 194 | KnownName::MacroRules => "macro_rules", |
195 | KnownName::Std => "std", | ||
196 | KnownName::Iter => "iter", | ||
197 | KnownName::IntoIterator => "IntoIterator", | ||
198 | KnownName::Item => "Item", | ||
185 | }; | 199 | }; |
186 | Name::new(s.into()) | 200 | Name::new(s.into()) |
187 | } | 201 | } |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index e79e5e223..973de70df 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -28,24 +28,28 @@ use test_utils::tested_by; | |||
28 | 28 | ||
29 | use super::{ | 29 | use super::{ |
30 | autoderef, method_resolution, op, primitive, | 30 | autoderef, method_resolution, op, primitive, |
31 | traits::{Guidance, Obligation, Solution}, | 31 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
32 | ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypableDef, TypeCtor, | 32 | ApplicationTy, CallableDef, ProjectionTy, Substs, TraitRef, Ty, TypableDef, TypeCtor, |
33 | }; | 33 | }; |
34 | use crate::{ | 34 | use crate::{ |
35 | adt::VariantDef, | 35 | adt::VariantDef, |
36 | code_model::{ModuleDef::Trait, TypeAlias}, | ||
36 | diagnostics::DiagnosticSink, | 37 | diagnostics::DiagnosticSink, |
37 | expr::{ | 38 | expr::{ |
38 | self, Array, BinaryOp, BindingAnnotation, Body, Expr, ExprId, FieldPat, Literal, Pat, | 39 | self, Array, BinaryOp, BindingAnnotation, Body, Expr, ExprId, FieldPat, Literal, Pat, |
39 | PatId, Statement, UnaryOp, | 40 | PatId, Statement, UnaryOp, |
40 | }, | 41 | }, |
41 | generics::{GenericParams, HasGenericParams}, | 42 | generics::{GenericParams, HasGenericParams}, |
42 | nameres::Namespace, | 43 | nameres::{Namespace, PerNs}, |
43 | path::{GenericArg, GenericArgs}, | 44 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, |
44 | resolve::{Resolution, Resolver}, | 45 | resolve::{ |
46 | Resolution::{self, Def}, | ||
47 | Resolver, | ||
48 | }, | ||
45 | ty::infer::diagnostics::InferenceDiagnostic, | 49 | ty::infer::diagnostics::InferenceDiagnostic, |
46 | type_ref::{Mutability, TypeRef}, | 50 | type_ref::{Mutability, TypeRef}, |
47 | AdtDef, ConstData, DefWithBody, FnData, Function, HirDatabase, ImplItem, ModuleDef, Name, Path, | 51 | AdtDef, AsName, ConstData, DefWithBody, FnData, Function, HirDatabase, ImplItem, KnownName, |
48 | StructField, | 52 | ModuleDef, Name, Path, StructField, |
49 | }; | 53 | }; |
50 | 54 | ||
51 | mod unify; | 55 | mod unify; |
@@ -323,34 +327,53 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
323 | fn resolve_obligations_as_possible(&mut self) { | 327 | fn resolve_obligations_as_possible(&mut self) { |
324 | let obligations = mem::replace(&mut self.obligations, Vec::new()); | 328 | let obligations = mem::replace(&mut self.obligations, Vec::new()); |
325 | for obligation in obligations { | 329 | for obligation in obligations { |
326 | let (solution, canonicalized) = match &obligation { | 330 | match &obligation { |
327 | Obligation::Trait(tr) => { | 331 | Obligation::Trait(tr) => { |
328 | let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone()); | 332 | let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone()); |
329 | ( | 333 | let solution = self |
330 | self.db.implements( | 334 | .db |
331 | self.resolver.krate().unwrap(), | 335 | .implements(self.resolver.krate().unwrap(), canonicalized.value.clone()); |
332 | canonicalized.value.clone(), | 336 | match solution { |
333 | ), | 337 | Some(Solution::Unique(substs)) => { |
334 | canonicalized, | 338 | canonicalized.apply_solution(self, substs.0); |
335 | ) | 339 | } |
336 | } | 340 | Some(Solution::Ambig(Guidance::Definite(substs))) => { |
337 | }; | 341 | canonicalized.apply_solution(self, substs.0); |
338 | match solution { | 342 | self.obligations.push(obligation); |
339 | Some(Solution::Unique(substs)) => { | 343 | } |
340 | canonicalized.apply_solution(self, substs.0); | 344 | Some(_) => { |
341 | } | 345 | // FIXME use this when trying to resolve everything at the end |
342 | Some(Solution::Ambig(Guidance::Definite(substs))) => { | 346 | self.obligations.push(obligation); |
343 | canonicalized.apply_solution(self, substs.0); | 347 | } |
344 | self.obligations.push(obligation); | 348 | None => { |
345 | } | 349 | // FIXME obligation cannot be fulfilled => diagnostic |
346 | Some(_) => { | 350 | } |
347 | // FIXME use this when trying to resolve everything at the end | 351 | }; |
348 | self.obligations.push(obligation); | ||
349 | } | 352 | } |
350 | None => { | 353 | Obligation::Projection(pr) => { |
351 | // FIXME obligation cannot be fulfilled => diagnostic | 354 | let canonicalized = self.canonicalizer().canonicalize_projection(pr.clone()); |
355 | let solution = self | ||
356 | .db | ||
357 | .normalize(self.resolver.krate().unwrap(), canonicalized.value.clone()); | ||
358 | |||
359 | match solution { | ||
360 | Some(Solution::Unique(substs)) => { | ||
361 | canonicalized.apply_solution(self, substs.0); | ||
362 | } | ||
363 | Some(Solution::Ambig(Guidance::Definite(substs))) => { | ||
364 | canonicalized.apply_solution(self, substs.0); | ||
365 | self.obligations.push(obligation); | ||
366 | } | ||
367 | Some(_) => { | ||
368 | // FIXME use this when trying to resolve everything at the end | ||
369 | self.obligations.push(obligation); | ||
370 | } | ||
371 | None => { | ||
372 | // FIXME obligation cannot be fulfilled => diagnostic | ||
373 | } | ||
374 | }; | ||
352 | } | 375 | } |
353 | } | 376 | }; |
354 | } | 377 | } |
355 | } | 378 | } |
356 | 379 | ||
@@ -967,8 +990,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
967 | Ty::unit() | 990 | Ty::unit() |
968 | } | 991 | } |
969 | Expr::For { iterable, body, pat } => { | 992 | Expr::For { iterable, body, pat } => { |
970 | let _iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | 993 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
971 | self.infer_pat(*pat, &Ty::Unknown, BindingMode::default()); | 994 | |
995 | let pat_ty = match self.resolve_into_iter_item() { | ||
996 | Some(into_iter_item_alias) => { | ||
997 | let pat_ty = self.new_type_var(); | ||
998 | let projection = ProjectionPredicate { | ||
999 | ty: pat_ty.clone(), | ||
1000 | projection_ty: ProjectionTy { | ||
1001 | associated_ty: into_iter_item_alias, | ||
1002 | parameters: vec![iterable_ty].into(), | ||
1003 | }, | ||
1004 | }; | ||
1005 | self.obligations.push(Obligation::Projection(projection)); | ||
1006 | self.resolve_ty_as_possible(&mut vec![], pat_ty) | ||
1007 | } | ||
1008 | None => Ty::Unknown, | ||
1009 | }; | ||
1010 | |||
1011 | self.infer_pat(*pat, &pat_ty, BindingMode::default()); | ||
972 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 1012 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
973 | Ty::unit() | 1013 | Ty::unit() |
974 | } | 1014 | } |
@@ -1301,6 +1341,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1301 | fn infer_body(&mut self) { | 1341 | fn infer_body(&mut self) { |
1302 | self.infer_expr(self.body.body_expr(), &Expectation::has_type(self.return_ty.clone())); | 1342 | self.infer_expr(self.body.body_expr(), &Expectation::has_type(self.return_ty.clone())); |
1303 | } | 1343 | } |
1344 | |||
1345 | fn resolve_into_iter_item(&self) -> Option<TypeAlias> { | ||
1346 | let into_iter_path = Path { | ||
1347 | kind: PathKind::Abs, | ||
1348 | segments: vec![ | ||
1349 | PathSegment { name: KnownName::Std.as_name(), args_and_bindings: None }, | ||
1350 | PathSegment { name: KnownName::Iter.as_name(), args_and_bindings: None }, | ||
1351 | PathSegment { name: KnownName::IntoIterator.as_name(), args_and_bindings: None }, | ||
1352 | ], | ||
1353 | }; | ||
1354 | |||
1355 | match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() { | ||
1356 | PerNs { types: Some(Def(Trait(trait_))), .. } => { | ||
1357 | Some(trait_.associated_type_by_name(self.db, KnownName::Item.as_name())?) | ||
1358 | } | ||
1359 | _ => None, | ||
1360 | } | ||
1361 | } | ||
1304 | } | 1362 | } |
1305 | 1363 | ||
1306 | /// The ID of a type variable. | 1364 | /// The ID of a type variable. |
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs index 49bf5b946..a24e5eb5c 100644 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ b/crates/ra_hir/src/ty/infer/unify.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use super::InferenceContext; | 3 | use super::InferenceContext; |
4 | use crate::db::HirDatabase; | 4 | use crate::db::HirDatabase; |
5 | use crate::ty::{Canonical, InferTy, TraitRef, Ty}; | 5 | use crate::ty::{Canonical, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty}; |
6 | 6 | ||
7 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 7 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
8 | pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> | 8 | pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> |
@@ -86,6 +86,25 @@ where | |||
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
89 | fn do_canonicalize_projection_ty(&mut self, projection_ty: ProjectionTy) -> ProjectionTy { | ||
90 | let params = projection_ty | ||
91 | .parameters | ||
92 | .iter() | ||
93 | .map(|ty| self.do_canonicalize_ty(ty.clone())) | ||
94 | .collect::<Vec<_>>(); | ||
95 | ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: params.into() } | ||
96 | } | ||
97 | |||
98 | fn do_canonicalize_projection_predicate( | ||
99 | &mut self, | ||
100 | projection: ProjectionPredicate, | ||
101 | ) -> ProjectionPredicate { | ||
102 | let ty = self.do_canonicalize_ty(projection.ty); | ||
103 | let projection_ty = self.do_canonicalize_projection_ty(projection.projection_ty); | ||
104 | |||
105 | ProjectionPredicate { ty, projection_ty } | ||
106 | } | ||
107 | |||
89 | pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | 108 | pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { |
90 | let result = self.do_canonicalize_ty(ty); | 109 | let result = self.do_canonicalize_ty(ty); |
91 | self.into_canonicalized(result) | 110 | self.into_canonicalized(result) |
@@ -95,6 +114,14 @@ where | |||
95 | let result = self.do_canonicalize_trait_ref(trait_ref); | 114 | let result = self.do_canonicalize_trait_ref(trait_ref); |
96 | self.into_canonicalized(result) | 115 | self.into_canonicalized(result) |
97 | } | 116 | } |
117 | |||
118 | pub fn canonicalize_projection( | ||
119 | mut self, | ||
120 | projection: ProjectionPredicate, | ||
121 | ) -> Canonicalized<ProjectionPredicate> { | ||
122 | let result = self.do_canonicalize_projection_predicate(projection); | ||
123 | self.into_canonicalized(result) | ||
124 | } | ||
98 | } | 125 | } |
99 | 126 | ||
100 | impl<T> Canonicalized<T> { | 127 | impl<T> Canonicalized<T> { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index aacd94a26..fe5e89f2d 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -21,6 +21,42 @@ use crate::{ | |||
21 | // update the snapshots. | 21 | // update the snapshots. |
22 | 22 | ||
23 | #[test] | 23 | #[test] |
24 | fn infer_for_loop() { | ||
25 | let (mut db, pos) = MockDatabase::with_position( | ||
26 | r#" | ||
27 | //- /main.rs | ||
28 | struct Vec<T> {} | ||
29 | impl<T> Vec<T> { | ||
30 | fn new() -> Self { Vec {} } | ||
31 | fn push(&mut self, t: T) { } | ||
32 | } | ||
33 | |||
34 | impl<T> ::std::iter::IntoIterator for Vec<T> { | ||
35 | type Item=T; | ||
36 | } | ||
37 | fn test() { | ||
38 | let v = Vec::new(); | ||
39 | v.push("foo"); | ||
40 | for x in v { | ||
41 | x<|>; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | //- /lib.rs | ||
46 | mod iter { | ||
47 | trait IntoIterator { | ||
48 | type Item; | ||
49 | } | ||
50 | } | ||
51 | "#, | ||
52 | ); | ||
53 | db.set_crate_graph_from_fixture(crate_graph! { | ||
54 | "main": ("/main.rs", ["std"]), | ||
55 | "std": ("/lib.rs", []), | ||
56 | }); | ||
57 | assert_eq!("&str", type_at_pos(&db, pos)); | ||
58 | } | ||
59 | #[test] | ||
24 | fn infer_basics() { | 60 | fn infer_basics() { |
25 | assert_snapshot_matches!( | 61 | assert_snapshot_matches!( |
26 | infer(r#" | 62 | infer(r#" |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 23a26a971..3e28852b6 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -75,7 +75,7 @@ pub enum Obligation { | |||
75 | /// Prove that a certain type implements a trait (the type is the `Self` type | 75 | /// Prove that a certain type implements a trait (the type is the `Self` type |
76 | /// parameter to the `TraitRef`). | 76 | /// parameter to the `TraitRef`). |
77 | Trait(TraitRef), | 77 | Trait(TraitRef), |
78 | // Projection(ProjectionPredicate), | 78 | Projection(ProjectionPredicate), |
79 | } | 79 | } |
80 | 80 | ||
81 | impl Obligation { | 81 | impl Obligation { |