Skip to content

Commit

Permalink
Rollup merge of rust-lang#124148 - notriddle:notriddle/reference, r=G…
Browse files Browse the repository at this point in the history
…uillaumeGomez

rustdoc-search: search for references

This feature extends rustdoc with syntax and search index information for searching borrow references. Part of rust-lang#60485

## Preview

- [`&mut`](https://notriddle.com/rustdoc-html-demo-11/reference/std/index.html?search=%26mut)
- [`&Option<T> -> Option<&T>`](https://notriddle.com/rustdoc-html-demo-11/reference/std/index.html?search=%26Option%3CT%3E%20-%3E%20Option%3C%26T%3E)
- [`&mut Option<T> -> Option<&mut T>`](https://notriddle.com/rustdoc-html-demo-11/reference/std/index.html?search=%26mut%20Option%3CT%3E%20-%3E%20Option%3C%26mut%20T%3E)

Updated chapter of the book: https://notriddle.com/rustdoc-html-demo-11/reference/rustdoc/read-documentation/search.html

## Motivation

See rust-lang#119676

## Guide-level explanation

You can't search by lifetimes, but other than that it's the same syntax references normally use.

## Reference-level description

<table>
<thead>
  <tr>
    <th>Shorthand</th>
    <th>Explicit names</th>
  </tr>
</thead>
<tbody>
  <tr><td colspan="2">Before this PR</td></tr>
  <tr>
    <td><code>[]</code></td>
    <td><code>primitive:slice</code> and/or <code>primitive:array</code></td>
  </tr>
  <tr>
    <td><code>[T]</code></td>
    <td><code>primitive:slice&lt;T&gt;</code> and/or <code>primitive:array&lt;T&gt;</code></td>
  </tr>
  <tr>
    <td><code>!</code></td>
    <td><code>primitive:never</code></td>
  </tr>
  <tr>
    <td><code>()</code></td>
    <td><code>primitive:unit</code> and/or <code>primitive:tuple</code></td>
  </tr>
  <tr>
    <td><code>(T)</code></td>
    <td><code>T</code></td>
  </tr>
  <tr>
    <td><code>(T,)</code></td>
    <td><code>primitive:tuple&lt;T&gt;</code></td>
  </tr>
  <tr>
    <td><code>(T, U -> V, W)</code></td>
    <td><code>fn(T, U) -> (V, W)</code>, Fn, FnMut, and FnOnce</td>
  </tr>
  <tr><td colspan="2">New additions with this PR</td></tr>
  <tr>
    <td><code>&</code></td>
    <td><code>primitive:reference</td>
  </tr>
  <tr>
    <td><code>&mut</code></td>
    <td><code>primitive:reference&lt;keyword:mut&gt;</td>
  </tr>
  <tr>
    <td><code>&T</code></td>
    <td><code>primitive:reference&lt;T&gt;</td>
  </tr>
  <tr>
    <td><code>&mut T</code></td>
    <td><code>primitive:reference&lt;keyword:mut, T&gt;</td>
  </tr>
</tbody>
</table>

### Search query grammar

<code><pre><strong>borrow-ref = AMP *WS [MUT] *WS [arg]</strong>
arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like / <strong>borrow-ref</strong>)</pre></code>

```
AMP = "&"
MUT = "mut"
```

## Future direction

As described in rust-lang#118194 and rust-lang#119676

* The remaining type expression grammar (this is another step in the type expression grammar: `ReferenceType` is now supported)
* Search subtyping and traits
  • Loading branch information
GuillaumeGomez committed May 5, 2024
2 parents 02f7806 + c514471 commit 042d0f5
Show file tree
Hide file tree
Showing 7 changed files with 874 additions and 24 deletions.
10 changes: 9 additions & 1 deletion src/doc/rustdoc/src/read-documentation/search.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ and number of matches. For example, a function with the signature
`fn read_all(&mut self: impl Read) -> Result<Vec<u8>, Error>`
will match these queries:

* `&mut Read -> Result<Vec<u8>, Error>`
* `Read -> Result<Vec<u8>, Error>`
* `Read -> Result<Error, Vec>`
* `Read -> Result<Vec<u8>>`
Expand All @@ -166,6 +167,10 @@ but you need to know which one you want.

| Shorthand | Explicit names |
| ---------------- | ------------------------------------------------- |
| `&` | `primitive:reference` |
| `&T` | `primitive:reference<T>` |
| `&mut` | `primitive:reference<keyword:mut>` |
| `&mut T` | `primitive:reference<keyword:mut, T>` |
| `[]` | `primitive:slice` and/or `primitive:array` |
| `[T]` | `primitive:slice<T>` and/or `primitive:array<T>` |
| `()` | `primitive:unit` and/or `primitive:tuple` |
Expand Down Expand Up @@ -253,7 +258,8 @@ ident = *(ALPHA / DIGIT / "_")
path = ident *(DOUBLE-COLON ident) [BANG]
slice-like = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET
tuple-like = OPEN-PAREN [ nonempty-arg-list ] CLOSE-PAREN
arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like)
borrow-ref = AMP *WS [MUT] *WS [arg]
arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like / borrow-ref)
type-sep = COMMA/WS *(COMMA/WS)
nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep) [ return-args ]
generic-arg-list = *(type-sep) arg [ EQUAL arg ] *(type-sep arg [ EQUAL arg ]) *(type-sep)
Expand Down Expand Up @@ -310,6 +316,8 @@ COMMA = ","
RETURN-ARROW = "->"
EQUAL = "="
BANG = "!"
AMP = "&"
MUT = "mut"
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
DIGIT = %x30-39
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ pub(crate) enum RenderTypeId {
Primitive(clean::PrimitiveType),
AssociatedType(Symbol),
Index(isize),
Mut,
}

impl RenderTypeId {
Expand Down
61 changes: 38 additions & 23 deletions src/librustdoc/html/render/search_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::DefId;
use rustc_span::sym;
use rustc_span::symbol::Symbol;
use rustc_span::symbol::{kw, Symbol};
use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
use thin_vec::ThinVec;

Expand Down Expand Up @@ -163,6 +163,15 @@ pub(crate) fn build_index<'tcx>(
) -> Option<RenderTypeId> {
let Cache { ref paths, ref external_paths, ref exact_paths, .. } = *cache;
match id {
RenderTypeId::Mut => Some(insert_into_map(
primitives,
kw::Mut,
lastpathid,
crate_paths,
ItemType::Keyword,
&[kw::Mut],
None,
)),
RenderTypeId::DefId(defid) => {
if let Some(&(ref fqp, item_type)) =
paths.get(&defid).or_else(|| external_paths.get(&defid))
Expand Down Expand Up @@ -765,9 +774,8 @@ fn get_index_type_id(
bounds.get(0).map(|b| RenderTypeId::DefId(b.trait_.def_id()))
}
clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
get_index_type_id(type_, rgen)
}
clean::BorrowedRef { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::Reference)),
clean::RawPointer(_, ref type_) => get_index_type_id(type_, rgen),
// The type parameters are converted to generics in `simplify_fn_type`
clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
Expand Down Expand Up @@ -833,28 +841,14 @@ fn simplify_fn_type<'tcx, 'a>(
}

// First, check if it's "Self".
let mut is_self = false;
let mut arg = if let Some(self_) = self_ {
match &*arg {
Type::BorrowedRef { type_, .. } if type_.is_self_type() => {
is_self = true;
self_
}
type_ if type_.is_self_type() => {
is_self = true;
self_
}
arg => arg,
}
let (is_self, arg) = if let Some(self_) = self_
&& arg.is_self_type()
{
(true, self_)
} else {
arg
(false, arg)
};

// strip references from the argument type
while let Type::BorrowedRef { type_, .. } = &*arg {
arg = &*type_;
}

// If this argument is a type parameter and not a trait bound or a type, we need to look
// for its bounds.
if let Type::Generic(arg_s) = *arg {
Expand Down Expand Up @@ -1027,6 +1021,27 @@ fn simplify_fn_type<'tcx, 'a>(
bindings: Some(ty_bindings),
generics: Some(ty_generics),
});
} else if let Type::BorrowedRef { lifetime: _, mutability, ref type_ } = *arg {
let mut ty_generics = Vec::new();
if mutability.is_mut() {
ty_generics.push(RenderType {
id: Some(RenderTypeId::Mut),
generics: None,
bindings: None,
});
}
simplify_fn_type(
self_,
generics,
&type_,
tcx,
recurse + 1,
&mut ty_generics,
rgen,
is_return,
cache,
);
res.push(get_index_type(arg, ty_generics, rgen));
} else {
// This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
// looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
Expand Down
31 changes: 31 additions & 0 deletions src/librustdoc/html/static/js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,37 @@ function initSearch(rawSearchIndex) {
}
elems.push(makePrimitiveElement(name, { bindingName, generics }));
}
} else if (parserState.userQuery[parserState.pos] === "&") {
if (parserState.typeFilter !== null && parserState.typeFilter !== "primitive") {
throw [
"Invalid search type: primitive ",
"&",
" and ",
parserState.typeFilter,
" both specified",
];
}
parserState.typeFilter = null;
parserState.pos += 1;
let c = parserState.userQuery[parserState.pos];
while (c === " " && parserState.pos < parserState.length) {
parserState.pos += 1;
c = parserState.userQuery[parserState.pos];
}
const generics = [];
if (parserState.userQuery.slice(parserState.pos, parserState.pos + 3) === "mut") {
generics.push(makePrimitiveElement("mut", { typeFilter: "keyword"}));
parserState.pos += 3;
c = parserState.userQuery[parserState.pos];
}
while (c === " " && parserState.pos < parserState.length) {
parserState.pos += 1;
c = parserState.userQuery[parserState.pos];
}
if (!isEndCharacter(c) && parserState.pos < parserState.length) {
getFilteredNextElem(query, parserState, generics, isInGenerics);
}
elems.push(makePrimitiveElement("reference", { generics }));
} else {
const isStringElem = parserState.userQuery[start] === "\"";
// We handle the strings on their own mostly to make code easier to follow.
Expand Down
Loading

0 comments on commit 042d0f5

Please sign in to comment.