diff options
| author | hkalbasi <hamidrezakalbasi@protonmail.com> | 2023-04-11 04:32:11 +0330 |
|---|---|---|
| committer | hkalbasi <hamidrezakalbasi@protonmail.com> | 2023-04-11 04:32:11 +0330 |
| commit | a584cb998fabe8f02d6743e7f19f6bdd53385a16 (patch) | |
| tree | fade5bff992f932a7a394ce8bdd58c519b51129e | |
| parent | 44cf8ef49ad3db5e82f18a89b20e925353389121 (diff) | |
| download | rust-a584cb998fabe8f02d6743e7f19f6bdd53385a16.tar.gz rust-a584cb998fabe8f02d6743e7f19f6bdd53385a16.zip | |
Infer types of nested RPITs
| -rw-r--r-- | crates/hir-def/src/layout.rs | 1 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 86 | ||||
| -rw-r--r-- | crates/hir-ty/src/layout.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/layout/tests.rs | 39 | ||||
| -rw-r--r-- | crates/test-utils/src/minicore.rs | 11 |
5 files changed, 105 insertions, 34 deletions
diff --git a/crates/hir-def/src/layout.rs b/crates/hir-def/src/layout.rs index 49b1190ad46..873936b5b76 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 b4da1a308d3..d90ca77b55c 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<T>( + &mut self, + t: T, + rpits: Arc<chalk_ir::Binders<crate::ReturnTypeImplTraits>>, + fn_placeholders: Substitution, + ) -> T + where + T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>, + { + 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 277998b6178..23cad5e6fd3 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<Lay TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => { 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 43ace8ff032..a0ffab55180 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -233,6 +233,45 @@ fn return_position_impl_trait() { foo() } size_and_align_expr! { + minicore: iterators; + stmts: [] + trait Tr {} + impl Tr for i32 {} + fn foo() -> impl Iterator<Item = impl Tr> { + [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<T>(inp: impl Future<Output = T>) -> Poll<T> { + // 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<Self>) { + } + } + 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, T)); trait T {} impl T for Foo<i32> {} diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 167af32a2ea..308dc5892e5 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, const N: usize>([T; N]); + struct IndexRange { + start: usize, + end: usize, + } + pub struct IntoIter<T, const N: usize> { + data: [T; N], + range: IndexRange, + } impl<T, const N: usize> IntoIterator for [T; N] { type Item = T; type IntoIter = IntoIter<T, N>; fn into_iter(self) -> I { - IntoIter(self) + IntoIter { data: self, range: IndexRange { start: 0, end: self.len() } } } } impl<T, const N: usize> Iterator for IntoIter<T, N> { |
