diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 54a21f2ed5c2a..bff4190ae7925 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -591,12 +591,12 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer cbox } - hir::ItemKind::Fn(ref decl, header, ref typarams, body) => { + hir::ItemKind::Fn(ref decl, header, ref param_names, body) => { self.head("")?; self.print_fn(decl, header, Some(item.ident.name), - typarams, + param_names, &item.vis, &[], Some(body))?; diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 20fa6009b310b..adbe73b165ef4 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -435,7 +435,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let new_ty = match &poly_trait.trait_ { &Type::ResolvedPath { ref path, - ref typarams, + ref param_names, ref did, ref is_generic, } => { @@ -444,7 +444,13 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .expect("segments were empty"); let (old_input, old_output) = match last_segment.args { - GenericArgs::AngleBracketed { types, .. } => (types, None), + GenericArgs::AngleBracketed { args, .. } => { + let types = args.iter().filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty.clone()), + _ => None, + }).collect(); + (types, None) + } GenericArgs::Parenthesized { inputs, output, .. } => { (inputs, output) } @@ -469,7 +475,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { Type::ResolvedPath { path: new_path, - typarams: typarams.clone(), + param_names: param_names.clone(), did: did.clone(), is_generic: *is_generic, } @@ -669,7 +675,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { match **trait_ { Type::ResolvedPath { path: ref trait_path, - ref typarams, + ref param_names, ref did, ref is_generic, } => { @@ -724,7 +730,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { PolyTrait { trait_: Type::ResolvedPath { path: new_trait_path, - typarams: typarams.clone(), + param_names: param_names.clone(), did: did.clone(), is_generic: *is_generic, }, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4819256a54550..ba4481733d592 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -17,11 +17,11 @@ use rustc::middle::resolve_lifetime as rl; use rustc::middle::lang_items; use rustc::middle::stability; use rustc::mir::interpret::{GlobalId, ConstValue}; -use rustc::hir::{self, GenericArg, HirVec}; +use rustc::hir::{self, HirVec}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::map::DisambiguatedDefPathData; -use rustc::ty::subst::{Kind, InternalSubsts, SubstsRef}; +use rustc::ty::subst::{Kind, InternalSubsts, SubstsRef, UnpackedKind}; use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind}; use rustc::ty::fold::TypeFolder; use rustc::ty::layout::VariantIdx; @@ -1057,7 +1057,7 @@ impl GenericBound { GenericBound::TraitBound(PolyTrait { trait_: ResolvedPath { path, - typarams: None, + param_names: None, did, is_generic: false, }, @@ -1101,24 +1101,37 @@ impl Clean for hir::GenericBound { } } -fn external_generic_args(cx: &DocContext<'_>, trait_did: Option, has_self: bool, - bindings: Vec, substs: SubstsRef<'_>) -> GenericArgs { - let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect(); - let types = substs.types().skip(has_self as usize).collect::>(); +fn external_generic_args( + cx: &DocContext<'_>, + trait_did: Option, + has_self: bool, + bindings: Vec, + substs: SubstsRef<'_>, +) -> GenericArgs { + let mut skip_self = has_self; + let mut ty_sty = None; + let args: Vec<_> = substs.iter().filter_map(|kind| match kind.unpack() { + UnpackedKind::Lifetime(lt) => { + lt.clean(cx).and_then(|lt| Some(GenericArg::Lifetime(lt))) + } + UnpackedKind::Type(_) if skip_self => { + skip_self = false; + None + } + UnpackedKind::Type(ty) => { + ty_sty = Some(&ty.sty); + Some(GenericArg::Type(ty.clean(cx))) + } + UnpackedKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), + }).collect(); match trait_did { // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => { - assert_eq!(types.len(), 1); - let inputs = match types[0].sty { - ty::Tuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(), - _ => { - return GenericArgs::AngleBracketed { - lifetimes, - types: types.clean(cx), - bindings, - } - } + assert!(ty_sty.is_some()); + let inputs = match ty_sty { + Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.clean(cx)).collect(), + _ => return GenericArgs::AngleBracketed { args, bindings }, }; let output = None; // FIXME(#20299) return type comes from a projection now @@ -1126,17 +1139,10 @@ fn external_generic_args(cx: &DocContext<'_>, trait_did: Option, has_self // ty::Tuple(ref v) if v.is_empty() => None, // -> () // _ => Some(types[1].clean(cx)) // }; - GenericArgs::Parenthesized { - inputs, - output, - } + GenericArgs::Parenthesized { inputs, output } }, _ => { - GenericArgs::AngleBracketed { - lifetimes, - types: types.clean(cx), - bindings, - } + GenericArgs::AngleBracketed { args, bindings } } } } @@ -1188,7 +1194,7 @@ impl<'a, 'tcx> Clean for (&'a ty::TraitRef<'tcx>, Vec PolyTrait { trait_: ResolvedPath { path, - typarams: None, + param_names: None, did: trait_ref.def_id, is_generic: false, }, @@ -1474,14 +1480,14 @@ impl GenericParamDef { } } -impl<'tcx> Clean for ty::GenericParamDef { +impl Clean for ty::GenericParamDef { fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { ty::GenericParamDefKind::Lifetime => { (self.name.to_string(), GenericParamDefKind::Lifetime) } ty::GenericParamDefKind::Type { has_default, .. } => { - cx.renderinfo.borrow_mut().external_typarams + cx.renderinfo.borrow_mut().external_param_names .insert(self.def_id, self.name.clean(cx)); let default = if has_default { Some(cx.tcx.type_of(self.def_id).clean(cx)) @@ -1496,7 +1502,10 @@ impl<'tcx> Clean for ty::GenericParamDef { }) } ty::GenericParamDefKind::Const { .. } => { - unimplemented!() // FIXME(const_generics) + (self.name.clean(cx), GenericParamDefKind::Const { + did: self.def_id, + ty: cx.tcx.type_of(self.def_id).clean(cx), + }) } }; @@ -1697,9 +1706,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, .flat_map(|param| match param.kind { ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)), ty::GenericParamDefKind::Type { .. } => None, - ty::GenericParamDefKind::Const { .. } => { - unimplemented!() // FIXME(const_generics) - } + ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)), }).chain(simplify::ty_params(stripped_typarams).into_iter()) .collect(), where_predicates: simplify::where_clauses(cx, where_predicates), @@ -2260,7 +2267,7 @@ pub enum Type { /// Structs/enums/traits (most that'd be an `hir::TyKind::Path`). ResolvedPath { path: Path, - typarams: Option>, + param_names: Option>, did: DefId, /// `true` if is a `T::Name` path for associated types. is_generic: bool, @@ -2381,12 +2388,15 @@ impl Type { } } - pub fn generics(&self) -> Option<&[Type]> { + pub fn generics(&self) -> Option> { match *self { ResolvedPath { ref path, .. } => { path.segments.last().and_then(|seg| { - if let GenericArgs::AngleBracketed { ref types, .. } = seg.args { - Some(&**types) + if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { + Some(args.iter().filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty.clone()), + _ => None, + }).collect()) } else { None } @@ -2722,7 +2732,7 @@ impl Clean for hir::Ty { } TyKind::TraitObject(ref bounds, ref lifetime) => { match bounds[0].clean(cx).trait_ { - ResolvedPath { path, typarams: None, did, is_generic } => { + ResolvedPath { path, param_names: None, did, is_generic } => { let mut bounds: Vec = bounds[1..].iter().map(|bound| { self::GenericBound::TraitBound(bound.clean(cx), hir::TraitBoundModifier::None) @@ -2730,7 +2740,7 @@ impl Clean for hir::Ty { if !lifetime.is_elided() { bounds.push(self::GenericBound::Outlives(lifetime.clean(cx))); } - ResolvedPath { path, typarams: Some(bounds), did, is_generic, } + ResolvedPath { path, param_names: Some(bounds), did, is_generic, } } _ => Infer // shouldn't happen } @@ -2797,7 +2807,7 @@ impl<'tcx> Clean for Ty<'tcx> { None, false, vec![], substs); ResolvedPath { path, - typarams: None, + param_names: None, did, is_generic: false, } @@ -2808,7 +2818,7 @@ impl<'tcx> Clean for Ty<'tcx> { None, false, vec![], InternalSubsts::empty()); ResolvedPath { path: path, - typarams: None, + param_names: None, did: did, is_generic: false, } @@ -2829,8 +2839,8 @@ impl<'tcx> Clean for Ty<'tcx> { inline::record_extern_fqn(cx, did, TypeKind::Trait); - let mut typarams = vec![]; - reg.clean(cx).map(|b| typarams.push(GenericBound::Outlives(b))); + let mut param_names = vec![]; + reg.clean(cx).map(|b| param_names.push(GenericBound::Outlives(b))); for did in dids { let empty = cx.tcx.intern_substs(&[]); let path = external_path(cx, &cx.tcx.item_name(did).as_str(), @@ -2839,13 +2849,13 @@ impl<'tcx> Clean for Ty<'tcx> { let bound = GenericBound::TraitBound(PolyTrait { trait_: ResolvedPath { path, - typarams: None, + param_names: None, did, is_generic: false, }, generic_params: Vec::new(), }, hir::TraitBoundModifier::None); - typarams.push(bound); + param_names.push(bound); } let mut bindings = vec![]; @@ -2860,7 +2870,7 @@ impl<'tcx> Clean for Ty<'tcx> { false, bindings, substs); ResolvedPath { path, - typarams: Some(typarams), + param_names: Some(param_names), did, is_generic: false, } @@ -2937,6 +2947,15 @@ impl<'tcx> Clean for Ty<'tcx> { } } +impl<'tcx> Clean for ty::Const<'tcx> { + fn clean(&self, cx: &DocContext<'_>) -> Constant { + Constant { + type_: self.ty.clean(cx), + expr: format!("{:?}", self.val), // FIXME(const_generics) + } + } +} + impl Clean for hir::StructField { fn clean(&self, cx: &DocContext<'_>) -> Item { let local_did = cx.tcx.hir().local_def_id_from_hir_id(self.hir_id); @@ -3244,11 +3263,27 @@ impl Clean for hir::Path { } } +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +pub enum GenericArg { + Lifetime(Lifetime), + Type(Type), + Const(Constant), +} + +impl fmt::Display for GenericArg { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + GenericArg::Lifetime(lt) => lt.fmt(f), + GenericArg::Type(ty) => ty.fmt(f), + GenericArg::Const(ct) => ct.fmt(f), + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub enum GenericArgs { AngleBracketed { - lifetimes: Vec, - types: Vec, + args: Vec, bindings: Vec, }, Parenthesized { @@ -3266,27 +3301,19 @@ impl Clean for hir::GenericArgs { output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None } } } else { - let (mut lifetimes, mut types) = (vec![], vec![]); - let mut elided_lifetimes = true; - for arg in &self.args { - match arg { - GenericArg::Lifetime(lt) => { - if !lt.is_elided() { - elided_lifetimes = false; - } - lifetimes.push(lt.clean(cx)); - } - GenericArg::Type(ty) => { - types.push(ty.clean(cx)); - } - GenericArg::Const(..) => { - unimplemented!() // FIXME(const_generics) - } - } - } + let elide_lifetimes = self.args.iter().all(|arg| match arg { + hir::GenericArg::Lifetime(lt) => lt.is_elided(), + _ => true, + }); GenericArgs::AngleBracketed { - lifetimes: if elided_lifetimes { vec![] } else { lifetimes }, - types, + args: self.args.iter().filter_map(|arg| match arg { + hir::GenericArg::Lifetime(lt) if !elide_lifetimes => { + Some(GenericArg::Lifetime(lt.clean(cx))) + } + hir::GenericArg::Lifetime(_) => None, + hir::GenericArg::Type(ty) => Some(GenericArg::Type(ty.clean(cx))), + hir::GenericArg::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), + }).collect(), bindings: self.bindings.clean(cx), } } @@ -3310,8 +3337,8 @@ impl Clean for hir::PathSegment { fn strip_type(ty: Type) -> Type { match ty { - Type::ResolvedPath { path, typarams, did, is_generic } => { - Type::ResolvedPath { path: strip_path(&path), typarams, did, is_generic } + Type::ResolvedPath { path, param_names, did, is_generic } => { + Type::ResolvedPath { path: strip_path(&path), param_names, did, is_generic } } Type::Tuple(inner_tys) => { Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect()) @@ -3338,9 +3365,8 @@ fn strip_path(path: &Path) -> Path { PathSegment { name: s.name.clone(), args: GenericArgs::AngleBracketed { - lifetimes: Vec::new(), - types: Vec::new(), - bindings: Vec::new(), + args: vec![], + bindings: vec![], } } }).collect(); @@ -3491,7 +3517,7 @@ impl Clean for doctree::Static { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub struct Constant { pub type_: Type, pub expr: String, @@ -3971,7 +3997,7 @@ fn resolve_type(cx: &DocContext<'_>, _ => false, }; let did = register_def(&*cx, path.def); - ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic } + ResolvedPath { path: path, param_names: None, did: did, is_generic: is_generic } } pub fn register_def(cx: &DocContext<'_>, def: Def) -> DefId { @@ -4397,9 +4423,9 @@ impl From for SimpleBound { match bound.clone() { GenericBound::Outlives(l) => SimpleBound::Outlives(l), GenericBound::TraitBound(t, mod_) => match t.trait_ { - Type::ResolvedPath { path, typarams, .. } => { + Type::ResolvedPath { path, param_names, .. } => { SimpleBound::TraitBound(path.segments, - typarams + param_names .map_or_else(|| Vec::new(), |v| v.iter() .map(|p| SimpleBound::from(p.clone())) .collect()), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index dca6458c701c5..1982a16f3b81d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -236,8 +236,16 @@ impl<'tcx> DocContext<'tcx> { ty::GenericParamDefKind::Type { .. } => { args.push(hir::GenericArg::Type(self.ty_param_to_ty(param.clone()))); } - ty::GenericParamDefKind::Const { .. } => { - unimplemented!() // FIXME(const_generics) + ty::GenericParamDefKind::Const => { + args.push(hir::GenericArg::Const(hir::ConstArg { + value: hir::AnonConst { + hir_id: hir::DUMMY_HIR_ID, + body: hir::BodyId { + hir_id: hir::DUMMY_HIR_ID, + } + }, + span: DUMMY_SP, + })) } } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 48baf27bae20a..3d8af7c7716b1 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -260,6 +260,14 @@ impl fmt::Display for clean::Lifetime { } } +impl fmt::Display for clean::Constant { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.expr, f)?; + f.write_str(": ")?; + fmt::Display::fmt(&self.type_, f) + } +} + impl fmt::Display for clean::PolyTrait { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if !self.generic_params.is_empty() { @@ -301,32 +309,23 @@ impl fmt::Display for clean::GenericBound { impl fmt::Display for clean::GenericArgs { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - clean::GenericArgs::AngleBracketed { - ref lifetimes, ref types, ref bindings - } => { - if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() { + clean::GenericArgs::AngleBracketed { ref args, ref bindings } => { + if !args.is_empty() || !bindings.is_empty() { if f.alternate() { f.write_str("<")?; } else { f.write_str("<")?; } let mut comma = false; - for lifetime in lifetimes { - if comma { - f.write_str(", ")?; - } - comma = true; - write!(f, "{}", *lifetime)?; - } - for ty in types { + for arg in args { if comma { f.write_str(", ")?; } comma = true; if f.alternate() { - write!(f, "{:#}", *ty)?; + write!(f, "{:#}", *arg)?; } else { - write!(f, "{}", *ty)?; + write!(f, "{}", *arg)?; } } for binding in bindings { @@ -522,8 +521,8 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, /// Helper to render type parameters fn tybounds(w: &mut fmt::Formatter<'_>, - typarams: &Option>) -> fmt::Result { - match *typarams { + param_names: &Option>) -> fmt::Result { + match *param_names { Some(ref params) => { for param in params { write!(w, " + ")?; @@ -560,13 +559,13 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> clean::Generic(ref name) => { f.write_str(name) } - clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => { - if typarams.is_some() { + clean::ResolvedPath{ did, ref param_names, ref path, is_generic } => { + if param_names.is_some() { f.write_str("dyn ")?; } // Paths like T::Output and Self::Output should be rendered with all segments resolved_path(f, did, path, is_generic, use_absolute)?; - tybounds(f, typarams) + tybounds(f, param_names) } clean::Infer => write!(f, "_"), clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()), @@ -664,7 +663,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } } } - clean::ResolvedPath { typarams: Some(ref v), .. } if !v.is_empty() => { + clean::ResolvedPath { param_names: Some(ref v), .. } if !v.is_empty() => { write!(f, "{}{}{}(", amp, lt, m)?; fmt_type(&ty, f, use_absolute)?; write!(f, ")") @@ -718,7 +717,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> // the ugliness comes from inlining across crates where // everything comes in as a fully resolved QPath (hard to // look at). - box clean::ResolvedPath { did, ref typarams, .. } => { + box clean::ResolvedPath { did, ref param_names, .. } => { match href(did) { Some((ref url, _, ref path)) if !f.alternate() => { write!(f, @@ -732,8 +731,8 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> _ => write!(f, "{}", name)?, } - // FIXME: `typarams` are not rendered, and this seems bad? - drop(typarams); + // FIXME: `param_names` are not rendered, and this seems bad? + drop(param_names); Ok(()) } _ => { @@ -772,7 +771,7 @@ fn fmt_impl(i: &clean::Impl, fmt::Display::fmt(ty, f)?; } else { match *ty { - clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => { + clean::ResolvedPath { param_names: None, ref path, is_generic: false, .. } => { let last = path.segments.last().unwrap(); fmt::Display::fmt(&last.name, f)?; fmt::Display::fmt(&last.args, f)?; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index a262a2f28853c..445ce0637662d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -271,7 +271,7 @@ pub struct Cache { /// Mapping of typaram ids to the name of the type parameter. This is used /// when pretty-printing a type (so pretty-printing doesn't have to /// painfully maintain a context like this) - pub typarams: FxHashMap, + pub param_names: FxHashMap, /// Maps a type ID to all known implementations for that type. This is only /// recognized for intra-crate `ResolvedPath` types, and is used to print @@ -368,7 +368,7 @@ pub struct Cache { pub struct RenderInfo { pub inlined: FxHashSet, pub external_paths: crate::core::ExternalPaths, - pub external_typarams: FxHashMap, + pub external_param_names: FxHashMap, pub exact_paths: FxHashMap>, pub access_levels: AccessLevels, pub deref_trait_did: Option, @@ -601,7 +601,7 @@ pub fn run(mut krate: clean::Crate, let RenderInfo { inlined: _, external_paths, - external_typarams, + external_param_names, exact_paths, access_levels, deref_trait_did, @@ -635,7 +635,7 @@ pub fn run(mut krate: clean::Crate, deref_mut_trait_did, owned_box_did, masked_crates: mem::replace(&mut krate.masked_crates, Default::default()), - typarams: external_typarams, + param_names: external_param_names, aliases: Default::default(), }; @@ -1751,7 +1751,7 @@ impl<'a> Cache { clean::GenericParamDefKind::Lifetime => {} clean::GenericParamDefKind::Type { did, .. } | clean::GenericParamDefKind::Const { did, .. } => { - self.typarams.insert(did, param.name.clone()); + self.param_names.insert(did, param.name.clone()); } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e04e127ccf15a..07df14ddc722c 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1263,13 +1263,13 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer cbox } - ast::ItemKind::Fn(ref decl, header, ref typarams, ref body) => { + ast::ItemKind::Fn(ref decl, header, ref param_names, ref body) => { self.head("")?; self.print_fn( decl, header, Some(item.ident), - typarams, + param_names, &item.vis )?; self.s.word(" ")?;