mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 06:22:00 +00:00
Auto merge of #92216 - matthiaskrgr:rollup-luplvuc, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #88858 (Allow reverse iteration of lowercase'd/uppercase'd chars) - #91544 (Fix duplicate derive clone suggestion) - #92026 (Add some JSDoc comments to rustdoc JS) - #92117 (kmc-solid: Add `std::sys::solid::fs::File::read_buf`) - #92139 (Change Backtrace::enabled atomic from SeqCst to Relaxed) - #92146 (Don't emit shared files when scraping examples from dependencies in Rustdoc) - #92208 (Quote bat script command line) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5aa0239b16
@ -1195,11 +1195,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn suggest_derive(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
unsatisfied_predicates: &Vec<(
|
||||
unsatisfied_predicates: &[(
|
||||
ty::Predicate<'tcx>,
|
||||
Option<ty::Predicate<'tcx>>,
|
||||
Option<ObligationCause<'tcx>>,
|
||||
)>,
|
||||
)],
|
||||
) {
|
||||
let mut derives = Vec::<(String, Span, String)>::new();
|
||||
let mut traits = Vec::<Span>::new();
|
||||
@ -1236,23 +1236,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
traits.push(self.tcx.def_span(trait_pred.def_id()));
|
||||
}
|
||||
}
|
||||
derives.sort();
|
||||
let derives_grouped = derives.into_iter().fold(
|
||||
Vec::<(String, Span, String)>::new(),
|
||||
|mut acc, (self_name, self_span, trait_name)| {
|
||||
if let Some((acc_self_name, _, ref mut traits)) = acc.last_mut() {
|
||||
if acc_self_name == &self_name {
|
||||
traits.push_str(format!(", {}", trait_name).as_str());
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
acc.push((self_name, self_span, trait_name));
|
||||
acc
|
||||
},
|
||||
);
|
||||
traits.sort();
|
||||
traits.dedup();
|
||||
|
||||
derives.sort();
|
||||
derives.dedup();
|
||||
|
||||
let mut derives_grouped = Vec::<(String, Span, String)>::new();
|
||||
for (self_name, self_span, trait_name) in derives.into_iter() {
|
||||
if let Some((last_self_name, _, ref mut last_trait_names)) = derives_grouped.last_mut()
|
||||
{
|
||||
if last_self_name == &self_name {
|
||||
last_trait_names.push_str(format!(", {}", trait_name).as_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
derives_grouped.push((self_name, self_span, trait_name));
|
||||
}
|
||||
|
||||
let len = traits.len();
|
||||
if len > 0 {
|
||||
let span: MultiSpan = traits.into();
|
||||
|
@ -1183,6 +1183,37 @@ fn test_rev_iterator() {
|
||||
assert_eq!(pos, v.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_lowercase_rev_iterator() {
|
||||
let s = "AÖßÜ💩ΣΤΙΓΜΑΣDžfiİ";
|
||||
let v = ['\u{307}', 'i', 'fi', 'dž', 'σ', 'α', 'μ', 'γ', 'ι', 'τ', 'σ', '💩', 'ü', 'ß', 'ö', 'a'];
|
||||
|
||||
let mut pos = 0;
|
||||
let it = s.chars().flat_map(|c| c.to_lowercase()).rev();
|
||||
|
||||
for c in it {
|
||||
assert_eq!(c, v[pos]);
|
||||
pos += 1;
|
||||
}
|
||||
assert_eq!(pos, v.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_uppercase_rev_iterator() {
|
||||
let s = "aößü💩στιγμαςDžfiᾀ";
|
||||
let v =
|
||||
['Ι', 'Ἀ', 'I', 'F', 'DŽ', 'Σ', 'Α', 'Μ', 'Γ', 'Ι', 'Τ', 'Σ', '💩', 'Ü', 'S', 'S', 'Ö', 'A'];
|
||||
|
||||
let mut pos = 0;
|
||||
let it = s.chars().flat_map(|c| c.to_uppercase()).rev();
|
||||
|
||||
for c in it {
|
||||
assert_eq!(c, v[pos]);
|
||||
pos += 1;
|
||||
}
|
||||
assert_eq!(pos, v.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_chars_decoding() {
|
||||
|
@ -393,6 +393,13 @@ impl Iterator for ToLowercase {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "case_mapping_double_ended", since = "1.59.0")]
|
||||
impl DoubleEndedIterator for ToLowercase {
|
||||
fn next_back(&mut self) -> Option<char> {
|
||||
self.0.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl FusedIterator for ToLowercase {}
|
||||
|
||||
@ -420,6 +427,13 @@ impl Iterator for ToUppercase {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "case_mapping_double_ended", since = "1.59.0")]
|
||||
impl DoubleEndedIterator for ToUppercase {
|
||||
fn next_back(&mut self) -> Option<char> {
|
||||
self.0.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl FusedIterator for ToUppercase {}
|
||||
|
||||
@ -479,6 +493,26 @@ impl Iterator for CaseMappingIter {
|
||||
}
|
||||
}
|
||||
|
||||
impl DoubleEndedIterator for CaseMappingIter {
|
||||
fn next_back(&mut self) -> Option<char> {
|
||||
match *self {
|
||||
CaseMappingIter::Three(a, b, c) => {
|
||||
*self = CaseMappingIter::Two(a, b);
|
||||
Some(c)
|
||||
}
|
||||
CaseMappingIter::Two(b, c) => {
|
||||
*self = CaseMappingIter::One(b);
|
||||
Some(c)
|
||||
}
|
||||
CaseMappingIter::One(c) => {
|
||||
*self = CaseMappingIter::Zero;
|
||||
Some(c)
|
||||
}
|
||||
CaseMappingIter::Zero => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CaseMappingIter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
|
@ -103,6 +103,9 @@ fn test_to_lowercase() {
|
||||
let iter: String = c.to_lowercase().collect();
|
||||
let disp: String = c.to_lowercase().to_string();
|
||||
assert_eq!(iter, disp);
|
||||
let iter_rev: String = c.to_lowercase().rev().collect();
|
||||
let disp_rev: String = disp.chars().rev().collect();
|
||||
assert_eq!(iter_rev, disp_rev);
|
||||
iter
|
||||
}
|
||||
assert_eq!(lower('A'), "a");
|
||||
@ -130,6 +133,9 @@ fn test_to_uppercase() {
|
||||
let iter: String = c.to_uppercase().collect();
|
||||
let disp: String = c.to_uppercase().to_string();
|
||||
assert_eq!(iter, disp);
|
||||
let iter_rev: String = c.to_uppercase().rev().collect();
|
||||
let disp_rev: String = disp.chars().rev().collect();
|
||||
assert_eq!(iter_rev, disp_rev);
|
||||
iter
|
||||
}
|
||||
assert_eq!(upper('a'), "A");
|
||||
|
@ -99,7 +99,7 @@ use crate::cell::UnsafeCell;
|
||||
use crate::env;
|
||||
use crate::ffi::c_void;
|
||||
use crate::fmt;
|
||||
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||
use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
|
||||
use crate::sync::Once;
|
||||
use crate::sys_common::backtrace::{lock, output_filename};
|
||||
use crate::vec::Vec;
|
||||
@ -256,7 +256,7 @@ impl Backtrace {
|
||||
// backtrace captures speedy, because otherwise reading environment
|
||||
// variables every time can be somewhat slow.
|
||||
static ENABLED: AtomicUsize = AtomicUsize::new(0);
|
||||
match ENABLED.load(SeqCst) {
|
||||
match ENABLED.load(Relaxed) {
|
||||
0 => {}
|
||||
1 => return false,
|
||||
_ => return true,
|
||||
@ -268,7 +268,7 @@ impl Backtrace {
|
||||
Err(_) => false,
|
||||
},
|
||||
};
|
||||
ENABLED.store(enabled as usize + 1, SeqCst);
|
||||
ENABLED.store(enabled as usize + 1, Relaxed);
|
||||
enabled
|
||||
}
|
||||
|
||||
|
@ -420,3 +420,22 @@ fn env_empty() {
|
||||
let p = Command::new("cmd").args(&["/C", "exit 0"]).env_clear().spawn();
|
||||
assert!(p.is_ok());
|
||||
}
|
||||
|
||||
// See issue #91991
|
||||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn run_bat_script() {
|
||||
let tempdir = crate::sys_common::io::test::tmpdir();
|
||||
let script_path = tempdir.join("hello.cmd");
|
||||
|
||||
crate::fs::write(&script_path, "@echo Hello, %~1!").unwrap();
|
||||
let output = Command::new(&script_path)
|
||||
.arg("fellow Rustaceans")
|
||||
.stdout(crate::process::Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait_with_output()
|
||||
.unwrap();
|
||||
assert!(output.status.success());
|
||||
assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "Hello, fellow Rustaceans!");
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use super::{abi, error};
|
||||
use crate::{
|
||||
ffi::{CStr, CString, OsStr, OsString},
|
||||
fmt,
|
||||
io::{self, IoSlice, IoSliceMut, SeekFrom},
|
||||
io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom},
|
||||
mem::MaybeUninit,
|
||||
os::raw::{c_int, c_short},
|
||||
os::solid::ffi::OsStrExt,
|
||||
@ -339,6 +339,32 @@ impl File {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
|
||||
unsafe {
|
||||
let len = buf.remaining();
|
||||
let mut out_num_bytes = MaybeUninit::uninit();
|
||||
error::SolidError::err_if_negative(abi::SOLID_FS_Read(
|
||||
self.fd.raw(),
|
||||
buf.unfilled_mut().as_mut_ptr() as *mut u8,
|
||||
len,
|
||||
out_num_bytes.as_mut_ptr(),
|
||||
))
|
||||
.map_err(|e| e.as_io_error())?;
|
||||
|
||||
// Safety: `out_num_bytes` is filled by the successful call to
|
||||
// `SOLID_FS_Read`
|
||||
let num_bytes_read = out_num_bytes.assume_init();
|
||||
|
||||
// Safety: `num_bytes_read` bytes were written to the unfilled
|
||||
// portion of the buffer
|
||||
buf.assume_init(num_bytes_read);
|
||||
|
||||
buf.add_filled(num_bytes_read);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
crate::io::default_read_vectored(|buf| self.read(buf), bufs)
|
||||
}
|
||||
|
@ -704,6 +704,19 @@ fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Resu
|
||||
// Encode the command and arguments in a command line string such
|
||||
// that the spawned process may recover them using CommandLineToArgvW.
|
||||
let mut cmd: Vec<u16> = Vec::new();
|
||||
|
||||
// CreateFileW has special handling for .bat and .cmd files, which means we
|
||||
// need to add an extra pair of quotes surrounding the whole command line
|
||||
// so they are properly passed on to the script.
|
||||
// See issue #91991.
|
||||
let is_batch_file = Path::new(prog)
|
||||
.extension()
|
||||
.map(|ext| ext.eq_ignore_ascii_case("cmd") || ext.eq_ignore_ascii_case("bat"))
|
||||
.unwrap_or(false);
|
||||
if is_batch_file {
|
||||
cmd.push(b'"' as u16);
|
||||
}
|
||||
|
||||
// Always quote the program name so CreateProcess doesn't interpret args as
|
||||
// part of the name if the binary wasn't found first time.
|
||||
append_arg(&mut cmd, prog, Quote::Always)?;
|
||||
@ -715,6 +728,9 @@ fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Resu
|
||||
};
|
||||
append_arg(&mut cmd, arg, quote)?;
|
||||
}
|
||||
if is_batch_file {
|
||||
cmd.push(b'"' as u16);
|
||||
}
|
||||
return Ok(cmd);
|
||||
|
||||
fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, quote: Quote) -> io::Result<()> {
|
||||
|
@ -272,7 +272,10 @@ crate struct RenderOptions {
|
||||
crate emit: Vec<EmitType>,
|
||||
/// If `true`, HTML source pages will generate links for items to their definition.
|
||||
crate generate_link_to_definition: bool,
|
||||
/// Set of function-call locations to include as examples
|
||||
crate call_locations: AllCallLocations,
|
||||
/// If `true`, Context::init will not emit shared files.
|
||||
crate no_emit_shared: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
@ -732,6 +735,7 @@ impl Options {
|
||||
emit,
|
||||
generate_link_to_definition,
|
||||
call_locations,
|
||||
no_emit_shared: false,
|
||||
},
|
||||
crate_name,
|
||||
output_format,
|
||||
|
@ -397,6 +397,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||
show_type_layout,
|
||||
generate_link_to_definition,
|
||||
call_locations,
|
||||
no_emit_shared,
|
||||
..
|
||||
} = options;
|
||||
|
||||
@ -516,6 +517,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||
sources::render(&mut cx, &krate)?;
|
||||
}
|
||||
|
||||
if !no_emit_shared {
|
||||
// Build our search index
|
||||
let index = build_index(&krate, &mut Rc::get_mut(&mut cx.shared).unwrap().cache, tcx);
|
||||
|
||||
@ -523,6 +525,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||
Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true);
|
||||
write_shared(&cx, &krate, index, &md_opts)?;
|
||||
Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false);
|
||||
}
|
||||
|
||||
Ok((cx, krate))
|
||||
}
|
||||
|
||||
|
15
src/librustdoc/html/static/js/README.md
Normal file
15
src/librustdoc/html/static/js/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Rustdoc JS
|
||||
|
||||
These JavaScript files are incorporated into the rustdoc binary at build time,
|
||||
and are minified and written to the filesystem as part of the doc build process.
|
||||
|
||||
We use the [Closure Compiler](https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler)
|
||||
dialect of JSDoc to comment our code and annotate params and return types.
|
||||
To run a check:
|
||||
|
||||
./x.py doc library/std
|
||||
npm i -g google-closure-compiler
|
||||
google-closure-compiler -W VERBOSE \
|
||||
build/<YOUR PLATFORM>/doc/{search-index*.js,crates*.js} \
|
||||
src/librustdoc/html/static/js/{search.js,main.js,storage.js} \
|
||||
--externs src/librustdoc/html/static/js/externs.js >/dev/null
|
32
src/librustdoc/html/static/js/externs.js
Normal file
32
src/librustdoc/html/static/js/externs.js
Normal file
@ -0,0 +1,32 @@
|
||||
// This file contains type definitions that are processed by the Closure Compiler but are
|
||||
// not put into the JavaScript we include as part of the documentation. It is used for
|
||||
// type checking. See README.md in this directory for more info.
|
||||
|
||||
/* eslint-disable */
|
||||
var searchState;
|
||||
function initSearch(searchIndex){}
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* raw: string,
|
||||
* query: string,
|
||||
* type: string,
|
||||
* id: string,
|
||||
* }}
|
||||
*/
|
||||
var ParsedQuery;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* crate: string,
|
||||
* desc: string,
|
||||
* id: number,
|
||||
* name: string,
|
||||
* normalizedName: string,
|
||||
* parent: (Object|null|undefined),
|
||||
* path: string,
|
||||
* ty: (Number|null|number),
|
||||
* type: (Array<?>|null)
|
||||
* }}
|
||||
*/
|
||||
var Row;
|
@ -420,6 +420,13 @@ function hideThemeButtonState() {
|
||||
return document.getElementById("help");
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the help popup.
|
||||
*
|
||||
* @param {boolean} display - Whether to show or hide the popup
|
||||
* @param {Event} ev - The event that triggered this call
|
||||
* @param {Element} [help] - The help element if it already exists
|
||||
*/
|
||||
function displayHelp(display, ev, help) {
|
||||
if (display) {
|
||||
help = help ? help : getHelpElement(true);
|
||||
|
@ -113,7 +113,15 @@ window.initSearch = function(rawSearchIndex) {
|
||||
var INPUTS_DATA = 0;
|
||||
var OUTPUT_DATA = 1;
|
||||
var NO_TYPE_FILTER = -1;
|
||||
var currentResults, index, searchIndex;
|
||||
/**
|
||||
* @type {Array<Row>}
|
||||
*/
|
||||
var searchIndex;
|
||||
/**
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
var searchWords;
|
||||
var currentResults;
|
||||
var ALIASES = {};
|
||||
var params = searchState.getQueryStringParams();
|
||||
|
||||
@ -126,12 +134,15 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query and builds an index of results
|
||||
* @param {[Object]} query [The user query]
|
||||
* @param {[type]} searchWords [The list of search words to query
|
||||
* against]
|
||||
* @param {[type]} filterCrates [Crate to search in if defined]
|
||||
* @return {[type]} [A search index of results]
|
||||
* Executes the query and returns a list of results for each results tab.
|
||||
* @param {Object} query - The user query
|
||||
* @param {Array<string>} searchWords - The list of search words to query against
|
||||
* @param {string} [filterCrates] - Crate to search in
|
||||
* @return {{
|
||||
* in_args: Array<?>,
|
||||
* returned: Array<?>,
|
||||
* others: Array<?>
|
||||
* }}
|
||||
*/
|
||||
function execQuery(query, searchWords, filterCrates) {
|
||||
function itemTypeFromName(typename) {
|
||||
@ -847,11 +858,11 @@ window.initSearch = function(rawSearchIndex) {
|
||||
* This could be written functionally, but I wanted to minimise
|
||||
* functions on stack.
|
||||
*
|
||||
* @param {[string]} name [The name of the result]
|
||||
* @param {[string]} path [The path of the result]
|
||||
* @param {[string]} keys [The keys to be used (["file", "open"])]
|
||||
* @param {[object]} parent [The parent of the result]
|
||||
* @return {boolean} [Whether the result is valid or not]
|
||||
* @param {string} name - The name of the result
|
||||
* @param {string} path - The path of the result
|
||||
* @param {string} keys - The keys to be used (["file", "open"])
|
||||
* @param {Object} parent - The parent of the result
|
||||
* @return {boolean} - Whether the result is valid or not
|
||||
*/
|
||||
function validateResult(name, path, keys, parent) {
|
||||
for (var i = 0, len = keys.length; i < len; ++i) {
|
||||
@ -872,8 +883,14 @@ window.initSearch = function(rawSearchIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a string into a query object.
|
||||
*
|
||||
* @param {string} raw - The text that the user typed.
|
||||
* @returns {ParsedQuery}
|
||||
*/
|
||||
function getQuery(raw) {
|
||||
var matches, type, query;
|
||||
var matches, type = "", query;
|
||||
query = raw;
|
||||
|
||||
matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
|
||||
@ -974,6 +991,12 @@ window.initSearch = function(rawSearchIndex) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a set of search results for a single tab.
|
||||
* @param {Array<?>} array - The search results for this tab
|
||||
* @param {ParsedQuery} query
|
||||
* @param {boolean} display - True if this is the active tab
|
||||
*/
|
||||
function addTab(array, query, display) {
|
||||
var extraClass = "";
|
||||
if (display === true) {
|
||||
@ -1083,7 +1106,7 @@ window.initSearch = function(rawSearchIndex) {
|
||||
|
||||
currentResults = query.id;
|
||||
|
||||
var ret_others = addTab(results.others, query);
|
||||
var ret_others = addTab(results.others, query, true);
|
||||
var ret_in_args = addTab(results.in_args, query, false);
|
||||
var ret_returned = addTab(results.returned, query, false);
|
||||
|
||||
@ -1253,6 +1276,12 @@ window.initSearch = function(rawSearchIndex) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a search based on the current state of the search input element
|
||||
* and display the results.
|
||||
* @param {Event} [e] - The event that triggered this search, if any
|
||||
* @param {boolean} [forced]
|
||||
*/
|
||||
function search(e, forced) {
|
||||
var params = searchState.getQueryStringParams();
|
||||
var query = getQuery(searchState.input.value.trim());
|
||||
@ -1287,11 +1316,14 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
|
||||
var filterCrates = getFilterCrates();
|
||||
showResults(execSearch(query, index, filterCrates), params.go_to_first);
|
||||
showResults(execSearch(query, searchWords, filterCrates), params["go_to_first"]);
|
||||
}
|
||||
|
||||
function buildIndex(rawSearchIndex) {
|
||||
searchIndex = [];
|
||||
/**
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
var searchWords = [];
|
||||
var i, word;
|
||||
var currentIndex = 0;
|
||||
@ -1304,6 +1336,38 @@ window.initSearch = function(rawSearchIndex) {
|
||||
|
||||
var crateSize = 0;
|
||||
|
||||
/**
|
||||
* The raw search data for a given crate. `n`, `t`, `d`, and `q`, `i`, and `f`
|
||||
* are arrays with the same length. n[i] contains the name of an item.
|
||||
* t[i] contains the type of that item (as a small integer that represents an
|
||||
* offset in `itemTypes`). d[i] contains the description of that item.
|
||||
*
|
||||
* q[i] contains the full path of the item, or an empty string indicating
|
||||
* "same as q[i-1]".
|
||||
*
|
||||
* i[i], f[i] are a mystery.
|
||||
*
|
||||
* `a` defines aliases with an Array of pairs: [name, offset], where `offset`
|
||||
* points into the n/t/d/q/i/f arrays.
|
||||
*
|
||||
* `doc` contains the description of the crate.
|
||||
*
|
||||
* `p` is a mystery and isn't the same length as n/t/d/q/i/f.
|
||||
*
|
||||
* @type {{
|
||||
* doc: string,
|
||||
* a: Object,
|
||||
* n: Array<string>,
|
||||
* t: Array<Number>,
|
||||
* d: Array<string>,
|
||||
* q: Array<string>,
|
||||
* i: Array<Number>,
|
||||
* f: Array<Array<?>>,
|
||||
* p: Array<Object>,
|
||||
* }}
|
||||
*/
|
||||
var crateCorpus = rawSearchIndex[crate];
|
||||
|
||||
searchWords.push(crate);
|
||||
// This object should have exactly the same set of fields as the "row"
|
||||
// object defined below. Your JavaScript runtime will thank you.
|
||||
@ -1313,7 +1377,7 @@ window.initSearch = function(rawSearchIndex) {
|
||||
ty: 1, // == ExternCrate
|
||||
name: crate,
|
||||
path: "",
|
||||
desc: rawSearchIndex[crate].doc,
|
||||
desc: crateCorpus.doc,
|
||||
parent: undefined,
|
||||
type: null,
|
||||
id: id,
|
||||
@ -1324,23 +1388,23 @@ window.initSearch = function(rawSearchIndex) {
|
||||
currentIndex += 1;
|
||||
|
||||
// an array of (Number) item types
|
||||
var itemTypes = rawSearchIndex[crate].t;
|
||||
var itemTypes = crateCorpus.t;
|
||||
// an array of (String) item names
|
||||
var itemNames = rawSearchIndex[crate].n;
|
||||
var itemNames = crateCorpus.n;
|
||||
// an array of (String) full paths (or empty string for previous path)
|
||||
var itemPaths = rawSearchIndex[crate].q;
|
||||
var itemPaths = crateCorpus.q;
|
||||
// an array of (String) descriptions
|
||||
var itemDescs = rawSearchIndex[crate].d;
|
||||
var itemDescs = crateCorpus.d;
|
||||
// an array of (Number) the parent path index + 1 to `paths`, or 0 if none
|
||||
var itemParentIdxs = rawSearchIndex[crate].i;
|
||||
var itemParentIdxs = crateCorpus.i;
|
||||
// an array of (Object | null) the type of the function, if any
|
||||
var itemFunctionSearchTypes = rawSearchIndex[crate].f;
|
||||
var itemFunctionSearchTypes = crateCorpus.f;
|
||||
// an array of [(Number) item type,
|
||||
// (String) name]
|
||||
var paths = rawSearchIndex[crate].p;
|
||||
var paths = crateCorpus.p;
|
||||
// an array of [(String) alias name
|
||||
// [Number] index to items]
|
||||
var aliases = rawSearchIndex[crate].a;
|
||||
var aliases = crateCorpus.a;
|
||||
|
||||
// convert `rawPaths` entries into object form
|
||||
var len = paths.length;
|
||||
@ -1406,6 +1470,16 @@ window.initSearch = function(rawSearchIndex) {
|
||||
return searchWords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the search form is submitted.
|
||||
* @param {Event} [e] - The event that triggered this call, if any
|
||||
*/
|
||||
function onSearchSubmit(e) {
|
||||
e.preventDefault();
|
||||
searchState.clearInputTimeout();
|
||||
search();
|
||||
}
|
||||
|
||||
function registerSearchEvents() {
|
||||
var searchAfter500ms = function() {
|
||||
searchState.clearInputTimeout();
|
||||
@ -1421,11 +1495,7 @@ window.initSearch = function(rawSearchIndex) {
|
||||
};
|
||||
searchState.input.onkeyup = searchAfter500ms;
|
||||
searchState.input.oninput = searchAfter500ms;
|
||||
document.getElementsByClassName("search-form")[0].onsubmit = function(e) {
|
||||
e.preventDefault();
|
||||
searchState.clearInputTimeout();
|
||||
search();
|
||||
};
|
||||
document.getElementsByClassName("search-form")[0].onsubmit = onSearchSubmit;
|
||||
searchState.input.onchange = function(e) {
|
||||
if (e.target !== document.activeElement) {
|
||||
// To prevent doing anything when it's from a blur event.
|
||||
@ -1546,7 +1616,7 @@ window.initSearch = function(rawSearchIndex) {
|
||||
};
|
||||
}
|
||||
|
||||
index = buildIndex(rawSearchIndex);
|
||||
searchWords = buildIndex(rawSearchIndex);
|
||||
registerSearchEvents();
|
||||
// If there's a search term in the URL, execute the search now.
|
||||
if (searchState.getQueryStringParams().search) {
|
||||
|
@ -55,6 +55,12 @@ function removeClass(elem, className) {
|
||||
elem.classList.remove(className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a callback for every element of an Array.
|
||||
* @param {Array<?>} arr - The array to iterate over
|
||||
* @param {function(?)} func - The callback
|
||||
* @param {boolean} [reversed] - Whether to iterate in reverse
|
||||
*/
|
||||
function onEach(arr, func, reversed) {
|
||||
if (arr && arr.length > 0 && func) {
|
||||
var length = arr.length;
|
||||
@ -76,6 +82,16 @@ function onEach(arr, func, reversed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn an HTMLCollection or a NodeList into an Array, then run a callback
|
||||
* for every element. This is useful because iterating over an HTMLCollection
|
||||
* or a "live" NodeList while modifying it can be very slow.
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/NodeList
|
||||
* @param {NodeList<?>|HTMLCollection<?>} lazyArray - An array to iterate over
|
||||
* @param {function(?)} func - The callback
|
||||
* @param {boolean} [reversed] - Whether to iterate in reverse
|
||||
*/
|
||||
function onEachLazy(lazyArray, func, reversed) {
|
||||
return onEach(
|
||||
Array.prototype.slice.call(lazyArray),
|
||||
|
@ -223,13 +223,14 @@ where
|
||||
|
||||
crate fn run(
|
||||
krate: clean::Crate,
|
||||
renderopts: config::RenderOptions,
|
||||
mut renderopts: config::RenderOptions,
|
||||
cache: formats::cache::Cache,
|
||||
tcx: TyCtxt<'_>,
|
||||
options: ScrapeExamplesOptions,
|
||||
) -> interface::Result<()> {
|
||||
let inner = move || -> Result<(), String> {
|
||||
// Generates source files for examples
|
||||
renderopts.no_emit_shared = true;
|
||||
let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?;
|
||||
|
||||
// Collect CrateIds corresponding to provided target crates
|
||||
|
25
src/test/ui/derives/issue-91492.rs
Normal file
25
src/test/ui/derives/issue-91492.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Reproduce the issue with vec
|
||||
pub struct NoDerives;
|
||||
fn fun1(foo: &mut Vec<NoDerives>, bar: &[NoDerives]) {
|
||||
foo.extend_from_slice(bar); //~ ERROR
|
||||
}
|
||||
|
||||
// Reproduce the issue with vec
|
||||
// and demonstrate that other derives are ignored in the suggested output
|
||||
#[derive(Default, PartialEq)]
|
||||
pub struct SomeDerives;
|
||||
fn fun2(foo: &mut Vec<SomeDerives>, bar: &[SomeDerives]) {
|
||||
foo.extend_from_slice(bar); //~ ERROR
|
||||
}
|
||||
|
||||
// Try and fail to reproduce the issue without vec.
|
||||
// No idea why it doesnt reproduce the issue but its still a useful test case.
|
||||
struct Object<T, A>(T, A);
|
||||
impl<T: Clone, A: Default> Object<T, A> {
|
||||
fn use_clone(&self) {}
|
||||
}
|
||||
fn fun3(foo: Object<NoDerives, SomeDerives>) {
|
||||
foo.use_clone(); //~ ERROR
|
||||
}
|
||||
|
||||
fn main() {}
|
54
src/test/ui/derives/issue-91492.stderr
Normal file
54
src/test/ui/derives/issue-91492.stderr
Normal file
@ -0,0 +1,54 @@
|
||||
error[E0599]: the method `extend_from_slice` exists for mutable reference `&mut Vec<NoDerives>`, but its trait bounds were not satisfied
|
||||
--> $DIR/issue-91492.rs:4:9
|
||||
|
|
||||
LL | pub struct NoDerives;
|
||||
| --------------------- doesn't satisfy `NoDerives: Clone`
|
||||
LL | fn fun1(foo: &mut Vec<NoDerives>, bar: &[NoDerives]) {
|
||||
LL | foo.extend_from_slice(bar);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`NoDerives: Clone`
|
||||
help: consider annotating `NoDerives` with `#[derive(Clone)]`
|
||||
|
|
||||
LL | #[derive(Clone)]
|
||||
|
|
||||
|
||||
error[E0599]: the method `extend_from_slice` exists for mutable reference `&mut Vec<SomeDerives>`, but its trait bounds were not satisfied
|
||||
--> $DIR/issue-91492.rs:12:9
|
||||
|
|
||||
LL | pub struct SomeDerives;
|
||||
| ----------------------- doesn't satisfy `SomeDerives: Clone`
|
||||
LL | fn fun2(foo: &mut Vec<SomeDerives>, bar: &[SomeDerives]) {
|
||||
LL | foo.extend_from_slice(bar);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`SomeDerives: Clone`
|
||||
help: consider annotating `SomeDerives` with `#[derive(Clone)]`
|
||||
|
|
||||
LL | #[derive(Clone)]
|
||||
|
|
||||
|
||||
error[E0599]: the method `use_clone` exists for struct `Object<NoDerives, SomeDerives>`, but its trait bounds were not satisfied
|
||||
--> $DIR/issue-91492.rs:22:9
|
||||
|
|
||||
LL | pub struct NoDerives;
|
||||
| --------------------- doesn't satisfy `NoDerives: Clone`
|
||||
...
|
||||
LL | struct Object<T, A>(T, A);
|
||||
| -------------------------- method `use_clone` not found for this
|
||||
...
|
||||
LL | foo.use_clone();
|
||||
| ^^^^^^^^^ method cannot be called on `Object<NoDerives, SomeDerives>` due to unsatisfied trait bounds
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`NoDerives: Clone`
|
||||
help: consider annotating `NoDerives` with `#[derive(Clone)]`
|
||||
|
|
||||
LL | #[derive(Clone)]
|
||||
|
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
Loading…
Reference in New Issue
Block a user