|
29 | 29 | use std::mem;
|
30 | 30 | use std::collections::HashMap;
|
31 | 31 |
|
32 |
| -use clean; |
33 |
| -use clean::WherePredicate as WP; |
| 32 | +use rustc::middle::subst; |
| 33 | +use rustc::middle::ty; |
| 34 | +use syntax::ast; |
| 35 | + |
34 | 36 | use clean::PathParameters as PP;
|
| 37 | +use clean::WherePredicate as WP; |
| 38 | +use clean::{self, Clean}; |
| 39 | +use core::DocContext; |
35 | 40 |
|
36 |
| -pub fn where_clauses(clauses: Vec<WP>) -> Vec<WP> { |
| 41 | +pub fn where_clauses(cx: &DocContext, clauses: Vec<WP>) -> Vec<WP> { |
37 | 42 | // First, partition the where clause into its separate components
|
38 | 43 | let mut params = HashMap::new();
|
39 | 44 | let mut lifetimes = Vec::new();
|
@@ -90,16 +95,25 @@ pub fn where_clauses(clauses: Vec<WP>) -> Vec<WP> {
|
90 | 95 | clean::ResolvedPath { did, ref mut path, ..} => (did, path),
|
91 | 96 | _ => return false,
|
92 | 97 | };
|
93 |
| - if did != trait_did { return false } |
| 98 | + // If this QPath's trait `trait_did` is the same as, or a supertrait |
| 99 | + // of, the bound's trait `did` then we can keep going, otherwise |
| 100 | + // this is just a plain old equality bound. |
| 101 | + if !trait_is_same_or_supertrait(cx, did, trait_did) { |
| 102 | + return false |
| 103 | + } |
94 | 104 | let last = path.segments.last_mut().unwrap();
|
95 |
| - let bindings = match last.params { |
96 |
| - PP::AngleBracketed { ref mut bindings, .. } => bindings, |
97 |
| - PP::Parenthesized { .. } => return false, |
| 105 | + match last.params { |
| 106 | + PP::AngleBracketed { ref mut bindings, .. } => { |
| 107 | + bindings.push(clean::TypeBinding { |
| 108 | + name: name.clone(), |
| 109 | + ty: rhs.clone(), |
| 110 | + }); |
| 111 | + } |
| 112 | + PP::Parenthesized { ref mut output, .. } => { |
| 113 | + assert!(output.is_none()); |
| 114 | + *output = Some(rhs.clone()); |
| 115 | + } |
98 | 116 | };
|
99 |
| - bindings.push(clean::TypeBinding { |
100 |
| - name: name.clone(), |
101 |
| - ty: rhs.clone(), |
102 |
| - }); |
103 | 117 | true
|
104 | 118 | })
|
105 | 119 | });
|
@@ -134,3 +148,33 @@ pub fn ty_params(mut params: Vec<clean::TyParam>) -> Vec<clean::TyParam> {
|
134 | 148 | fn ty_bounds(bounds: Vec<clean::TyParamBound>) -> Vec<clean::TyParamBound> {
|
135 | 149 | bounds
|
136 | 150 | }
|
| 151 | + |
| 152 | +fn trait_is_same_or_supertrait(cx: &DocContext, child: ast::DefId, |
| 153 | + trait_: ast::DefId) -> bool { |
| 154 | + if child == trait_ { |
| 155 | + return true |
| 156 | + } |
| 157 | + let def = ty::lookup_trait_def(cx.tcx(), child); |
| 158 | + let predicates = ty::lookup_predicates(cx.tcx(), child); |
| 159 | + let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); |
| 160 | + generics.where_predicates.iter().filter_map(|pred| { |
| 161 | + match *pred { |
| 162 | + clean::WherePredicate::BoundPredicate { |
| 163 | + ty: clean::Generic(ref s), |
| 164 | + ref bounds |
| 165 | + } if *s == "Self" => Some(bounds), |
| 166 | + _ => None, |
| 167 | + } |
| 168 | + }).flat_map(|bounds| bounds.iter()).any(|bound| { |
| 169 | + let poly_trait = match *bound { |
| 170 | + clean::TraitBound(ref t, _) => t, |
| 171 | + _ => return false, |
| 172 | + }; |
| 173 | + match poly_trait.trait_ { |
| 174 | + clean::ResolvedPath { did, .. } => { |
| 175 | + trait_is_same_or_supertrait(cx, did, trait_) |
| 176 | + } |
| 177 | + _ => false, |
| 178 | + } |
| 179 | + }) |
| 180 | +} |
0 commit comments