Skip to content

Commit 65248c5

Browse files
committed
auto merge of #19934 : tomjakubowski/rust/rustdoc-unboxed-closures-redux, r=alexcrichton
We render HRTB and the unboxed closure trait sugar (the so-called "parenthesized" notation) where appropriate. Also address the new `for` syntax on the old closures.
2 parents 7e11b22 + 64b5464 commit 65248c5

File tree

3 files changed

+220
-94
lines changed

3 files changed

+220
-94
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
328328
derived: clean::detect_derived(attrs.as_slice()),
329329
trait_: associated_trait.clean(cx).map(|bound| {
330330
match bound {
331-
clean::TraitBound(ty) => ty,
331+
clean::TraitBound(polyt) => polyt.trait_,
332332
clean::RegionBound(..) => unreachable!(),
333333
}
334334
}),

src/librustdoc/clean/mod.rs

Lines changed: 134 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ use rustc::metadata::cstore;
4343
use rustc::metadata::csearch;
4444
use rustc::metadata::decoder;
4545
use rustc::middle::def;
46-
use rustc::middle::subst;
47-
use rustc::middle::subst::VecPerParamSpace;
46+
use rustc::middle::subst::{mod, ParamSpace, VecPerParamSpace};
4847
use rustc::middle::ty;
4948
use rustc::middle::stability;
5049
use rustc::session::config;
@@ -493,7 +492,7 @@ impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
493492
#[deriving(Clone, RustcEncodable, RustcDecodable, PartialEq)]
494493
pub enum TyParamBound {
495494
RegionBound(Lifetime),
496-
TraitBound(Type)
495+
TraitBound(PolyTrait)
497496
}
498497

499498
impl Clean<TyParamBound> for ast::TyParamBound {
@@ -516,19 +515,55 @@ impl Clean<Vec<TyParamBound>> for ty::ExistentialBounds {
516515
}
517516
}
518517

519-
fn external_path(cx: &DocContext, name: &str, substs: &subst::Substs) -> Path {
518+
fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
519+
substs: &subst::Substs) -> PathParameters {
520+
use rustc::middle::ty::sty;
520521
let lifetimes = substs.regions().get_slice(subst::TypeSpace)
521522
.iter()
522523
.filter_map(|v| v.clean(cx))
523524
.collect();
524525
let types = substs.types.get_slice(subst::TypeSpace).to_vec();
525-
let types = types.clean(cx);
526+
527+
match (trait_did, cx.tcx_opt()) {
528+
// Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
529+
(Some(did), Some(ref tcx)) if tcx.lang_items.fn_trait_kind(did).is_some() => {
530+
assert_eq!(types.len(), 2);
531+
let inputs = match types[0].sty {
532+
sty::ty_tup(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
533+
_ => {
534+
return PathParameters::AngleBracketed {
535+
lifetimes: lifetimes,
536+
types: types.clean(cx)
537+
}
538+
}
539+
};
540+
let output = match types[1].sty {
541+
sty::ty_tup(ref v) if v.is_empty() => None, // -> ()
542+
_ => Some(types[1].clean(cx))
543+
};
544+
PathParameters::Parenthesized {
545+
inputs: inputs,
546+
output: output
547+
}
548+
},
549+
(_, _) => {
550+
PathParameters::AngleBracketed {
551+
lifetimes: lifetimes,
552+
types: types.clean(cx),
553+
}
554+
}
555+
}
556+
}
557+
558+
// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
559+
// from Fn<(A, B,), C> to Fn(A, B) -> C
560+
fn external_path(cx: &DocContext, name: &str, trait_did: Option<ast::DefId>,
561+
substs: &subst::Substs) -> Path {
526562
Path {
527563
global: false,
528564
segments: vec![PathSegment {
529565
name: name.to_string(),
530-
lifetimes: lifetimes,
531-
types: types,
566+
params: external_path_params(cx, trait_did, substs)
532567
}],
533568
}
534569
}
@@ -543,25 +578,28 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
543578
let (did, path) = match *self {
544579
ty::BoundSend =>
545580
(tcx.lang_items.send_trait().unwrap(),
546-
external_path(cx, "Send", &empty)),
581+
external_path(cx, "Send", None, &empty)),
547582
ty::BoundSized =>
548583
(tcx.lang_items.sized_trait().unwrap(),
549-
external_path(cx, "Sized", &empty)),
584+
external_path(cx, "Sized", None, &empty)),
550585
ty::BoundCopy =>
551586
(tcx.lang_items.copy_trait().unwrap(),
552-
external_path(cx, "Copy", &empty)),
587+
external_path(cx, "Copy", None, &empty)),
553588
ty::BoundSync =>
554589
(tcx.lang_items.sync_trait().unwrap(),
555-
external_path(cx, "Sync", &empty)),
590+
external_path(cx, "Sync", None, &empty)),
556591
};
557592
let fqn = csearch::get_item_path(tcx, did);
558593
let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
559594
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did,
560595
(fqn, TypeTrait));
561-
TraitBound(ResolvedPath {
562-
path: path,
563-
typarams: None,
564-
did: did,
596+
TraitBound(PolyTrait {
597+
trait_: ResolvedPath {
598+
path: path,
599+
typarams: None,
600+
did: did,
601+
},
602+
lifetimes: vec![]
565603
})
566604
}
567605
}
@@ -582,13 +620,34 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
582620
let fqn = fqn.into_iter().map(|i| i.to_string())
583621
.collect::<Vec<String>>();
584622
let path = external_path(cx, fqn.last().unwrap().as_slice(),
585-
&self.substs);
623+
Some(self.def_id), &self.substs);
586624
cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id,
587625
(fqn, TypeTrait));
588-
TraitBound(ResolvedPath {
589-
path: path,
590-
typarams: None,
591-
did: self.def_id,
626+
627+
debug!("ty::TraitRef\n substs.types(TypeSpace): {}\n",
628+
self.substs.types.get_slice(ParamSpace::TypeSpace));
629+
630+
// collect any late bound regions
631+
let mut late_bounds = vec![];
632+
for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace).iter() {
633+
use rustc::middle::ty::{Region, sty};
634+
if let sty::ty_tup(ref ts) = ty_s.sty {
635+
for &ty_s in ts.iter() {
636+
if let sty::ty_rptr(ref reg, _) = ty_s.sty {
637+
if let &Region::ReLateBound(_, _) = reg {
638+
debug!(" hit an ReLateBound {}", reg);
639+
if let Some(lt) = reg.clean(cx) {
640+
late_bounds.push(lt)
641+
}
642+
}
643+
}
644+
}
645+
}
646+
}
647+
648+
TraitBound(PolyTrait {
649+
trait_: ResolvedPath { path: path, typarams: None, did: self.def_id, },
650+
lifetimes: late_bounds
592651
})
593652
}
594653
}
@@ -615,7 +674,7 @@ impl<'tcx> Clean<(Vec<TyParamBound>, Option<Type>)> for ty::ParamBounds<'tcx> {
615674
(v, None)
616675
} else {
617676
let ty = match ty::BoundSized.clean(cx) {
618-
TraitBound(ty) => ty,
677+
TraitBound(polyt) => polyt.trait_,
619678
_ => unreachable!()
620679
};
621680
(v, Some(ty))
@@ -627,7 +686,10 @@ impl<'tcx> Clean<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
627686
fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
628687
let mut v = Vec::new();
629688
v.extend(self.regions().iter().filter_map(|r| r.clean(cx)).map(RegionBound));
630-
v.extend(self.types.iter().map(|t| TraitBound(t.clean(cx))));
689+
v.extend(self.types.iter().map(|t| TraitBound(PolyTrait {
690+
trait_: t.clean(cx),
691+
lifetimes: vec![]
692+
})));
631693
if v.len() > 0 {Some(v)} else {None}
632694
}
633695
}
@@ -1006,9 +1068,12 @@ impl Clean<Type> for ast::TraitRef {
10061068
}
10071069
}
10081070

1009-
impl Clean<Type> for ast::PolyTraitRef {
1010-
fn clean(&self, cx: &DocContext) -> Type {
1011-
self.trait_ref.clean(cx)
1071+
impl Clean<PolyTrait> for ast::PolyTraitRef {
1072+
fn clean(&self, cx: &DocContext) -> PolyTrait {
1073+
PolyTrait {
1074+
trait_: self.trait_ref.clean(cx),
1075+
lifetimes: self.bound_lifetimes.clean(cx)
1076+
}
10121077
}
10131078
}
10141079

@@ -1129,6 +1194,13 @@ impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
11291194
}
11301195
}
11311196

1197+
/// A trait reference, which may have higher ranked lifetimes.
1198+
#[deriving(Clone, RustcEncodable, RustcDecodable, PartialEq)]
1199+
pub struct PolyTrait {
1200+
pub trait_: Type,
1201+
pub lifetimes: Vec<Lifetime>
1202+
}
1203+
11321204
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
11331205
/// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
11341206
/// it does not preserve mutability or boxes.
@@ -1399,7 +1471,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
13991471
_ => TypeEnum,
14001472
};
14011473
let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
1402-
substs);
1474+
None, substs);
14031475
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
14041476
ResolvedPath {
14051477
path: path,
@@ -1708,31 +1780,48 @@ impl Clean<Path> for ast::Path {
17081780
}
17091781

17101782
#[deriving(Clone, RustcEncodable, RustcDecodable, PartialEq)]
1711-
pub struct PathSegment {
1712-
pub name: String,
1713-
pub lifetimes: Vec<Lifetime>,
1714-
pub types: Vec<Type>,
1783+
pub enum PathParameters {
1784+
AngleBracketed {
1785+
lifetimes: Vec<Lifetime>,
1786+
types: Vec<Type>,
1787+
},
1788+
Parenthesized {
1789+
inputs: Vec<Type>,
1790+
output: Option<Type>
1791+
}
17151792
}
17161793

1717-
impl Clean<PathSegment> for ast::PathSegment {
1718-
fn clean(&self, cx: &DocContext) -> PathSegment {
1719-
let (lifetimes, types) = match self.parameters {
1794+
impl Clean<PathParameters> for ast::PathParameters {
1795+
fn clean(&self, cx: &DocContext) -> PathParameters {
1796+
match *self {
17201797
ast::AngleBracketedParameters(ref data) => {
1721-
(data.lifetimes.clean(cx), data.types.clean(cx))
1798+
PathParameters::AngleBracketed {
1799+
lifetimes: data.lifetimes.clean(cx),
1800+
types: data.types.clean(cx)
1801+
}
17221802
}
17231803

17241804
ast::ParenthesizedParameters(ref data) => {
1725-
// FIXME -- rustdoc should be taught about Foo() notation
1726-
let inputs = Tuple(data.inputs.clean(cx));
1727-
let output = data.output.as_ref().map(|t| t.clean(cx)).unwrap_or(Tuple(Vec::new()));
1728-
(Vec::new(), vec![inputs, output])
1805+
PathParameters::Parenthesized {
1806+
inputs: data.inputs.clean(cx),
1807+
output: data.output.clean(cx)
1808+
}
17291809
}
1730-
};
1810+
}
1811+
}
1812+
}
1813+
1814+
#[deriving(Clone, RustcEncodable, RustcDecodable, PartialEq)]
1815+
pub struct PathSegment {
1816+
pub name: String,
1817+
pub params: PathParameters
1818+
}
17311819

1820+
impl Clean<PathSegment> for ast::PathSegment {
1821+
fn clean(&self, cx: &DocContext) -> PathSegment {
17321822
PathSegment {
17331823
name: self.identifier.clean(cx),
1734-
lifetimes: lifetimes,
1735-
types: types,
1824+
params: self.parameters.clean(cx)
17361825
}
17371826
}
17381827
}
@@ -2363,8 +2452,10 @@ fn lang_struct(cx: &DocContext, did: Option<ast::DefId>,
23632452
global: false,
23642453
segments: vec![PathSegment {
23652454
name: name.to_string(),
2366-
lifetimes: vec![],
2367-
types: vec![t.clean(cx)],
2455+
params: PathParameters::AngleBracketed {
2456+
lifetimes: vec![],
2457+
types: vec![t.clean(cx)],
2458+
}
23682459
}],
23692460
},
23702461
}

0 commit comments

Comments
 (0)