mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-15 22:54:00 +00:00
Auto merge of #13311 - lowr:fix/for-loop-item-resolution, r=Veykril
fix: infer for-loop item type with `IntoIterator` and `Iterator` Part of #13299 We've been inferring the type of the yielded values in for-loop as `<T as IntoIterator>::Item`. We infer the correct type most of the time when we normalize the projection type, but it turns out not always. We should infer the type as `<<T as IntoIterator>::IntoIter as Iterator>::Item`. When one specifies `IntoIter` assoc type of `IntoIterator` but not `Item` in generic bounds, we fail to normalize `<T as IntoIterator>::Item` (even though `IntoIter` is defined like so: `type IntoIter: Iterator<Item = Self::Item>` - rustc does *not* normalize projections based on other projection's bound I believe; see [this playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e88e19385094cb98fadbf647b4c2082e)). Note that this doesn't fully fix # 13299 - given the following code, chalk can normalize `<I as IntoIterator>::IntoIter` to `S`, but cannot normalize `<S as Iterator>::Item` to `i32`. ```rust struct S; impl Iterator for S { type Item = i32; /* ... */ } fn f<I: IntoIterator<IntoIter = S>>(it: I) { for elem in it {} //^^^^{unknown} } ``` This is because chalk finds multiple answers that satisfy the query `AliasEq(<S as Iterator>::Item = ?X`: `?X = i32` and `?X = <I as IntoIterator>::Item` - which are supposed to be the same type due to the aforementioned bound on `IntoIter` but chalk is unable to figure it out.
This commit is contained in:
commit
97f8f4a3da
5 changed files with 29 additions and 3 deletions
|
@ -263,6 +263,7 @@ pub mod known {
|
||||||
Iterator,
|
Iterator,
|
||||||
IntoIterator,
|
IntoIterator,
|
||||||
Item,
|
Item,
|
||||||
|
IntoIter,
|
||||||
Try,
|
Try,
|
||||||
Ok,
|
Ok,
|
||||||
Future,
|
Future,
|
||||||
|
|
|
@ -883,6 +883,12 @@ impl<'a> InferenceContext<'a> {
|
||||||
fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
|
fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
|
||||||
let path = path![core::iter::IntoIterator];
|
let path = path![core::iter::IntoIterator];
|
||||||
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||||
|
self.db.trait_data(trait_).associated_type_by_name(&name![IntoIter])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_iterator_item(&self) -> Option<TypeAliasId> {
|
||||||
|
let path = path![core::iter::Iterator];
|
||||||
|
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||||
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
|
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,8 +207,10 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
&Expr::For { iterable, body, pat, label } => {
|
&Expr::For { iterable, body, pat, label } => {
|
||||||
let iterable_ty = self.infer_expr(iterable, &Expectation::none());
|
let iterable_ty = self.infer_expr(iterable, &Expectation::none());
|
||||||
let pat_ty =
|
let into_iter_ty =
|
||||||
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
|
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
|
||||||
|
let pat_ty =
|
||||||
|
self.resolve_associated_type(into_iter_ty, self.resolve_iterator_item());
|
||||||
|
|
||||||
self.infer_pat(pat, &pat_ty, BindingMode::default());
|
self.infer_pat(pat, &pat_ty, BindingMode::default());
|
||||||
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
|
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
|
||||||
|
|
|
@ -279,6 +279,10 @@ fn test() {
|
||||||
pub mod iter {
|
pub mod iter {
|
||||||
pub trait IntoIterator {
|
pub trait IntoIterator {
|
||||||
type Item;
|
type Item;
|
||||||
|
type IntoIter: Iterator<Item = Self::Item>;
|
||||||
|
}
|
||||||
|
pub trait Iterator {
|
||||||
|
type Item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
|
@ -297,7 +301,13 @@ pub mod collections {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IntoIterator for Vec<T> {
|
impl<T> IntoIterator for Vec<T> {
|
||||||
type Item=T;
|
type Item = T;
|
||||||
|
type IntoIter = IntoIter<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IntoIter<T> {}
|
||||||
|
impl<T> Iterator for IntoIter<T> {
|
||||||
|
type Item = T;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
|
|
@ -2024,7 +2024,14 @@ impl<T> Vec<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IntoIterator for Vec<T> {
|
impl<T> IntoIterator for Vec<T> {
|
||||||
type Item=T;
|
type Item = T;
|
||||||
|
type IntoIter = IntoIter<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IntoIter<T> {}
|
||||||
|
|
||||||
|
impl<T> Iterator for IntoIter<T> {
|
||||||
|
type Item = T;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
Loading…
Reference in a new issue