Skip to content

Commit f7500c7

Browse files
committed
rustdoc-search: simplify rules for generics and type params
This commit is a response to feedback on the displayed type signatures results, by making type params looser and generics act stricter. Type params are loosened by allowing a single function type param to match multiple query params. In other words, the relationship is loosened to N:1 instead of the older 1:1 rule. This change also allows a type param to be unboxed in one spot and matched in another. Generics are tightened by making order significant. This means `Vec<Allocator>` now matches only with a true vector of allocators, instead of matching the second type param. It also makes unboxing within generics stricter, so `Result<A, B>` only matches if `B` is in the error type and `A` is in the success type. The top level of the function search is unaffected. Find the discussion on: * <https://rust-lang.zulipchat.com/#narrow/stream/393423-t-rustdoc.2Fmeetings/topic/meeting.202024-07-08/near/449965149> * <rust-lang#124544 (comment)>
1 parent b678a6b commit f7500c7

40 files changed

+603
-209
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
204204
"meant for internal use only" {
205205
keyword => rustdoc_internals
206206
fake_variadic => rustdoc_internals
207+
search_unbox => rustdoc_internals
207208
}
208209
);
209210
}

compiler/rustc_passes/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ passes_doc_masked_only_extern_crate =
226226
passes_doc_rust_logo =
227227
the `#[doc(rust_logo)]` attribute is used for Rust branding
228228
229+
passes_doc_search_unbox_invalid =
230+
`#[doc(search_unbox)]` should be used on generic structs and enums
231+
229232
passes_doc_test_literal = `#![doc(test(...)]` does not take a literal
230233
231234
passes_doc_test_takes_list =

compiler/rustc_passes/src/check_attr.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, B
1616
use rustc_hir::def_id::LocalModDefId;
1717
use rustc_hir::intravisit::{self, Visitor};
1818
use rustc_hir::{
19-
self as hir, self, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId, Item, ItemKind,
20-
MethodKind, Safety, Target, TraitItem,
19+
self as hir, self, AssocItemKind, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId,
20+
Item, ItemKind, MethodKind, Safety, Target, TraitItem,
2121
};
2222
use rustc_macros::LintDiagnostic;
2323
use rustc_middle::hir::nested_filter;
@@ -946,6 +946,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
946946
}
947947
}
948948

949+
fn check_doc_search_unbox(&self, meta: &NestedMetaItem, hir_id: HirId) {
950+
let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else {
951+
self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
952+
return;
953+
};
954+
match item.kind {
955+
ItemKind::Enum(_, generics) | ItemKind::Struct(_, generics)
956+
if generics.params.len() != 0 => {}
957+
ItemKind::Trait(_, _, generics, _, items)
958+
if generics.params.len() != 0
959+
|| items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {}
960+
_ => {
961+
self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
962+
}
963+
}
964+
}
965+
949966
/// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes.
950967
///
951968
/// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
@@ -1158,6 +1175,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
11581175
}
11591176
}
11601177

1178+
sym::search_unbox => {
1179+
if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
1180+
self.check_doc_search_unbox(meta, hir_id);
1181+
}
1182+
}
1183+
11611184
sym::test => {
11621185
if self.check_attr_crate_level(attr, meta, hir_id) {
11631186
self.check_test_attr(meta, hir_id);

compiler/rustc_passes/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,13 @@ pub(crate) struct DocKeywordOnlyImpl {
230230
pub span: Span,
231231
}
232232

233+
#[derive(Diagnostic)]
234+
#[diag(passes_doc_search_unbox_invalid)]
235+
pub(crate) struct DocSearchUnboxInvalid {
236+
#[primary_span]
237+
pub span: Span,
238+
}
239+
233240
#[derive(Diagnostic)]
234241
#[diag(passes_doc_inline_conflict)]
235242
#[help]

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1754,6 +1754,7 @@ symbols! {
17541754
saturating_add,
17551755
saturating_div,
17561756
saturating_sub,
1757+
search_unbox,
17571758
select_unpredictable,
17581759
self_in_typedefs,
17591760
self_struct_ctor,

library/alloc/src/boxed.rs

+1
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ mod thin;
228228
#[lang = "owned_box"]
229229
#[fundamental]
230230
#[stable(feature = "rust1", since = "1.0.0")]
231+
#[cfg_attr(not(bootstrap), doc(search_unbox))]
231232
// The declaration of the `Box` struct must be kept in sync with the
232233
// compiler or ICEs will happen.
233234
pub struct Box<

library/alloc/src/rc.rs

+1
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ fn rcbox_layout_for_value_layout(layout: Layout) -> Layout {
307307
/// `value.get_mut()`. This avoids conflicts with methods of the inner type `T`.
308308
///
309309
/// [get_mut]: Rc::get_mut
310+
#[cfg_attr(not(bootstrap), doc(search_unbox))]
310311
#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")]
311312
#[stable(feature = "rust1", since = "1.0.0")]
312313
#[rustc_insignificant_dtor]

library/alloc/src/sync.rs

+1
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ macro_rules! acquire {
235235
/// counting in general.
236236
///
237237
/// [rc_examples]: crate::rc#examples
238+
#[cfg_attr(not(bootstrap), doc(search_unbox))]
238239
#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")]
239240
#[stable(feature = "rust1", since = "1.0.0")]
240241
pub struct Arc<

library/core/src/future/future.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::task::{Context, Poll};
2525
/// [`async`]: ../../std/keyword.async.html
2626
/// [`Waker`]: crate::task::Waker
2727
#[doc(notable_trait)]
28+
#[cfg_attr(not(bootstrap), doc(search_unbox))]
2829
#[must_use = "futures do nothing unless you `.await` or poll them"]
2930
#[stable(feature = "futures_api", since = "1.36.0")]
3031
#[lang = "future_trait"]

library/core/src/option.rs

+1
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ use crate::pin::Pin;
563563
use crate::{cmp, convert, hint, mem, slice};
564564

565565
/// The `Option` type. See [the module level documentation](self) for more.
566+
#[cfg_attr(not(bootstrap), doc(search_unbox))]
566567
#[derive(Copy, Eq, Debug, Hash)]
567568
#[rustc_diagnostic_item = "Option"]
568569
#[lang = "Option"]

library/core/src/result.rs

+1
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ use crate::{convert, fmt, hint};
520520
/// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
521521
///
522522
/// See the [module documentation](self) for details.
523+
#[cfg_attr(not(bootstrap), doc(search_unbox))]
523524
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
524525
#[must_use = "this `Result` may be an `Err` variant, which should be handled"]
525526
#[rustc_diagnostic_item = "Result"]

src/doc/rustdoc/src/read-documentation/search.md

+7-5
Original file line numberDiff line numberDiff line change
@@ -130,29 +130,31 @@ pub trait MyTrait {
130130
/// This function can be found using the following search queries:
131131
///
132132
/// MyTrait<First=u8, Second=u32> -> bool
133-
/// MyTrait<u32, First=u8> -> bool
134133
/// MyTrait<Second=u32> -> bool
135-
/// MyTrait<u32, u8> -> bool
136134
///
137135
/// The following queries, however, will *not* match it:
138136
///
139137
/// MyTrait<First=u32> -> bool
140138
/// MyTrait<u32, u32> -> bool
139+
/// MyTrait<u32, First=u8> -> bool
140+
/// MyTrait<u32, u8> -> bool
141141
pub fn my_fn(x: impl MyTrait<First=u8, Second=u32>) -> bool { true }
142142
```
143143

144-
Generics and function parameters are order-agnostic, but sensitive to nesting
144+
Function parameters are order-agnostic, but sensitive to nesting
145145
and number of matches. For example, a function with the signature
146146
`fn read_all(&mut self: impl Read) -> Result<Vec<u8>, Error>`
147147
will match these queries:
148148

149149
* `&mut Read -> Result<Vec<u8>, Error>`
150150
* `Read -> Result<Vec<u8>, Error>`
151-
* `Read -> Result<Error, Vec>`
152151
* `Read -> Result<Vec<u8>>`
153152
* `Read -> u8`
154153

155-
But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`.
154+
But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`,
155+
because those are nested incorrectly, and it does not match
156+
`Result<Error, Vec<u8>>` or `Result<Error>`, because those are
157+
in the wrong order.
156158

157159
To search for a function that accepts a function as a parameter,
158160
like `Iterator::all`, wrap the nested signature in parenthesis,

0 commit comments

Comments
 (0)