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.
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.
11 //! Simplification of where clauses and parameter bounds into a prettier and
12 //! more canonical form.
14 //! Currently all cross-crate-inlined function use `rustc::ty` to reconstruct
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
18 //! is that the AST predicate of: `where T: Trait<Foo=Bar>` is encoded as:
19 //! `where T: Trait, <T as Trait>::Foo = Bar`.
21 //! This module attempts to reconstruct the original where and/or parameter
22 //! bounds by special casing scenarios such as these. Fun!
25 use std
::collections
::BTreeMap
;
27 use rustc
::hir
::def_id
::DefId
;
30 use clean
::GenericArgs
as PP
;
31 use clean
::WherePredicate
as WP
;
35 pub fn where_clauses(cx
: &DocContext
, clauses
: Vec
<WP
>) -> Vec
<WP
> {
36 // First, partition the where clause into its separate components
37 let mut params
= BTreeMap
::new();
38 let mut lifetimes
= Vec
::new();
39 let mut equalities
= Vec
::new();
40 let mut tybounds
= Vec
::new();
42 for clause
in clauses
{
44 WP
::BoundPredicate { ty, bounds }
=> {
46 clean
::Generic(s
) => params
.entry(s
).or_insert(Vec
::new())
48 t
=> tybounds
.push((t
, ty_bounds(bounds
))),
51 WP
::RegionPredicate { lifetime, bounds }
=> {
52 lifetimes
.push((lifetime
, bounds
));
54 WP
::EqPredicate { lhs, rhs }
=> equalities
.push((lhs
, rhs
)),
58 // Simplify the type parameter bounds on all the generics
59 let mut params
= params
.into_iter().map(|(k
, v
)| {
61 }).collect
::<BTreeMap
<_
, _
>>();
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
)
72 let generic
= match **self_
{
73 clean
::Generic(ref s
) => s
,
76 let trait_did
= match **trait_
{
77 clean
::ResolvedPath { did, .. }
=> did
,
80 let bounds
= match params
.get_mut(generic
) {
84 !bounds
.iter_mut().any(|b
| {
85 let trait_ref
= match *b
{
86 clean
::GenericBound
::TraitBound(ref mut tr
, _
) => tr
,
87 clean
::GenericBound
::Outlives(..) => return false,
89 let (did
, path
) = match trait_ref
.trait_
{
90 clean
::ResolvedPath { did, ref mut path, ..}
=> (did
, path
),
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
) {
99 let last
= path
.segments
.last_mut().unwrap();
101 PP
::AngleBracketed { ref mut bindings, .. }
=> {
102 bindings
.push(clean
::TypeBinding
{
107 PP
::Parenthesized { ref mut output, .. }
=> {
108 assert
!(output
.is_none());
109 if *rhs
!= clean
::Type
::Tuple(Vec
::new()) {
110 *output
= Some(rhs
.clone());
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 }
123 clauses
.extend(params
.into_iter().map(|(k
, v
)| {
125 ty
: clean
::Generic(k
),
129 clauses
.extend(tybounds
.into_iter().map(|(ty
, bounds
)| {
130 WP
::BoundPredicate { ty: ty, bounds: bounds }
132 clauses
.extend(equalities
.into_iter().map(|(lhs
, rhs
)| {
133 WP
::EqPredicate { lhs: lhs, rhs: rhs }
138 pub fn ty_params(mut params
: Vec
<clean
::GenericParamDef
>) -> Vec
<clean
::GenericParamDef
> {
139 for param
in &mut params
{
141 clean
::GenericParamDefKind
::Type { ref mut bounds, .. }
=> {
142 *bounds
= ty_bounds(mem
::replace(bounds
, Vec
::new()));
144 _
=> panic
!("expected only type parameters"),
150 fn ty_bounds(bounds
: Vec
<clean
::GenericBound
>) -> Vec
<clean
::GenericBound
> {
154 fn trait_is_same_or_supertrait(cx
: &DocContext
, child
: DefId
,
155 trait_
: DefId
) -> bool
{
159 let predicates
= cx
.tcx
.super_predicates_of(child
).predicates
;
160 predicates
.iter().filter_map(|pred
| {
161 if let ty
::Predicate
::Trait(ref pred
) = *pred
{
162 if pred
.skip_binder().trait_ref
.self_ty().is_self() {
170 }).any(|did
| trait_is_same_or_supertrait(cx
, did
, trait_
))