Skip to content

Commit 7afd204

Browse files
committed
Auto merge of rust-lang#14544 - HKalbasi:dev, r=Veykril
Infer types of nested RPITs fix rust-lang/rust-analyzer#14474 (comment)
2 parents fd27621 + a584cb9 commit 7afd204

File tree

5 files changed

+105
-34
lines changed

5 files changed

+105
-34
lines changed

crates/hir-def/src/layout.rs

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pub enum LayoutError {
9292
SizeOverflow,
9393
TargetLayoutNotAvailable,
9494
HasPlaceholder,
95+
HasErrorType,
9596
NotImplemented,
9697
Unknown,
9798
}

crates/hir-ty/src/infer.rs

+55-31
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use hir_def::{
3333
TraitId, TypeAliasId, VariantId,
3434
};
3535
use hir_expand::name::{name, Name};
36-
use la_arena::ArenaMap;
36+
use la_arena::{ArenaMap, Entry};
3737
use rustc_hash::{FxHashMap, FxHashSet};
3838
use stdx::{always, never};
3939

@@ -676,36 +676,16 @@ impl<'a> InferenceContext<'a> {
676676
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
677677
// RPIT opaque types use substitution of their parent function.
678678
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
679-
fold_tys(
680-
return_ty,
681-
|ty, _| {
682-
let opaque_ty_id = match ty.kind(Interner) {
683-
TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
684-
_ => return ty,
685-
};
686-
let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
687-
ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
688-
_ => unreachable!(),
689-
};
690-
let bounds = (*rpits).map_ref(|rpits| {
691-
rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter())
692-
});
693-
let var = self.table.new_type_var();
694-
let var_subst = Substitution::from1(Interner, var.clone());
695-
for bound in bounds {
696-
let predicate =
697-
bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
698-
let (var_predicate, binders) = predicate
699-
.substitute(Interner, &var_subst)
700-
.into_value_and_skipped_binders();
701-
always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
702-
self.push_obligation(var_predicate.cast(Interner));
703-
}
704-
self.result.type_of_rpit.insert(idx, var.clone());
705-
var
706-
},
707-
DebruijnIndex::INNERMOST,
708-
)
679+
let result =
680+
self.insert_inference_vars_for_rpit(return_ty, rpits.clone(), fn_placeholders);
681+
let rpits = rpits.skip_binders();
682+
for (id, _) in rpits.impl_traits.iter() {
683+
if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) {
684+
never!("Missed RPIT in `insert_inference_vars_for_rpit`");
685+
e.insert(TyKind::Error.intern(Interner));
686+
}
687+
}
688+
result
709689
} else {
710690
return_ty
711691
};
@@ -714,6 +694,50 @@ impl<'a> InferenceContext<'a> {
714694
self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
715695
}
716696

697+
fn insert_inference_vars_for_rpit<T>(
698+
&mut self,
699+
t: T,
700+
rpits: Arc<chalk_ir::Binders<crate::ReturnTypeImplTraits>>,
701+
fn_placeholders: Substitution,
702+
) -> T
703+
where
704+
T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>,
705+
{
706+
fold_tys(
707+
t,
708+
|ty, _| {
709+
let opaque_ty_id = match ty.kind(Interner) {
710+
TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
711+
_ => return ty,
712+
};
713+
let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
714+
ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
715+
_ => unreachable!(),
716+
};
717+
let bounds = (*rpits)
718+
.map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter()));
719+
let var = self.table.new_type_var();
720+
let var_subst = Substitution::from1(Interner, var.clone());
721+
for bound in bounds {
722+
let predicate =
723+
bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
724+
let (var_predicate, binders) =
725+
predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders();
726+
always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
727+
let var_predicate = self.insert_inference_vars_for_rpit(
728+
var_predicate,
729+
rpits.clone(),
730+
fn_placeholders.clone(),
731+
);
732+
self.push_obligation(var_predicate.cast(Interner));
733+
}
734+
self.result.type_of_rpit.insert(idx, var.clone());
735+
var
736+
},
737+
DebruijnIndex::INNERMOST,
738+
)
739+
}
740+
717741
fn infer_body(&mut self) {
718742
match self.return_coercion {
719743
Some(_) => self.infer_return(self.body.body_expr),

crates/hir-ty/src/layout.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
245245
TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => {
246246
return Err(LayoutError::NotImplemented)
247247
}
248+
TyKind::Error => return Err(LayoutError::HasErrorType),
248249
TyKind::AssociatedType(_, _)
249-
| TyKind::Error
250250
| TyKind::Alias(_)
251251
| TyKind::Placeholder(_)
252252
| TyKind::BoundVar(_)

crates/hir-ty/src/layout/tests.rs

+39
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,45 @@ fn return_position_impl_trait() {
232232
fn foo() -> (impl T, impl T, impl T) { (2i64, 5i32, 7i32) }
233233
foo()
234234
}
235+
size_and_align_expr! {
236+
minicore: iterators;
237+
stmts: []
238+
trait Tr {}
239+
impl Tr for i32 {}
240+
fn foo() -> impl Iterator<Item = impl Tr> {
241+
[1, 2, 3].into_iter()
242+
}
243+
let mut iter = foo();
244+
let item = iter.next();
245+
(iter, item)
246+
}
247+
size_and_align_expr! {
248+
minicore: future;
249+
stmts: []
250+
use core::{future::Future, task::{Poll, Context}, pin::pin};
251+
use std::{task::Wake, sync::Arc};
252+
trait Tr {}
253+
impl Tr for i32 {}
254+
async fn f() -> impl Tr {
255+
2
256+
}
257+
fn unwrap_fut<T>(inp: impl Future<Output = T>) -> Poll<T> {
258+
// In a normal test we could use `loop {}` or `panic!()` here,
259+
// but rustc actually runs this code.
260+
let pinned = pin!(inp);
261+
struct EmptyWaker;
262+
impl Wake for EmptyWaker {
263+
fn wake(self: Arc<Self>) {
264+
}
265+
}
266+
let waker = Arc::new(EmptyWaker).into();
267+
let mut context = Context::from_waker(&waker);
268+
let x = pinned.poll(&mut context);
269+
x
270+
}
271+
let x = unwrap_fut(f());
272+
x
273+
}
235274
size_and_align_expr! {
236275
struct Foo<T>(T, T, (T, T));
237276
trait T {}

crates/test-utils/src/minicore.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -891,12 +891,19 @@ pub mod iter {
891891
self
892892
}
893893
}
894-
pub struct IntoIter<T, const N: usize>([T; N]);
894+
struct IndexRange {
895+
start: usize,
896+
end: usize,
897+
}
898+
pub struct IntoIter<T, const N: usize> {
899+
data: [T; N],
900+
range: IndexRange,
901+
}
895902
impl<T, const N: usize> IntoIterator for [T; N] {
896903
type Item = T;
897904
type IntoIter = IntoIter<T, N>;
898905
fn into_iter(self) -> I {
899-
IntoIter(self)
906+
IntoIter { data: self, range: IndexRange { start: 0, end: self.len() } }
900907
}
901908
}
902909
impl<T, const N: usize> Iterator for IntoIter<T, N> {

0 commit comments

Comments
 (0)