about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhkalbasi <hamidrezakalbasi@protonmail.com>2023-04-11 04:32:11 +0330
committerhkalbasi <hamidrezakalbasi@protonmail.com>2023-04-11 04:32:11 +0330
commita584cb998fabe8f02d6743e7f19f6bdd53385a16 (patch)
treefade5bff992f932a7a394ce8bdd58c519b51129e
parent44cf8ef49ad3db5e82f18a89b20e925353389121 (diff)
downloadrust-a584cb998fabe8f02d6743e7f19f6bdd53385a16.tar.gz
rust-a584cb998fabe8f02d6743e7f19f6bdd53385a16.zip
Infer types of nested RPITs
-rw-r--r--crates/hir-def/src/layout.rs1
-rw-r--r--crates/hir-ty/src/infer.rs86
-rw-r--r--crates/hir-ty/src/layout.rs2
-rw-r--r--crates/hir-ty/src/layout/tests.rs39
-rw-r--r--crates/test-utils/src/minicore.rs11
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> {