]> git.lizzy.rs Git - rust.git/commitdiff
Associated type bound for inlined impl Trait doc
authorShotaro Yamada <sinkuu@sinkuu.xyz>
Mon, 8 Jul 2019 08:59:26 +0000 (17:59 +0900)
committerShotaro Yamada <sinkuu@sinkuu.xyz>
Mon, 19 Aug 2019 08:49:54 +0000 (17:49 +0900)
src/librustdoc/clean/mod.rs
src/librustdoc/clean/simplify.rs
src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs
src/test/rustdoc/inline_cross/impl_trait.rs

index d3065f16793162ab362d4a8fd6d9b2cc54746d5c..bde1826c7fd5a71f7f7ff3719d0d5b5d09de79be 100644 (file)
@@ -1698,7 +1698,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Generics {
 
         // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
         // since `Clean for ty::Predicate` would consume them.
-        let mut impl_trait = FxHashMap::<ImplTraitParam, Vec<_>>::default();
+        let mut impl_trait = FxHashMap::<ImplTraitParam, Vec<GenericBound>>::default();
 
         // Bounds in the type_params and lifetimes fields are repeated in the
         // predicates field (see rustc_typeck::collect::ty_generics), so remove
@@ -1720,41 +1720,73 @@ 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();
+
         let mut where_predicates = preds.predicates.iter()
             .flat_map(|(p, _)| {
-                let param_idx = if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
-                    if let ty::Param(param) = trait_ref.self_ty().sty {
-                        Some(param.index)
-                    } else {
-                        None
-                    }
-                } else if let Some(outlives) = p.to_opt_type_outlives() {
-                    if let ty::Param(param) = outlives.skip_binder().0.sty {
-                        Some(param.index)
-                    } else {
-                        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 {
+                            return Some(param.index);
+                        }
+                    } else if let Some(outlives) = p.to_opt_type_outlives() {
+                        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 {
+                            return Some(param.index);
+                        }
                     }
-                } else {
+
                     None
-                };
+                })();
 
                 let p = p.clean(cx)?;
 
-                if let Some(b) = param_idx.and_then(|i| impl_trait.get_mut(&i.into())) {
-                    b.extend(
-                        p.get_bounds()
-                            .into_iter()
-                            .flatten()
-                            .cloned()
-                            .filter(|b| !b.is_sized_bound(cx))
-                    );
-                    return None;
+                if let Some(param_idx) = param_idx {
+                    if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
+                        b.extend(
+                            p.get_bounds()
+                                .into_iter()
+                                .flatten()
+                                .cloned()
+                                .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 {
+                            impl_trait_proj
+                                .entry((param_idx, trait_did))
+                                .or_default()
+                                .push((name.to_string(), rhs.clone()));
+                        }
+
+                        return None;
+                    }
                 }
 
                 Some(p)
             })
             .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 {
@@ -2664,6 +2696,21 @@ pub fn is_full_generic(&self) -> bool {
             _ => false,
         }
     }
+
+    pub fn projection(&self) -> Option<(&Type, DefId, &str)> {
+        let (self_, trait_, name) = match self {
+            QPath { ref self_type, ref trait_, ref name } => {
+                (self_type, trait_, name)
+            }
+            _ => return None,
+        };
+        let trait_did = match **trait_ {
+            ResolvedPath { did, .. } => did,
+            _ => return None,
+        };
+        Some((&self_, trait_did, name))
+    }
+
 }
 
 impl GetDefId for Type {
index 3801c42307fc6f00099bfb01217c258dfa809dda..8758ab19691163ab4f93e847ed21d0c31d08b459 100644 (file)
@@ -53,58 +53,21 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
     // Look for equality predicates on associated types that can be merged into
     // general bound predicates
     equalities.retain(|&(ref lhs, ref rhs)| {
-        let (self_, trait_, name) = match *lhs {
-            clean::QPath { ref self_type, ref trait_, ref name } => {
-                (self_type, trait_, name)
-            }
-            _ => return true,
-        };
-        let generic = match **self_ {
-            clean::Generic(ref s) => s,
-            _ => return true,
+        let (self_, trait_did, name) = if let Some(p) = lhs.projection() {
+            p
+        } else {
+            return true;
         };
-        let trait_did = match **trait_ {
-            clean::ResolvedPath { did, .. } => did,
+        let generic = match self_ {
+            clean::Generic(s) => s,
             _ => return true,
         };
         let bounds = match params.get_mut(generic) {
             Some(bound) => bound,
             None => return true,
         };
-        !bounds.iter_mut().any(|b| {
-            let trait_ref = match *b {
-                clean::GenericBound::TraitBound(ref mut tr, _) => tr,
-                clean::GenericBound::Outlives(..) => return false,
-            };
-            let (did, path) = match trait_ref.trait_ {
-                clean::ResolvedPath { did, ref mut path, ..} => (did, path),
-                _ => return false,
-            };
-            // If this QPath's trait `trait_did` is the same as, or a supertrait
-            // of, the bound's trait `did` then we can keep going, otherwise
-            // this is just a plain old equality bound.
-            if !trait_is_same_or_supertrait(cx, did, trait_did) {
-                return false
-            }
-            let last = path.segments.last_mut().expect("segments were empty");
-            match last.args {
-                PP::AngleBracketed { ref mut bindings, .. } => {
-                    bindings.push(clean::TypeBinding {
-                        name: name.clone(),
-                        kind: clean::TypeBindingKind::Equality {
-                            ty: rhs.clone(),
-                        },
-                    });
-                }
-                PP::Parenthesized { ref mut output, .. } => {
-                    assert!(output.is_none());
-                    if *rhs != clean::Type::Tuple(Vec::new()) {
-                        *output = Some(rhs.clone());
-                    }
-                }
-            };
-            true
-        })
+
+        merge_bounds(cx, bounds, trait_did, name, rhs)
     });
 
     // And finally, let's reassemble everything
@@ -127,6 +90,49 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
     clauses
 }
 
+pub fn merge_bounds(
+    cx: &clean::DocContext<'_>,
+    bounds: &mut Vec<clean::GenericBound>,
+    trait_did: DefId,
+    name: &str,
+    rhs: &clean::Type,
+) -> bool {
+    !bounds.iter_mut().any(|b| {
+        let trait_ref = match *b {
+            clean::GenericBound::TraitBound(ref mut tr, _) => tr,
+            clean::GenericBound::Outlives(..) => return false,
+        };
+        let (did, path) = match trait_ref.trait_ {
+            clean::ResolvedPath { did, ref mut path, ..} => (did, path),
+            _ => return false,
+        };
+        // If this QPath's trait `trait_did` is the same as, or a supertrait
+        // of, the bound's trait `did` then we can keep going, otherwise
+        // this is just a plain old equality bound.
+        if !trait_is_same_or_supertrait(cx, did, trait_did) {
+            return false
+        }
+        let last = path.segments.last_mut().expect("segments were empty");
+        match last.args {
+            PP::AngleBracketed { ref mut bindings, .. } => {
+                bindings.push(clean::TypeBinding {
+                    name: name.to_string(),
+                    kind: clean::TypeBindingKind::Equality {
+                        ty: rhs.clone(),
+                    },
+                });
+            }
+            PP::Parenthesized { ref mut output, .. } => {
+                assert!(output.is_none());
+                if *rhs != clean::Type::Tuple(Vec::new()) {
+                    *output = Some(rhs.clone());
+                }
+            }
+        };
+        true
+    })
+}
+
 pub fn ty_params(mut params: Vec<clean::GenericParamDef>) -> Vec<clean::GenericParamDef> {
     for param in &mut params {
         match param.kind {
index 7807acbc4d61d0ad572a8ad286f3589f43b2834d..7b6e665b85f1903408b0714c77206959747e8a3a 100644 (file)
@@ -1,5 +1,9 @@
+use std::ops::Deref;
+
 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 struct Foo;
 
 impl Foo {
index 091baa9773ecffe5cae5c682d4a3de2a144cbc92..20d193aad16dc0866a32e1fe3769c7f1c2d484c6 100644 (file)
@@ -7,6 +7,12 @@
 // @!has - '//pre[@class="rust fn"]' 'where'
 pub use impl_trait_aux::func;
 
+// @has impl_trait/fn.func2.html
+// @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/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'