Skip to content

Commit 6a7fca5

Browse files
Auto merge of #142502 - nnethercote:rustdoc-json-GenericArgs, r=<try>
rustdoc_json: improve handling of generic args This PR fixes some inconsistencies and inefficiencies in how generic args are handled by rustdoc-json-types. r? `@aDotInTheVoid` try-job: x86_64-mingw-2
2 parents 6f935a0 + a172d78 commit 6a7fca5

File tree

5 files changed

+79
-19
lines changed

5 files changed

+79
-19
lines changed

src/librustdoc/json/conversions.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,13 @@ pub(crate) fn from_deprecation(deprecation: attrs::Deprecation) -> Deprecation {
170170
Deprecation { since, note: note.map(|s| s.to_string()) }
171171
}
172172

173-
impl FromClean<clean::GenericArgs> for GenericArgs {
173+
impl FromClean<clean::GenericArgs> for Option<Box<GenericArgs>> {
174174
fn from_clean(args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self {
175175
use clean::GenericArgs::*;
176-
match args {
176+
if args.is_empty() {
177+
return None;
178+
}
179+
Some(Box::new(match args {
177180
AngleBracketed { args, constraints } => GenericArgs::AngleBracketed {
178181
args: args.into_json(renderer),
179182
constraints: constraints.into_json(renderer),
@@ -183,7 +186,7 @@ impl FromClean<clean::GenericArgs> for GenericArgs {
183186
output: output.as_ref().map(|a| a.as_ref().into_json(renderer)),
184187
},
185188
ReturnTypeNotation => GenericArgs::ReturnTypeNotation,
186-
}
189+
}))
187190
}
188191
}
189192

@@ -580,7 +583,20 @@ impl FromClean<clean::Path> for Path {
580583
Path {
581584
path: path.whole_name(),
582585
id: renderer.id_from_item_default(path.def_id().into()),
583-
args: path.segments.last().map(|args| Box::new(args.args.into_json(renderer))),
586+
args: {
587+
if let Some((final_seg, rest_segs)) = path.segments.split_last() {
588+
// In general, `clean::Path` can hold things like
589+
// `std::vec::Vec::<u32>::new`, where generic args appear
590+
// in a middle segment. But for the places where `Path` is
591+
// used by rustdoc-json-types, generic args can only be
592+
// used in the final segment, e.g. `std::vec::Vec<u32>`. So
593+
// check that the non-final segments have no generic args.
594+
assert!(rest_segs.iter().all(|seg| seg.args.is_empty()));
595+
final_seg.args.into_json(renderer)
596+
} else {
597+
None // no generics on any segments because there are no segments
598+
}
599+
},
584600
}
585601
}
586602
}
@@ -591,7 +607,7 @@ impl FromClean<clean::QPathData> for Type {
591607

592608
Self::QualifiedPath {
593609
name: assoc.name.to_string(),
594-
args: Box::new(assoc.args.into_json(renderer)),
610+
args: assoc.args.into_json(renderer),
595611
self_type: Box::new(self_type.into_json(renderer)),
596612
trait_: trait_.as_ref().map(|trait_| trait_.into_json(renderer)),
597613
}

src/rustdoc-json-types/lib.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
3737
// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
3838
// are deliberately not in a doc comment, because they need not be in public docs.)
3939
//
40-
// Latest feature: Pretty printing of inline attributes changed
41-
pub const FORMAT_VERSION: u32 = 48;
40+
// Latest feature: improve handling of generic args
41+
pub const FORMAT_VERSION: u32 = 49;
4242

4343
/// The root of the emitted JSON blob.
4444
///
@@ -277,8 +277,8 @@ pub struct PolyTrait {
277277
/// A set of generic arguments provided to a path segment, e.g.
278278
///
279279
/// ```text
280-
/// std::option::Option::<u32>::None
281-
/// ^^^^^
280+
/// std::option::Option<u32>
281+
/// ^^^^^
282282
/// ```
283283
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
284284
#[serde(rename_all = "snake_case")]
@@ -331,7 +331,7 @@ pub enum GenericArg {
331331
Const(Constant),
332332
/// A generic argument that's explicitly set to be inferred.
333333
/// ```text
334-
/// std::vec::Vec::<_>::new()
334+
/// std::vec::Vec::<_>
335335
/// ^
336336
/// ```
337337
Infer,
@@ -362,7 +362,7 @@ pub struct AssocItemConstraint {
362362
/// The name of the associated type/constant.
363363
pub name: String,
364364
/// Arguments provided to the associated type/constant.
365-
pub args: GenericArgs,
365+
pub args: Option<Box<GenericArgs>>,
366366
/// The kind of bound applied to the associated type/constant.
367367
pub binding: AssocItemConstraintKind,
368368
}
@@ -1118,7 +1118,7 @@ pub enum Type {
11181118
/// <core::slice::IterMut<'static, u32> as BetterIterator>::Item<'static>
11191119
/// // ^^^^^^^^^
11201120
/// ```
1121-
args: Box<GenericArgs>,
1121+
args: Option<Box<GenericArgs>>,
11221122
/// The type with which this type is associated.
11231123
///
11241124
/// ```ignore (incomplete expression)

src/rustdoc-json-types/tests.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,28 @@ fn test_union_info_roundtrip() {
3838
let decoded: ItemEnum = bincode::deserialize(&encoded).unwrap();
3939
assert_eq!(u, decoded);
4040
}
41+
42+
// The memory used by a `Crate` can get large. These types are the ones that
43+
// contribute the most to its size.
44+
#[test]
45+
#[cfg(target_pointer_width = "64")]
46+
fn test_type_sizes() {
47+
// tidy-alphabetical-start
48+
assert_eq!(size_of::<AssocItemConstraint>(), 112);
49+
assert_eq!(size_of::<Crate>(), 184);
50+
assert_eq!(size_of::<ExternalCrate>(), 48);
51+
assert_eq!(size_of::<FunctionPointer>(), 168);
52+
assert_eq!(size_of::<GenericArg>(), 80);
53+
assert_eq!(size_of::<GenericArgs>(), 104);
54+
assert_eq!(size_of::<GenericBound>(), 72);
55+
assert_eq!(size_of::<GenericParamDef>(), 136);
56+
assert_eq!(size_of::<Impl>(), 304);
57+
assert_eq!(size_of::<Item>(), 552);
58+
assert_eq!(size_of::<ItemSummary>(), 32);
59+
assert_eq!(size_of::<PolyTrait>(), 64);
60+
assert_eq!(size_of::<PreciseCapturingArg>(), 32);
61+
assert_eq!(size_of::<TargetFeature>(), 80);
62+
assert_eq!(size_of::<Type>(), 80);
63+
assert_eq!(size_of::<WherePredicate>(), 160);
64+
// tidy-alphabetical-end
65+
}

src/tools/jsondoclint/src/validator.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ impl<'a> Validator<'a> {
271271
Type::RawPointer { is_mutable: _, type_ } => self.check_type(&**type_),
272272
Type::BorrowedRef { lifetime: _, is_mutable: _, type_ } => self.check_type(&**type_),
273273
Type::QualifiedPath { name: _, args, self_type, trait_ } => {
274-
self.check_generic_args(&**args);
274+
self.check_opt_generic_args(&args);
275275
self.check_type(&**self_type);
276276
if let Some(trait_) = trait_ {
277277
self.check_path(trait_, PathKind::Trait);
@@ -309,13 +309,12 @@ impl<'a> Validator<'a> {
309309
self.fail(&x.id, ErrorKind::Custom(format!("No entry in '$.paths' for {x:?}")));
310310
}
311311

312-
if let Some(args) = &x.args {
313-
self.check_generic_args(&**args);
314-
}
312+
self.check_opt_generic_args(&x.args);
315313
}
316314

317-
fn check_generic_args(&mut self, x: &'a GenericArgs) {
318-
match x {
315+
fn check_opt_generic_args(&mut self, x: &'a Option<Box<GenericArgs>>) {
316+
let Some(x) = x else { return };
317+
match &**x {
319318
GenericArgs::AngleBracketed { args, constraints } => {
320319
args.iter().for_each(|arg| self.check_generic_arg(arg));
321320
constraints.iter().for_each(|bind| self.check_assoc_item_constraint(bind));
@@ -355,7 +354,7 @@ impl<'a> Validator<'a> {
355354
}
356355

357356
fn check_assoc_item_constraint(&mut self, bind: &'a AssocItemConstraint) {
358-
self.check_generic_args(&bind.args);
357+
self.check_opt_generic_args(&bind.args);
359358
match &bind.binding {
360359
AssocItemConstraintKind::Equality(term) => self.check_term(term),
361360
AssocItemConstraintKind::Constraint(bounds) => {

tests/rustdoc-json/generic-args.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
pub struct MyStruct(u32);
2+
3+
pub trait MyTrait {
4+
type MyType;
5+
fn my_fn(&self);
6+
}
7+
8+
impl MyTrait for MyStruct {
9+
type MyType = u32;
10+
fn my_fn(&self) {}
11+
}
12+
13+
//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.args" null
14+
//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.args" null
15+
pub fn my_fn1(_: <MyStruct as MyTrait>::MyType) {}
16+
17+
//@ is "$.index[?(@.name=='my_fn2')].inner.function.sig.inputs[0][1].dyn_trait.traits[0].trait.args.angle_bracketed.constraints[0].args" null
18+
pub fn my_fn2(_: IntoIterator<Item = MyStruct, IntoIter = impl Clone>) {}
19+
20+
fn main() {}

0 commit comments

Comments
 (0)