]>
Commit | Line | Data |
---|---|---|
9346a6ac AL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! Simplification of where clauses and parameter bounds into a prettier and | |
12 | //! more canonical form. | |
13 | //! | |
54a0048b | 14 | //! Currently all cross-crate-inlined function use `rustc::ty` to reconstruct |
9346a6ac AL |
15 | //! the AST (e.g. see all of `clean::inline`), but this is not always a |
16 | //! non-lossy transformation. The current format of storage for where clauses | |
17 | //! for functions and such is simply a list of predicates. One example of this | |
ea8adc8c XL |
18 | //! is that the AST predicate of: `where T: Trait<Foo=Bar>` is encoded as: |
19 | //! `where T: Trait, <T as Trait>::Foo = Bar`. | |
9346a6ac AL |
20 | //! |
21 | //! This module attempts to reconstruct the original where and/or parameter | |
22 | //! bounds by special casing scenarios such as these. Fun! | |
23 | ||
24 | use std::mem; | |
a7813a04 | 25 | use std::collections::BTreeMap; |
9346a6ac | 26 | |
54a0048b | 27 | use rustc::hir::def_id::DefId; |
9e0c209e | 28 | use rustc::ty; |
9346a6ac AL |
29 | |
30 | use clean::PathParameters as PP; | |
31 | use clean::WherePredicate as WP; | |
9e0c209e | 32 | use clean; |
9346a6ac AL |
33 | use core::DocContext; |
34 | ||
35 | pub fn where_clauses(cx: &DocContext, clauses: Vec<WP>) -> Vec<WP> { | |
36 | // First, partition the where clause into its separate components | |
a7813a04 | 37 | let mut params = BTreeMap::new(); |
9346a6ac AL |
38 | let mut lifetimes = Vec::new(); |
39 | let mut equalities = Vec::new(); | |
40 | let mut tybounds = Vec::new(); | |
ff7c6d11 | 41 | |
9346a6ac AL |
42 | for clause in clauses { |
43 | match clause { | |
44 | WP::BoundPredicate { ty, bounds } => { | |
45 | match ty { | |
46 | clean::Generic(s) => params.entry(s).or_insert(Vec::new()) | |
47 | .extend(bounds), | |
48 | t => tybounds.push((t, ty_bounds(bounds))), | |
49 | } | |
50 | } | |
51 | WP::RegionPredicate { lifetime, bounds } => { | |
52 | lifetimes.push((lifetime, bounds)); | |
53 | } | |
54 | WP::EqPredicate { lhs, rhs } => equalities.push((lhs, rhs)), | |
55 | } | |
56 | } | |
57 | ||
58 | // Simplify the type parameter bounds on all the generics | |
59 | let mut params = params.into_iter().map(|(k, v)| { | |
60 | (k, ty_bounds(v)) | |
a7813a04 | 61 | }).collect::<BTreeMap<_, _>>(); |
9346a6ac AL |
62 | |
63 | // Look for equality predicates on associated types that can be merged into | |
64 | // general bound predicates | |
65 | equalities.retain(|&(ref lhs, ref rhs)| { | |
66 | let (self_, trait_, name) = match *lhs { | |
67 | clean::QPath { ref self_type, ref trait_, ref name } => { | |
68 | (self_type, trait_, name) | |
69 | } | |
70 | _ => return true, | |
71 | }; | |
72 | let generic = match **self_ { | |
73 | clean::Generic(ref s) => s, | |
74 | _ => return true, | |
75 | }; | |
76 | let trait_did = match **trait_ { | |
77 | clean::ResolvedPath { did, .. } => did, | |
78 | _ => return true, | |
79 | }; | |
80 | let bounds = match params.get_mut(generic) { | |
81 | Some(bound) => bound, | |
82 | None => return true, | |
83 | }; | |
84 | !bounds.iter_mut().any(|b| { | |
85 | let trait_ref = match *b { | |
86 | clean::TraitBound(ref mut tr, _) => tr, | |
87 | clean::RegionBound(..) => return false, | |
88 | }; | |
89 | let (did, path) = match trait_ref.trait_ { | |
90 | clean::ResolvedPath { did, ref mut path, ..} => (did, path), | |
91 | _ => return false, | |
92 | }; | |
93 | // If this QPath's trait `trait_did` is the same as, or a supertrait | |
94 | // of, the bound's trait `did` then we can keep going, otherwise | |
95 | // this is just a plain old equality bound. | |
96 | if !trait_is_same_or_supertrait(cx, did, trait_did) { | |
97 | return false | |
98 | } | |
99 | let last = path.segments.last_mut().unwrap(); | |
100 | match last.params { | |
101 | PP::AngleBracketed { ref mut bindings, .. } => { | |
102 | bindings.push(clean::TypeBinding { | |
103 | name: name.clone(), | |
104 | ty: rhs.clone(), | |
105 | }); | |
106 | } | |
107 | PP::Parenthesized { ref mut output, .. } => { | |
108 | assert!(output.is_none()); | |
2c00a5a8 XL |
109 | if *rhs != clean::Type::Tuple(Vec::new()) { |
110 | *output = Some(rhs.clone()); | |
111 | } | |
9346a6ac AL |
112 | } |
113 | }; | |
114 | true | |
115 | }) | |
116 | }); | |
117 | ||
118 | // And finally, let's reassemble everything | |
119 | let mut clauses = Vec::new(); | |
120 | clauses.extend(lifetimes.into_iter().map(|(lt, bounds)| { | |
121 | WP::RegionPredicate { lifetime: lt, bounds: bounds } | |
122 | })); | |
123 | clauses.extend(params.into_iter().map(|(k, v)| { | |
124 | WP::BoundPredicate { | |
125 | ty: clean::Generic(k), | |
126 | bounds: v, | |
127 | } | |
128 | })); | |
129 | clauses.extend(tybounds.into_iter().map(|(ty, bounds)| { | |
130 | WP::BoundPredicate { ty: ty, bounds: bounds } | |
131 | })); | |
132 | clauses.extend(equalities.into_iter().map(|(lhs, rhs)| { | |
133 | WP::EqPredicate { lhs: lhs, rhs: rhs } | |
134 | })); | |
135 | clauses | |
136 | } | |
137 | ||
138 | pub fn ty_params(mut params: Vec<clean::TyParam>) -> Vec<clean::TyParam> { | |
62682a34 | 139 | for param in &mut params { |
9346a6ac AL |
140 | param.bounds = ty_bounds(mem::replace(&mut param.bounds, Vec::new())); |
141 | } | |
c30ab7b3 | 142 | params |
9346a6ac AL |
143 | } |
144 | ||
145 | fn ty_bounds(bounds: Vec<clean::TyParamBound>) -> Vec<clean::TyParamBound> { | |
146 | bounds | |
147 | } | |
148 | ||
e9174d1e SL |
149 | fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId, |
150 | trait_: DefId) -> bool { | |
9346a6ac AL |
151 | if child == trait_ { |
152 | return true | |
153 | } | |
7cac9316 | 154 | let predicates = cx.tcx.super_predicates_of(child).predicates; |
9e0c209e SL |
155 | predicates.iter().filter_map(|pred| { |
156 | if let ty::Predicate::Trait(ref pred) = *pred { | |
157 | if pred.0.trait_ref.self_ty().is_self() { | |
158 | Some(pred.def_id()) | |
159 | } else { | |
160 | None | |
9346a6ac | 161 | } |
9e0c209e SL |
162 | } else { |
163 | None | |
9346a6ac | 164 | } |
9e0c209e | 165 | }).any(|did| trait_is_same_or_supertrait(cx, did, trait_)) |
9346a6ac | 166 | } |