1
Fork 0

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:
bors 2021-12-23 01:47:08 +00:00
commit 5aa0239b16
18 changed files with 418 additions and 57 deletions

View file

@ -1195,11 +1195,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn suggest_derive( fn suggest_derive(
&self, &self,
err: &mut DiagnosticBuilder<'_>, err: &mut DiagnosticBuilder<'_>,
unsatisfied_predicates: &Vec<( unsatisfied_predicates: &[(
ty::Predicate<'tcx>, ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>, Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>, Option<ObligationCause<'tcx>>,
)>, )],
) { ) {
let mut derives = Vec::<(String, Span, String)>::new(); let mut derives = Vec::<(String, Span, String)>::new();
let mut traits = Vec::<Span>::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())); 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.sort();
traits.dedup(); 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(); let len = traits.len();
if len > 0 { if len > 0 {
let span: MultiSpan = traits.into(); let span: MultiSpan = traits.into();

View file

@ -1183,6 +1183,37 @@ fn test_rev_iterator() {
assert_eq!(pos, v.len()); 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] #[test]
#[cfg_attr(miri, ignore)] // Miri is too slow #[cfg_attr(miri, ignore)] // Miri is too slow
fn test_chars_decoding() { fn test_chars_decoding() {

View file

@ -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")] #[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for ToLowercase {} 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")] #[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for ToUppercase {} 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 { impl fmt::Display for CaseMappingIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self { match *self {

View file

@ -103,6 +103,9 @@ fn test_to_lowercase() {
let iter: String = c.to_lowercase().collect(); let iter: String = c.to_lowercase().collect();
let disp: String = c.to_lowercase().to_string(); let disp: String = c.to_lowercase().to_string();
assert_eq!(iter, disp); 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 iter
} }
assert_eq!(lower('A'), "a"); assert_eq!(lower('A'), "a");
@ -130,6 +133,9 @@ fn test_to_uppercase() {
let iter: String = c.to_uppercase().collect(); let iter: String = c.to_uppercase().collect();
let disp: String = c.to_uppercase().to_string(); let disp: String = c.to_uppercase().to_string();
assert_eq!(iter, disp); 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 iter
} }
assert_eq!(upper('a'), "A"); assert_eq!(upper('a'), "A");

View file

@ -99,7 +99,7 @@ use crate::cell::UnsafeCell;
use crate::env; use crate::env;
use crate::ffi::c_void; use crate::ffi::c_void;
use crate::fmt; use crate::fmt;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
use crate::sync::Once; use crate::sync::Once;
use crate::sys_common::backtrace::{lock, output_filename}; use crate::sys_common::backtrace::{lock, output_filename};
use crate::vec::Vec; use crate::vec::Vec;
@ -256,7 +256,7 @@ impl Backtrace {
// backtrace captures speedy, because otherwise reading environment // backtrace captures speedy, because otherwise reading environment
// variables every time can be somewhat slow. // variables every time can be somewhat slow.
static ENABLED: AtomicUsize = AtomicUsize::new(0); static ENABLED: AtomicUsize = AtomicUsize::new(0);
match ENABLED.load(SeqCst) { match ENABLED.load(Relaxed) {
0 => {} 0 => {}
1 => return false, 1 => return false,
_ => return true, _ => return true,
@ -268,7 +268,7 @@ impl Backtrace {
Err(_) => false, Err(_) => false,
}, },
}; };
ENABLED.store(enabled as usize + 1, SeqCst); ENABLED.store(enabled as usize + 1, Relaxed);
enabled enabled
} }

View file

@ -420,3 +420,22 @@ fn env_empty() {
let p = Command::new("cmd").args(&["/C", "exit 0"]).env_clear().spawn(); let p = Command::new("cmd").args(&["/C", "exit 0"]).env_clear().spawn();
assert!(p.is_ok()); 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!");
}

View file

@ -2,7 +2,7 @@ use super::{abi, error};
use crate::{ use crate::{
ffi::{CStr, CString, OsStr, OsString}, ffi::{CStr, CString, OsStr, OsString},
fmt, fmt,
io::{self, IoSlice, IoSliceMut, SeekFrom}, io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom},
mem::MaybeUninit, mem::MaybeUninit,
os::raw::{c_int, c_short}, os::raw::{c_int, c_short},
os::solid::ffi::OsStrExt, 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> { pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
crate::io::default_read_vectored(|buf| self.read(buf), bufs) crate::io::default_read_vectored(|buf| self.read(buf), bufs)
} }

View file

@ -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 // Encode the command and arguments in a command line string such
// that the spawned process may recover them using CommandLineToArgvW. // that the spawned process may recover them using CommandLineToArgvW.
let mut cmd: Vec<u16> = Vec::new(); 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 // Always quote the program name so CreateProcess doesn't interpret args as
// part of the name if the binary wasn't found first time. // part of the name if the binary wasn't found first time.
append_arg(&mut cmd, prog, Quote::Always)?; 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)?; append_arg(&mut cmd, arg, quote)?;
} }
if is_batch_file {
cmd.push(b'"' as u16);
}
return Ok(cmd); return Ok(cmd);
fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, quote: Quote) -> io::Result<()> { fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, quote: Quote) -> io::Result<()> {

View file

@ -272,7 +272,10 @@ crate struct RenderOptions {
crate emit: Vec<EmitType>, crate emit: Vec<EmitType>,
/// If `true`, HTML source pages will generate links for items to their definition. /// If `true`, HTML source pages will generate links for items to their definition.
crate generate_link_to_definition: bool, crate generate_link_to_definition: bool,
/// Set of function-call locations to include as examples
crate call_locations: AllCallLocations, crate call_locations: AllCallLocations,
/// If `true`, Context::init will not emit shared files.
crate no_emit_shared: bool,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -732,6 +735,7 @@ impl Options {
emit, emit,
generate_link_to_definition, generate_link_to_definition,
call_locations, call_locations,
no_emit_shared: false,
}, },
crate_name, crate_name,
output_format, output_format,

View file

@ -397,6 +397,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
show_type_layout, show_type_layout,
generate_link_to_definition, generate_link_to_definition,
call_locations, call_locations,
no_emit_shared,
.. ..
} = options; } = options;
@ -516,13 +517,16 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
sources::render(&mut cx, &krate)?; sources::render(&mut cx, &krate)?;
} }
// Build our search index if !no_emit_shared {
let index = build_index(&krate, &mut Rc::get_mut(&mut cx.shared).unwrap().cache, tcx); // Build our search index
let index = build_index(&krate, &mut Rc::get_mut(&mut cx.shared).unwrap().cache, tcx);
// Write shared runs within a flock; disable thread dispatching of IO temporarily.
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);
}
// Write shared runs within a flock; disable thread dispatching of IO temporarily.
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)) Ok((cx, krate))
} }

View 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

View 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;

View file

@ -420,6 +420,13 @@ function hideThemeButtonState() {
return document.getElementById("help"); 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) { function displayHelp(display, ev, help) {
if (display) { if (display) {
help = help ? help : getHelpElement(true); help = help ? help : getHelpElement(true);

View file

@ -113,7 +113,15 @@ window.initSearch = function(rawSearchIndex) {
var INPUTS_DATA = 0; var INPUTS_DATA = 0;
var OUTPUT_DATA = 1; var OUTPUT_DATA = 1;
var NO_TYPE_FILTER = -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 ALIASES = {};
var params = searchState.getQueryStringParams(); var params = searchState.getQueryStringParams();
@ -126,12 +134,15 @@ window.initSearch = function(rawSearchIndex) {
} }
/** /**
* Executes the query and builds an index of results * Executes the query and returns a list of results for each results tab.
* @param {[Object]} query [The user query] * @param {Object} query - The user query
* @param {[type]} searchWords [The list of search words to query * @param {Array<string>} searchWords - The list of search words to query against
* against] * @param {string} [filterCrates] - Crate to search in
* @param {[type]} filterCrates [Crate to search in if defined] * @return {{
* @return {[type]} [A search index of results] * in_args: Array<?>,
* returned: Array<?>,
* others: Array<?>
* }}
*/ */
function execQuery(query, searchWords, filterCrates) { function execQuery(query, searchWords, filterCrates) {
function itemTypeFromName(typename) { function itemTypeFromName(typename) {
@ -847,11 +858,11 @@ window.initSearch = function(rawSearchIndex) {
* This could be written functionally, but I wanted to minimise * This could be written functionally, but I wanted to minimise
* functions on stack. * functions on stack.
* *
* @param {[string]} name [The name of the result] * @param {string} name - The name of the result
* @param {[string]} path [The path of the result] * @param {string} path - The path of the result
* @param {[string]} keys [The keys to be used (["file", "open"])] * @param {string} keys - The keys to be used (["file", "open"])
* @param {[object]} parent [The parent of the result] * @param {Object} parent - The parent of the result
* @return {boolean} [Whether the result is valid or not] * @return {boolean} - Whether the result is valid or not
*/ */
function validateResult(name, path, keys, parent) { function validateResult(name, path, keys, parent) {
for (var i = 0, len = keys.length; i < len; ++i) { for (var i = 0, len = keys.length; i < len; ++i) {
@ -872,8 +883,14 @@ window.initSearch = function(rawSearchIndex) {
return true; return true;
} }
/**
* Parse a string into a query object.
*
* @param {string} raw - The text that the user typed.
* @returns {ParsedQuery}
*/
function getQuery(raw) { function getQuery(raw) {
var matches, type, query; var matches, type = "", query;
query = raw; query = raw;
matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i); matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
@ -974,6 +991,12 @@ window.initSearch = function(rawSearchIndex) {
return tmp; 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) { function addTab(array, query, display) {
var extraClass = ""; var extraClass = "";
if (display === true) { if (display === true) {
@ -1083,7 +1106,7 @@ window.initSearch = function(rawSearchIndex) {
currentResults = query.id; 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_in_args = addTab(results.in_args, query, false);
var ret_returned = addTab(results.returned, query, false); var ret_returned = addTab(results.returned, query, false);
@ -1253,6 +1276,12 @@ window.initSearch = function(rawSearchIndex) {
return undefined; 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) { function search(e, forced) {
var params = searchState.getQueryStringParams(); var params = searchState.getQueryStringParams();
var query = getQuery(searchState.input.value.trim()); var query = getQuery(searchState.input.value.trim());
@ -1287,11 +1316,14 @@ window.initSearch = function(rawSearchIndex) {
} }
var filterCrates = getFilterCrates(); var filterCrates = getFilterCrates();
showResults(execSearch(query, index, filterCrates), params.go_to_first); showResults(execSearch(query, searchWords, filterCrates), params["go_to_first"]);
} }
function buildIndex(rawSearchIndex) { function buildIndex(rawSearchIndex) {
searchIndex = []; searchIndex = [];
/**
* @type {Array<string>}
*/
var searchWords = []; var searchWords = [];
var i, word; var i, word;
var currentIndex = 0; var currentIndex = 0;
@ -1304,6 +1336,38 @@ window.initSearch = function(rawSearchIndex) {
var crateSize = 0; 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); searchWords.push(crate);
// This object should have exactly the same set of fields as the "row" // This object should have exactly the same set of fields as the "row"
// object defined below. Your JavaScript runtime will thank you. // object defined below. Your JavaScript runtime will thank you.
@ -1313,7 +1377,7 @@ window.initSearch = function(rawSearchIndex) {
ty: 1, // == ExternCrate ty: 1, // == ExternCrate
name: crate, name: crate,
path: "", path: "",
desc: rawSearchIndex[crate].doc, desc: crateCorpus.doc,
parent: undefined, parent: undefined,
type: null, type: null,
id: id, id: id,
@ -1324,23 +1388,23 @@ window.initSearch = function(rawSearchIndex) {
currentIndex += 1; currentIndex += 1;
// an array of (Number) item types // an array of (Number) item types
var itemTypes = rawSearchIndex[crate].t; var itemTypes = crateCorpus.t;
// an array of (String) item names // 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) // 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 // 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 // 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 // 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, // an array of [(Number) item type,
// (String) name] // (String) name]
var paths = rawSearchIndex[crate].p; var paths = crateCorpus.p;
// an array of [(String) alias name // an array of [(String) alias name
// [Number] index to items] // [Number] index to items]
var aliases = rawSearchIndex[crate].a; var aliases = crateCorpus.a;
// convert `rawPaths` entries into object form // convert `rawPaths` entries into object form
var len = paths.length; var len = paths.length;
@ -1406,6 +1470,16 @@ window.initSearch = function(rawSearchIndex) {
return searchWords; 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() { function registerSearchEvents() {
var searchAfter500ms = function() { var searchAfter500ms = function() {
searchState.clearInputTimeout(); searchState.clearInputTimeout();
@ -1421,11 +1495,7 @@ window.initSearch = function(rawSearchIndex) {
}; };
searchState.input.onkeyup = searchAfter500ms; searchState.input.onkeyup = searchAfter500ms;
searchState.input.oninput = searchAfter500ms; searchState.input.oninput = searchAfter500ms;
document.getElementsByClassName("search-form")[0].onsubmit = function(e) { document.getElementsByClassName("search-form")[0].onsubmit = onSearchSubmit;
e.preventDefault();
searchState.clearInputTimeout();
search();
};
searchState.input.onchange = function(e) { searchState.input.onchange = function(e) {
if (e.target !== document.activeElement) { if (e.target !== document.activeElement) {
// To prevent doing anything when it's from a blur event. // 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(); registerSearchEvents();
// If there's a search term in the URL, execute the search now. // If there's a search term in the URL, execute the search now.
if (searchState.getQueryStringParams().search) { if (searchState.getQueryStringParams().search) {

View file

@ -55,6 +55,12 @@ function removeClass(elem, className) {
elem.classList.remove(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) { function onEach(arr, func, reversed) {
if (arr && arr.length > 0 && func) { if (arr && arr.length > 0 && func) {
var length = arr.length; var length = arr.length;
@ -76,6 +82,16 @@ function onEach(arr, func, reversed) {
return false; 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) { function onEachLazy(lazyArray, func, reversed) {
return onEach( return onEach(
Array.prototype.slice.call(lazyArray), Array.prototype.slice.call(lazyArray),

View file

@ -223,13 +223,14 @@ where
crate fn run( crate fn run(
krate: clean::Crate, krate: clean::Crate,
renderopts: config::RenderOptions, mut renderopts: config::RenderOptions,
cache: formats::cache::Cache, cache: formats::cache::Cache,
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
options: ScrapeExamplesOptions, options: ScrapeExamplesOptions,
) -> interface::Result<()> { ) -> interface::Result<()> {
let inner = move || -> Result<(), String> { let inner = move || -> Result<(), String> {
// Generates source files for examples // Generates source files for examples
renderopts.no_emit_shared = true;
let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?; let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?;
// Collect CrateIds corresponding to provided target crates // Collect CrateIds corresponding to provided target crates

View 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() {}

View 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`.