Skip to content

Commit f7cd40d

Browse files
committed
add projection to infer for loop variable
1 parent fee552d commit f7cd40d

File tree

5 files changed

+170
-35
lines changed

5 files changed

+170
-35
lines changed

crates/ra_hir/src/name.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ impl Name {
8686
"Self" => KnownName::SelfType,
8787
"self" => KnownName::SelfParam,
8888
"macro_rules" => KnownName::MacroRules,
89+
90+
"std" => KnownName::Std,
91+
"iter" => KnownName::Iter,
92+
"IntoIterator" => KnownName::IntoIterator,
93+
"Item" => KnownName::Item,
8994
_ => return None,
9095
};
9196
Some(name)
@@ -157,6 +162,11 @@ pub(crate) enum KnownName {
157162
SelfParam,
158163

159164
MacroRules,
165+
166+
Std,
167+
Iter,
168+
IntoIterator,
169+
Item,
160170
}
161171

162172
impl AsName for KnownName {
@@ -182,6 +192,10 @@ impl AsName for KnownName {
182192
KnownName::SelfType => "Self",
183193
KnownName::SelfParam => "self",
184194
KnownName::MacroRules => "macro_rules",
195+
KnownName::Std => "std",
196+
KnownName::Iter => "iter",
197+
KnownName::IntoIterator => "IntoIterator",
198+
KnownName::Item => "Item",
185199
};
186200
Name::new(s.into())
187201
}

crates/ra_hir/src/ty/infer.rs

Lines changed: 91 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,28 @@ use test_utils::tested_by;
2828

2929
use super::{
3030
autoderef, method_resolution, op, primitive,
31-
traits::{Guidance, Obligation, Solution},
32-
ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypableDef, TypeCtor,
31+
traits::{Guidance, Obligation, ProjectionPredicate, Solution},
32+
ApplicationTy, CallableDef, ProjectionTy, Substs, TraitRef, Ty, TypableDef, TypeCtor,
3333
};
3434
use crate::{
3535
adt::VariantDef,
36+
code_model::{ModuleDef::Trait, TypeAlias},
3637
diagnostics::DiagnosticSink,
3738
expr::{
3839
self, Array, BinaryOp, BindingAnnotation, Body, Expr, ExprId, FieldPat, Literal, Pat,
3940
PatId, Statement, UnaryOp,
4041
},
4142
generics::{GenericParams, HasGenericParams},
42-
nameres::Namespace,
43-
path::{GenericArg, GenericArgs},
44-
resolve::{Resolution, Resolver},
43+
nameres::{Namespace, PerNs},
44+
path::{GenericArg, GenericArgs, PathKind, PathSegment},
45+
resolve::{
46+
Resolution::{self, Def},
47+
Resolver,
48+
},
4549
ty::infer::diagnostics::InferenceDiagnostic,
4650
type_ref::{Mutability, TypeRef},
47-
AdtDef, ConstData, DefWithBody, FnData, Function, HirDatabase, ImplItem, ModuleDef, Name, Path,
48-
StructField,
51+
AdtDef, AsName, ConstData, DefWithBody, FnData, Function, HirDatabase, ImplItem, KnownName,
52+
ModuleDef, Name, Path, StructField,
4953
};
5054

5155
mod unify;
@@ -323,34 +327,53 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
323327
fn resolve_obligations_as_possible(&mut self) {
324328
let obligations = mem::replace(&mut self.obligations, Vec::new());
325329
for obligation in obligations {
326-
let (solution, canonicalized) = match &obligation {
330+
match &obligation {
327331
Obligation::Trait(tr) => {
328332
let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone());
329-
(
330-
self.db.implements(
331-
self.resolver.krate().unwrap(),
332-
canonicalized.value.clone(),
333-
),
334-
canonicalized,
335-
)
336-
}
337-
};
338-
match solution {
339-
Some(Solution::Unique(substs)) => {
340-
canonicalized.apply_solution(self, substs.0);
341-
}
342-
Some(Solution::Ambig(Guidance::Definite(substs))) => {
343-
canonicalized.apply_solution(self, substs.0);
344-
self.obligations.push(obligation);
345-
}
346-
Some(_) => {
347-
// FIXME use this when trying to resolve everything at the end
348-
self.obligations.push(obligation);
333+
let solution = self
334+
.db
335+
.implements(self.resolver.krate().unwrap(), canonicalized.value.clone());
336+
match solution {
337+
Some(Solution::Unique(substs)) => {
338+
canonicalized.apply_solution(self, substs.0);
339+
}
340+
Some(Solution::Ambig(Guidance::Definite(substs))) => {
341+
canonicalized.apply_solution(self, substs.0);
342+
self.obligations.push(obligation);
343+
}
344+
Some(_) => {
345+
// FIXME use this when trying to resolve everything at the end
346+
self.obligations.push(obligation);
347+
}
348+
None => {
349+
// FIXME obligation cannot be fulfilled => diagnostic
350+
}
351+
};
349352
}
350-
None => {
351-
// FIXME obligation cannot be fulfilled => diagnostic
353+
Obligation::Projection(pr) => {
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+
};
352375
}
353-
}
376+
};
354377
}
355378
}
356379

@@ -967,8 +990,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
967990
Ty::unit()
968991
}
969992
Expr::For { iterable, body, pat } => {
970-
let _iterable_ty = self.infer_expr(*iterable, &Expectation::none());
971-
self.infer_pat(*pat, &Ty::Unknown, BindingMode::default());
993+
let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
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());
9721012
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
9731013
Ty::unit()
9741014
}
@@ -1301,6 +1341,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
13011341
fn infer_body(&mut self) {
13021342
self.infer_expr(self.body.body_expr(), &Expectation::has_type(self.return_ty.clone()));
13031343
}
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+
}
13041362
}
13051363

13061364
/// The ID of a type variable.

crates/ra_hir/src/ty/infer/unify.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use super::InferenceContext;
44
use crate::db::HirDatabase;
5-
use crate::ty::{Canonical, InferTy, TraitRef, Ty};
5+
use crate::ty::{Canonical, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty};
66

77
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
88
pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D>
@@ -86,6 +86,25 @@ where
8686
}
8787
}
8888

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+
89108
pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
90109
let result = self.do_canonicalize_ty(ty);
91110
self.into_canonicalized(result)
@@ -95,6 +114,14 @@ where
95114
let result = self.do_canonicalize_trait_ref(trait_ref);
96115
self.into_canonicalized(result)
97116
}
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+
}
98125
}
99126

100127
impl<T> Canonicalized<T> {

crates/ra_hir/src/ty/tests.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,42 @@ use crate::{
2020
// against snapshots of the expected results using insta. Use cargo-insta to
2121
// update the snapshots.
2222

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+
}
2359
#[test]
2460
fn infer_basics() {
2561
assert_snapshot_matches!(

crates/ra_hir/src/ty/traits.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pub enum Obligation {
7575
/// Prove that a certain type implements a trait (the type is the `Self` type
7676
/// parameter to the `TraitRef`).
7777
Trait(TraitRef),
78-
// Projection(ProjectionPredicate),
78+
Projection(ProjectionPredicate),
7979
}
8080

8181
impl Obligation {

0 commit comments

Comments
 (0)