aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-07-07 16:20:09 +0100
committerbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-07-07 16:20:09 +0100
commit1b38ca3b8739230af1cc69884b5b11650b5fcb46 (patch)
tree02f5ae58fed812857cc299299ae5e0bd6f5836ce
parent6c31f5b0a79c8b97110aaf854b839b57811c375a (diff)
parentf7cd40d8306dfd3f2c55ad97de5167319350a592 (diff)
Merge #1501
1501: Infer for loop variable r=flodiebold a=unrealhoang My take on https://github.com/rust-analyzer/rust-analyzer/issues/1425 Co-authored-by: Unreal Hoang <[email protected]>
-rw-r--r--crates/ra_hir/src/name.rs14
-rw-r--r--crates/ra_hir/src/ty/infer.rs124
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs29
-rw-r--r--crates/ra_hir/src/ty/tests.rs36
-rw-r--r--crates/ra_hir/src/ty/traits.rs2
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
162impl AsName for KnownName { 172impl 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
29use super::{ 29use 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};
34use crate::{ 34use 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
51mod unify; 55mod 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
3use super::InferenceContext; 3use super::InferenceContext;
4use crate::db::HirDatabase; 4use crate::db::HirDatabase;
5use crate::ty::{Canonical, InferTy, TraitRef, Ty}; 5use crate::ty::{Canonical, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty};
6 6
7impl<'a, D: HirDatabase> InferenceContext<'a, D> { 7impl<'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
100impl<T> Canonicalized<T> { 127impl<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]
24fn infer_for_loop() {
25 let (mut db, pos) = MockDatabase::with_position(
26 r#"
27//- /main.rs
28struct Vec<T> {}
29impl<T> Vec<T> {
30 fn new() -> Self { Vec {} }
31 fn push(&mut self, t: T) { }
32}
33
34impl<T> ::std::iter::IntoIterator for Vec<T> {
35 type Item=T;
36}
37fn test() {
38 let v = Vec::new();
39 v.push("foo");
40 for x in v {
41 x<|>;
42 }
43}
44
45//- /lib.rs
46mod 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]
24fn infer_basics() { 60fn 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
81impl Obligation { 81impl Obligation {