]> git.lizzy.rs Git - rust.git/commitdiff
Support nested `impl Trait`
authorShotaro Yamada <sinkuu@sinkuu.xyz>
Mon, 8 Jul 2019 11:42:45 +0000 (20:42 +0900)
committerShotaro Yamada <sinkuu@sinkuu.xyz>
Mon, 19 Aug 2019 08:49:54 +0000 (17:49 +0900)
src/librustdoc/clean/mod.rs
src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs
src/test/rustdoc/inline_cross/impl_trait.rs

index bde1826c7fd5a71f7f7ff3719d0d5b5d09de79be..93e650d6d61ae251c6582ca4d3ddacad9786a3d2 100644 (file)
@@ -1720,11 +1720,13 @@ fn clean(&self, cx: &DocContext<'_>) -> Generics {
                 ty::GenericParamDefKind::Const { .. } => None,
             }).collect::<Vec<GenericParamDef>>();
 
-        // (param index, def id of trait) -> (name, type)
-        let mut impl_trait_proj = FxHashMap::<(u32, DefId), Vec<(String, Type)>>::default();
+        // param index -> [(DefId of trait, associated type name, type)]
+        let mut impl_trait_proj =
+            FxHashMap::<u32, Vec<(DefId, String, Ty<'tcx>)>>::default();
 
         let mut where_predicates = preds.predicates.iter()
             .flat_map(|(p, _)| {
+                let mut projection = None;
                 let param_idx = (|| {
                     if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
                         if let ty::Param(param) = trait_ref.self_ty().sty {
@@ -1734,8 +1736,9 @@ fn clean(&self, cx: &DocContext<'_>) -> Generics {
                         if let ty::Param(param) = outlives.skip_binder().0.sty {
                             return Some(param.index);
                         }
-                    } else if let ty::Predicate::Projection(proj) = p {
-                        if let ty::Param(param) = proj.skip_binder().projection_ty.self_ty().sty {
+                    } else if let ty::Predicate::Projection(p) = p {
+                        if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().sty {
+                            projection = Some(p);
                             return Some(param.index);
                         }
                     }
@@ -1755,16 +1758,15 @@ fn clean(&self, cx: &DocContext<'_>) -> Generics {
                                 .filter(|b| !b.is_sized_bound(cx))
                         );
 
-                        let proj = match &p {
-                            WherePredicate::EqPredicate { lhs, rhs } => Some((lhs, rhs))
-                                .and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))),
-                            _ => None,
-                        };
-                        if let Some(((_, trait_did, name), rhs)) = proj {
+                        let proj = projection
+                            .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
+                        if let Some(((_, trait_did, name), rhs)) =
+                            proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
+                        {
                             impl_trait_proj
-                                .entry((param_idx, trait_did))
+                                .entry(param_idx)
                                 .or_default()
-                                .push((name.to_string(), rhs.clone()));
+                                .push((trait_did, name.to_string(), rhs));
                         }
 
                         return None;
@@ -1775,18 +1777,6 @@ fn clean(&self, cx: &DocContext<'_>) -> Generics {
             })
             .collect::<Vec<_>>();
 
-        for ((param_idx, trait_did), bounds) in impl_trait_proj {
-            for (name, rhs) in bounds {
-                simplify::merge_bounds(
-                    cx,
-                    impl_trait.get_mut(&param_idx.into()).unwrap(),
-                    trait_did,
-                    &name,
-                    &rhs,
-                );
-            }
-        }
-
         // Move `TraitPredicate`s to the front.
         for (_, bounds) in impl_trait.iter_mut() {
             bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b {
@@ -1796,7 +1786,25 @@ fn clean(&self, cx: &DocContext<'_>) -> Generics {
             });
         }
 
-        cx.impl_trait_bounds.borrow_mut().extend(impl_trait);
+        for (param, mut bounds) in impl_trait {
+            if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
+                if let Some(proj) = impl_trait_proj.remove(&idx) {
+                    for (trait_did, name, rhs) in proj {
+                        simplify::merge_bounds(
+                            cx,
+                            &mut bounds,
+                            trait_did,
+                            &name,
+                            &rhs.clean(cx),
+                        );
+                    }
+                }
+            } else {
+                unreachable!();
+            }
+
+            cx.impl_trait_bounds.borrow_mut().insert(param, bounds);
+        }
 
         // Type parameters and have a Sized bound by default unless removed with
         // ?Sized. Scan through the predicates and mark any type parameter with
index 7b6e665b85f1903408b0714c77206959747e8a3a..e0f7c6d08ce2fa38d7ed61ef1b5833d683dd2c58 100644 (file)
@@ -4,6 +4,8 @@ pub fn func<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {}
 
 pub fn func2<T>(_x: impl Deref<Target = Option<T>> + Iterator<Item = T>, _y: impl Iterator<Item = u8>) {}
 
+pub fn func3(_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone) {}
+
 pub struct Foo;
 
 impl Foo {
index 20d193aad16dc0866a32e1fe3769c7f1c2d484c6..b08a070dcb74d0fd11fbd9998cf129c7a29e14a4 100644 (file)
@@ -8,11 +8,17 @@
 pub use impl_trait_aux::func;
 
 // @has impl_trait/fn.func2.html
+// @has - '//pre[@class="rust fn"]' "func2<T>("
 // @has - '//pre[@class="rust fn"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
 // @has - '//pre[@class="rust fn"]' "_y: impl Iterator<Item = u8>)"
 // @!has - '//pre[@class="rust fn"]' 'where'
 pub use impl_trait_aux::func2;
 
+// @has impl_trait/fn.func3.html
+// @has - '//pre[@class="rust fn"]' "func3(_x: impl Clone + Iterator<Item = impl Iterator<Item = u8>>)"
+// @!has - '//pre[@class="rust fn"]' 'where'
+pub use impl_trait_aux::func3;
+
 // @has impl_trait/struct.Foo.html
 // @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8>> + 'a)"
 // @!has - '//code[@id="method.v"]' 'where'