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
18 changed files with 418 additions and 57 deletions
|
@ -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();
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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!");
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<()> {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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");
|
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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
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…
Add table
Add a link
Reference in a new issue