diff --git a/crates/hir-def/src/layout.rs b/crates/hir-def/src/layout.rs index 49b1190ad4..873936b5b7 100644 --- a/crates/hir-def/src/layout.rs +++ b/crates/hir-def/src/layout.rs @@ -92,6 +92,7 @@ pub enum LayoutError { SizeOverflow, TargetLayoutNotAvailable, HasPlaceholder, + HasErrorType, NotImplemented, Unknown, } diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index b4da1a308d..d90ca77b55 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -33,7 +33,7 @@ use hir_def::{ TraitId, TypeAliasId, VariantId, }; use hir_expand::name::{name, Name}; -use la_arena::ArenaMap; +use la_arena::{ArenaMap, Entry}; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::{always, never}; @@ -676,36 +676,16 @@ impl<'a> InferenceContext<'a> { let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) { // RPIT opaque types use substitution of their parent function. let fn_placeholders = TyBuilder::placeholder_subst(self.db, func); - fold_tys( - return_ty, - |ty, _| { - let opaque_ty_id = match ty.kind(Interner) { - TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id, - _ => return ty, - }; - let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { - ImplTraitId::ReturnTypeImplTrait(_, idx) => idx, - _ => unreachable!(), - }; - let bounds = (*rpits).map_ref(|rpits| { - rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter()) - }); - let var = self.table.new_type_var(); - let var_subst = Substitution::from1(Interner, var.clone()); - for bound in bounds { - let predicate = - bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders); - let (var_predicate, binders) = predicate - .substitute(Interner, &var_subst) - .into_value_and_skipped_binders(); - always!(binders.is_empty(Interner)); // quantified where clauses not yet handled - self.push_obligation(var_predicate.cast(Interner)); - } - self.result.type_of_rpit.insert(idx, var.clone()); - var - }, - DebruijnIndex::INNERMOST, - ) + let result = + self.insert_inference_vars_for_rpit(return_ty, rpits.clone(), fn_placeholders); + let rpits = rpits.skip_binders(); + for (id, _) in rpits.impl_traits.iter() { + if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) { + never!("Missed RPIT in `insert_inference_vars_for_rpit`"); + e.insert(TyKind::Error.intern(Interner)); + } + } + result } else { return_ty }; @@ -714,6 +694,50 @@ impl<'a> InferenceContext<'a> { self.return_coercion = Some(CoerceMany::new(self.return_ty.clone())); } + fn insert_inference_vars_for_rpit( + &mut self, + t: T, + rpits: Arc>, + fn_placeholders: Substitution, + ) -> T + where + T: crate::HasInterner + crate::TypeFoldable, + { + fold_tys( + t, + |ty, _| { + let opaque_ty_id = match ty.kind(Interner) { + TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id, + _ => return ty, + }; + let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { + ImplTraitId::ReturnTypeImplTrait(_, idx) => idx, + _ => unreachable!(), + }; + let bounds = (*rpits) + .map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter())); + let var = self.table.new_type_var(); + let var_subst = Substitution::from1(Interner, var.clone()); + for bound in bounds { + let predicate = + bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders); + let (var_predicate, binders) = + predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders(); + always!(binders.is_empty(Interner)); // quantified where clauses not yet handled + let var_predicate = self.insert_inference_vars_for_rpit( + var_predicate, + rpits.clone(), + fn_placeholders.clone(), + ); + self.push_obligation(var_predicate.cast(Interner)); + } + self.result.type_of_rpit.insert(idx, var.clone()); + var + }, + DebruijnIndex::INNERMOST, + ) + } + fn infer_body(&mut self) { match self.return_coercion { Some(_) => self.infer_return(self.body.body_expr), diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 277998b617..23cad5e6fd 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -245,8 +245,8 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result { return Err(LayoutError::NotImplemented) } + TyKind::Error => return Err(LayoutError::HasErrorType), TyKind::AssociatedType(_, _) - | TyKind::Error | TyKind::Alias(_) | TyKind::Placeholder(_) | TyKind::BoundVar(_) diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index 43ace8ff03..a0ffab5518 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -232,6 +232,45 @@ fn return_position_impl_trait() { fn foo() -> (impl T, impl T, impl T) { (2i64, 5i32, 7i32) } foo() } + size_and_align_expr! { + minicore: iterators; + stmts: [] + trait Tr {} + impl Tr for i32 {} + fn foo() -> impl Iterator { + [1, 2, 3].into_iter() + } + let mut iter = foo(); + let item = iter.next(); + (iter, item) + } + size_and_align_expr! { + minicore: future; + stmts: [] + use core::{future::Future, task::{Poll, Context}, pin::pin}; + use std::{task::Wake, sync::Arc}; + trait Tr {} + impl Tr for i32 {} + async fn f() -> impl Tr { + 2 + } + fn unwrap_fut(inp: impl Future) -> Poll { + // In a normal test we could use `loop {}` or `panic!()` here, + // but rustc actually runs this code. + let pinned = pin!(inp); + struct EmptyWaker; + impl Wake for EmptyWaker { + fn wake(self: Arc) { + } + } + let waker = Arc::new(EmptyWaker).into(); + let mut context = Context::from_waker(&waker); + let x = pinned.poll(&mut context); + x + } + let x = unwrap_fut(f()); + x + } size_and_align_expr! { struct Foo(T, T, (T, T)); trait T {} diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 167af32a2e..308dc5892e 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -891,12 +891,19 @@ pub mod iter { self } } - pub struct IntoIter([T; N]); + struct IndexRange { + start: usize, + end: usize, + } + pub struct IntoIter { + data: [T; N], + range: IndexRange, + } impl IntoIterator for [T; N] { type Item = T; type IntoIter = IntoIter; fn into_iter(self) -> I { - IntoIter(self) + IntoIter { data: self, range: IndexRange { start: 0, end: self.len() } } } } impl Iterator for IntoIter {